I am implementing a custom authentication provider in spring security that authenticates user. Authentication server is in remote side (Restful service). everytime I called my service I encounterd with this error (this code reaches the
return new UsernamePasswordAuthenticationToken(userDetails, authentication.getCredentials().toString(), grantedAuthorities);
part )
{"error":"invalid_client","error_description":"Bad client credentials"}
here is my code:
CustomAuthenticationProvider
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(HttpClients.createDefault());
RequestConfig requestConfig = RequestConfig.custom().setConnectTimeout(60 * 1000)
.setSocketTimeout(60 * 1000).build();
PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
poolingHttpClientConnectionManager.setMaxTotal(20);
poolingHttpClientConnectionManager.setDefaultMaxPerRoute(20);
CloseableHttpClient httpClientBuilder = HttpClientBuilder.create()
.setConnectionManager(poolingHttpClientConnectionManager).setDefaultRequestConfig(requestConfig)
.build();
requestFactory.setHttpClient(httpClientBuilder);
RestTemplate restTemplate = new RestTemplate(requestFactory);
UserInfoRequestBean userInfoRequestBean = new UserInfoRequestBean();
String username = (String)authentication.getPrincipal();
userInfoRequestBean.setUsername(username);
userInfoRequestBean.setPassword((String)authentication.getCredentials());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<?> httpEntity = new HttpEntity<UserInfoRequestBean>(userInfoRequestBean, headers);
try{
ResponseBean<LoginResponseBean> responseBody = restTemplate.exchange(getLoginUrl(), HttpMethod.POST, httpEntity, new ParameterizedTypeReference<ResponseBean<LoginResponseBean>>() {}).getBody();
UserDetails userDetails = new UserDetails();
userDetails.setGender(responseBody.getResult().getGender());
userDetails.setLastLoginDate(new Date());
userDetails.setYaghutSessionId(responseBody.getResult().getSessionId());
userDetails.setName(responseBody.getResult().getName());
userDetails.setUsername(username);
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
// Granting authorization roles to user
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new UsernamePasswordAuthenticationToken(userDetails, authentication.getCredentials().toString(), grantedAuthorities);
}catch (RestClientException exp) {
exp.printStackTrace();
//TODO: implement this method
}
return null;
}
#Override
public boolean supports(Class<?> authentication) {
// TODO Auto-generated method stub
return true;
}
private String getLoginUrl(){
//return restful service url
}
}
Spring-security-config
<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" />
<bean id="clientCredentialsTokenEndpointFilter"
class="org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter">
<property name="authenticationManager" ref="customAuthenticationManager" />
</bean>
<bean id="clientAuthenticationEntryPoint" class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="realmName" value="test/client" />
<property name="typeName" value="Basic" />
</bean>
<bean id="customProvider"
class="com.adpdigital.idm.security.provider.CustomAuthenticationProvider" />
<authentication-manager id="customAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider ref="customProvider" />
</authentication-manager>
<http pattern="/oauth/token" create-session="stateless" authentication-manager-ref="customAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<intercept-url pattern="/oauth/token" access="IS_AUTHENTICATED_FULLY"/>
<anonymous enabled="false"/>
<http-basic entry-point-ref="clientAuthenticationEntryPoint" />
<!-- include this only if you need to authenticate clients via request parameters -->
<custom-filter ref="clientCredentialsTokenEndpointFilter" after="BASIC_AUTH_FILTER" />
<access-denied-handler ref="oauthAccessDeniedHandler" />
</http>
Instead of passing UserDetails simply pass the username, when returning UsernamePasswordAuthenticationToken. Below is the example -
return new UsernamePasswordAuthenticationToken(username, authentication.getCredentials().toString(), grantedAuthorities);
Related
I am new with RESTful web services in spring,whenever i am requesting the URL through postman,i am getting random generated token from server side, here you are controller code,through this i am getting random generated token.
#RequestMapping(value = "/api/authenticate", method = RequestMethod.POST)
public #ResponseBody
Result doLogIn(#RequestParam("BulkData") String bulkData, HttpServletResponse response) throws Exception {
ObjectMapper mapper = new ObjectMapper();
JsonNode actualObj = null;
try {
actualObj = mapper.readTree(bulkData);
} catch (IOException e1) {
e1.printStackTrace();
return new Result("Invalid Request", ResultCodes.LOGIN_FAILURE);
}
String userName = actualObj.get("userName").asText();
String password = actualObj.get("password").asText();
logger.debug("[REST]: Attempting login for -> " + userName);
UserDetails details = userDetailService.loadUserByUsername(userName);
// validate password
if (details != null && !details.getPassword().equals(password)) {
logger.debug("[REST]: Invalid username/password");
try {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid username/password");
} catch (IOException e) {
e.printStackTrace();
}
return new Result("Invalid username or password", ResultCodes.LOGIN_FAILURE);
}
// Generate token. ATM, use only username
String generatedToken = Jwts.builder().setSubject(userName)
.setIssuedAt(new Date())
// set token expiration time
.setExpiration(new Date(System.currentTimeMillis() + Config.TOKEN_EXPIRY_PERIOD))
.signWith(SignatureAlgorithm.HS256, servletContext.getInitParameter("API_SECRET_KEY"))
.compact();
// provide token to user in form of a Http Header
response.addHeader(Config.AUTH_TOKEN_HEADER_NAME, generatedToken);
return new Result("Login Success", ResultCodes.LOGIN_SUCCESS_TOKEN_GENERATED);
}
and here is the code for authorization , to do so i am using AuthenticationTokenProcessingFilter,
public class AuthenticationTokenProcessingFilter extends GenericFilterBean {
#Autowired
private UserDetailService userDetailService;
#Autowired
private AuthenticationManager authenticationManager;
private static Logger logger = Logger.getLogger(AuthenticationTokenProcessingFilter.class);
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
// Exclude login URL
if(req.getRequestURI().endsWith("/api/authenticate")) {
chain.doFilter(req, response);
return;
}
// Client must send token in header
String authHeader = req.getHeader(Config.AUTH_TOKEN_HEADER_NAME);
if (authHeader == null) {
logger.error("[REST]: Authentication header was null...");
throw new ServletException("Missing or invalid Authorization header.");
}
// Parse token, fetch user and reload Security Context
try {
String SECRET_KEY = getServletContext().getInitParameter("API_SECRET_KEY");
Jws<Claims> claims = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(authHeader);
Claims claim = claims.getBody();
String userName = claim.getSubject();
logger.debug("[REST]: Token of user -> " + userName + " expires: " + claim.getExpiration());
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userName, userDetailService.loadUserByUsername(userName).getPassword());
token.setDetails(new WebAuthenticationDetails(req));
Authentication authentication = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
} catch (SignatureException e) {
logger.debug("[REST]: Invalid token");
throw new ServletException("Invalid token.");
}
chain.doFilter(req, response);
// clear security context now because we are going for Stateless Web Services
SecurityContextHolder.getContext().setAuthentication(null);
}
now i want to use this generated token to call this method ,
#RequestMapping(value="/api/admin/getEmployeerole", method=RequestMethod.POST)
public List<EmployeeRole> EmployeeRoleList() {
List<EmployeeRole> getRole=employeeRoleService.getAll();
return getRole;
}
now what is happening here when i am writing this URL to postman and adding generated token into header ,and i have used authorization type (No auth), i have also tried with basic Authorization, still my request is going to customAuthenticationEntrypoint and it throws Access denied exception,that the user Role is annonymous, at server side i am getting status 401 unauthorized.it would be great if someone can help to get over from this..
here You are my spring security configuration..
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan base-package="hp.bootmgr.authentication.provider" />
<http pattern="/resources/**" security="none" />
<http pattern="/api/**" realm="Protected API" use-expressions="true" auto-config="false" create-session="stateless" entry-point-ref="customAuthenticationEntryPoint">
<!-- <custom-filter position="FORM_LOGIN_FILTER" /> -->
<intercept-url pattern="/api/authenticate" access="permitAll()" />
<intercept-url pattern="/api/admin/**" access="hasRole('ADMIN')" />
<intercept-url pattern="/api/user/**" access="hasAnyRole('ADMIN', 'EMPLOYEE')" />
<intercept-url pattern="/api/member/**" access="hasAnyRole('ADMIN', 'MEMBER')" />
<!--<form-login
login-page="/api/authenticate"
login-processing-url="/j_spring_security_check"
username-parameter="userName"
password-parameter="password" />-->
<logout logout-url="/logout"/>
<csrf disabled="true"/>
</http>
<http auto-config="true" use-expressions="true" entry-point-ref="authenticationEntryPoint">
<access-denied-handler error-page="/403" />
<intercept-url pattern="/login" access="true"/>
<intercept-url pattern="/admin/**" access="hasRole('ADMIN')" />
<!-- Allow access to user pages to admin, as long as there is no more other rules-->
<intercept-url pattern="/user/**" access="hasAnyRole('ADMIN', 'EMPLOYEE')" />
<intercept-url pattern="/member/**" access="hasAnyRole('ADMIN', 'MEMBER')" />
<form-login
login-page="/login"
default-target-url="/home"
authentication-failure-url="/login?failed=1"
login-processing-url="/j_spring_security_check"
username-parameter="userName"
password-parameter="password" />
<logout logout-success-url="/login?logout=1" invalidate-session="true" logout-url="/logout"/>
<!-- enable csrf protection -->
<csrf disabled="true"/>
<session-management>
<concurrency-control max-sessions="1" expired-url="/login" />
</session-management>
</http>
<beans:bean id="customAuthenticationEntryPoint" class="hp.bootmgr.web.services.authentication.CustomAuthenticationEntryPoint" />
<beans:bean id="authenticationTokenProcessingFilter" class="hp.bootmgr.web.services.authentication.AuthenticationTokenProcessingFilter" />
<beans:bean id="authenticationEntryPoint" class="hp.bootmgr.security.AuthenticationEntryPoint">
<beans:constructor-arg name="loginUrl" value="/login"/>
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider user-service-ref="userDetailService" />
</authentication-manager>
</beans:beans>
I am working on a Java application which connects to a Spring-MVC server, using Spring-Security for authentication/authorization. The login part works, and I get a JSESSIONID back in the Java application, but when I make request to secured resource, it fails, Spring-Security is unable to find any logged in user. What am I doing wrong here?
security-applicationContext.xml :
<security:http pattern="/resources/**" security="none"/>
<security:http create-session="ifRequired" use-expressions="true" auto-config="false" disable-url-rewriting="true">
<security:form-login login-page="/login" login-processing-url="/j_spring_security_check"
default-target-url="/dashboard" always-use-default-target="false"
authentication-failure-url="/denied"/>
<security:remember-me key="_spring_security_remember_me" user-service-ref="userDetailsService"
token-validity-seconds="1209600" data-source-ref="dataSource"/>
<security:logout delete-cookies="JSESSIONID" invalidate-session="true" logout-url="/j_spring_security_logout"/>
<!--<security:intercept-url pattern="/**" requires-channel="https"/>-->
<security:port-mappings>
<security:port-mapping http="8080" https="8443"/>
</security:port-mappings>
<security:logout logout-url="/logout" logout-success-url="/" success-handler-ref="myLogoutHandler"/>
<security:session-management session-fixation-protection="migrateSession">
<security:concurrency-control session-registry-ref="sessionRegistry" max-sessions="5" expired-url="/login"/>
</security:session-management>
</security:http>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="restaurantauthenticationprovider"/>
<security:authentication-provider ref="userauthenticationprovider"/>
</security:authentication-manager>
<beans:bean id="encoder"
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<beans:constructor-arg name="strength" value="11"/>
</beans:bean>
<beans:bean id="restaurantauthenticationprovider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="LoginServiceImpl"/>
<beans:property name="passwordEncoder" ref="encoder"/>
</beans:bean>
<beans:bean id="userauthenticationprovider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="UserLoginServiceImpl"/>
<beans:property name="passwordEncoder" ref="encoder"/>
</beans:bean>
As I have 2 tables to check from which to login, I have 2 DAOAuthenticationProviders.
UserLoginServiceImpl :
#Transactional
#Service("loginuserDetailsService")
public class UserLoginServiceImpl implements UserDetailsService {
#Autowired
private PersonDAO personDAO;
#Autowired
private UserAssembler userAssembler;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException,DataAccessException {
System.out.println("Username is "+username);
Person person = this.personDAO.findPersonByUserName(username.toLowerCase());
if(person == null) { throw new UsernameNotFoundException("Wrong username or password");}
return userAssembler.buildUserFromUserEntity(person);
}
}
Assembler :
#Service("userassembler")
#Transactional
public class UserAssembler {
#Transactional
User buildUserFromUserEntity(Person userEntity){
System.out.println("We are in Userassembler"+userEntity.getEmail());
String username = userEntity.getUsername().toLowerCase();
String password = userEntity.getPassword();
boolean enabled = userEntity.isEnabled();
boolean accountNonExpired = userEntity.isAccountNonExpired();
boolean credentialsNonExpired = userEntity.isCredentialsNonExpired();
boolean accountNonLocked = userEntity.isAccountNonLocked();
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new User(username,password,enabled,accountNonExpired,credentialsNonExpired,accountNonLocked,authorities);
}
}
The above is the config, now I will put the rest code which is failing :
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
Log.d("Username is ", username);
String jsessionid = rest.execute("http://192.168.178.60:8080/j_spring_security_check", HttpMethod.POST,
new RequestCallback() {
#Override
public void doWithRequest(ClientHttpRequest request) throws IOException {
request.getBody().write(("j_username=" + username + "&j_password=" + password).getBytes());
}
}, new ResponseExtractor<String>() {
#Override
public String extractData(ClientHttpResponse response) throws IOException {
List<String> cookies = response.getHeaders().get("Cookie");
if (cookies == null) {
cookies = response.getHeaders().get("Set-Cookie");
}
String cookie = cookies.get(cookies.size() - 1);
System.out.println("Cookie is " + cookie);
// The method below gets me which user is logged in, and I always get null for Controller method.
reply = rest.getForObject(
"http://192.168.178.60:8080/dashboard", String.class);
int start = cookie.indexOf('=');
int end = cookie.indexOf(';');
return cookie.substring(start + 1, end);
}
});
}
});
thread.start();
Update
Finally, the code which worked :
// I am getting the cookie from the server, which I am setting manually for every request, cookie is a static volatile string.
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Cookie", "JSESSIONID=" + StaticRestTemplate.jsessionid);
HttpEntity requestEntity = new HttpEntity(null, requestHeaders);
ResponseEntity rssResponse = rest.exchange(
"http://192.168.178.60:8080/dashboard",
HttpMethod.GET,
requestEntity,
String.class);
String abc = (String) rssResponse.getBody();
Spring's RestTemplate does not keep track of cookies by default. This ensures you don't accidentally pass a cookie (i.e. JSESSIONID) from one user on behalf of another user (i.e. think of using the RestTemplate on a server where many users are leveraging the same RestTemplate).
If you want to do this you can configure it using something like this:
RestTemplate rest = new RestTemplate();
// initialize the RequestFactory to allow cookies
HttpClient httpClient = HttpClientBuilder.create().build();
ClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
rest.setRequestFactory(factory);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("username", "user");
map.add("password", "password");
String result = rest.postForObject("http://localhost:8080/login", map, String.class);
String hello = rest.postForObject("http://localhost:8080/", map, String.class);
assertThat(hello).isEqualTo("Hello");
To use this code you will need to ensure you have httpclient on your classpath. For example, the following might be in your pom.xml if you are using Maven:
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5</version>
</dependency>
Obviously you will need to ensure you include the version of httpclient that works for your dependencies.
I am working with spring-security 3.1 to implement two different logons. The first thing I have to a database that brings me CustomUserDetailService credentials datos.Este the same database is for administrator access. The second port is for the user but the information comes from a web service I call him with me a method validates the user. The problem I have with the second port, and to develop a CustomAuthenticationProvider for the second AuthenticationManager (web service), but when I try to access the spring-security user sends me to error page login.html? Error = true the furmulario administrator access. Esteb is my configuration file:
<http pattern="../resources/**" security="none" />
<http pattern="/login.html*" security="none" />
<http pattern="/loginUser.html*" security="none" />
<!-- USER -->
<http auto-config="true" authentication-manager-ref="wsAuthenticationManager" use-expressions="true" pattern="/testUser/**">
<intercept-url pattern="/loginUser.html" access="permitAll" />
<intercept-url pattern="/testUser/**" access="hasRole('user')" />
<access-denied-handler error-page="/403" />
<form-login login-page="/loginUser.html"
authentication-failure-url="/loginUser.html?login_error=true"
default-target-url="/testUser" />
<logout invalidate-session="true" logout-success-url="/logintUser.html" />
</http>
<beans:bean id="customAuthenticationProvider" class="net.universia.test.service.CustomAuthenticationProvider" />
<!-- Acceso contra WS -->
<authentication-manager id="wsAuthenticationManager">
<authentication-provider ref="customAuthenticationProvider" />
</authentication-manager>
<!--ADMIN -->
<http auto-config="true" use-expressions="true" authentication-manager-ref="authenticationManager" >
<intercept-url pattern="/login.html" access="permitAll" />
<intercept-url pattern="/test/**" access="hasRole('admin')" />
<intercept-url pattern="/member/**" access="hasAnyRole('moderator','admin')" />
<intercept-url pattern="/testUser/**" access="hasRole('admin')" />
<access-denied-handler error-page="/403" />
<form-login login-page="/login.html"
authentication-failure-url="/login.html?login_error=true"
username-parameter="j_username" password-parameter="j_password"/>
<logout invalidate-session="true" logout-success-url="/loginUser.html" />
<remember-me user-service-ref="customUserDetailsService" />
</http>
<beans:bean id="customUserDetailsService" class="net.universia.test.service.CustomUserDetailsService" />
<beans:bean id="md5PasswordEncoder"
class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />
<!-- Acceso contra base de datos -->
<authentication-manager alias="authenticationManager" id="authenticationManager">
<authentication-provider user-service-ref="customUserDetailsService">
<password-encoder hash="md5" />
</authentication-provider>
</authentication-manager>
</beans:beans>
CustomUserDetailService para administrator:
#Service
#Transactional(readOnly=true)
public class CustomUserDetailsService implements UserDetailsService {
#Autowired
private HibernateTestAdminDaoImpl userDAO;
public UserDetails loadUserByUsername(String login)throws UsernameNotFoundException {
TestAdmin userAdmin = null;
try {
userAdmin = userDAO.getTestAdmin(login);
} catch (BussinessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
return new User(
userAdmin.getLoginAdmin(),
userAdmin.getPasswordAdmin(),
enabled,
accountNonExpired,
credentialsNonExpired,
accountNonLocked,
getAuthorities(userAdmin.getRole().getIdRole())
);
}
public Collection<? extends GrantedAuthority> getAuthorities(Integer role) {
List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(role));
return authList;
}
public List<String> getRoles(Integer role) {
List<String> roles = new ArrayList<String>();
if (role.intValue() == 1) {
roles.add("admin");
roles.add("moderator");
} else if (role.intValue() == 2) {
roles.add("moderator");
}
return roles;
}
public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
}
CustomAuthenticationProvider user:
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
private HibernateTestUsuarioDaoImpl userDAO;
UniversiaUser usw;
public CustomAuthenticationProvider() {
super();
}
// Retorna credenciales del usuario web service
public Authentication authenticate(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
/*
final String loginUser = authentication.getName();
final String password = authentication.getCredentials().toString();
try {
usw = userDAO.loginUserWS(loginUser, password);
} catch (UserRegistryWSException e) {
String errorCode = e.getLocalizedMessage();
System.out.print(errorCode);
} catch (Exception e) {
UsuarioUniversiaException ee = new UsuarioUniversiaException(
UsuarioUniversiaException.FERIA_VIRTUAL_USER_ERROR_LOGIN,
e);
ee.setLogin(loginUser);
throw ee;
}
if (usw.getEmail().equals("loginUser")) {
final List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("user"));
final UserDetails principal = new User(loginUser, password, grantedAuths);
final Authentication auth = new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
return auth;
} else {
return null;
}
*/
//Test parameters
final String loginUser = request.getParameter("username");
final String password = request.getParameter("password");
if (loginUser.equals("admin") && password.equals("system")) {
final List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("user"));
final UserDetails principal = new User(loginUser, password, grantedAuths);
final Authentication auth = new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
return auth;
} else {
return null;
}
}
#Override
public boolean supports(final Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
#Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// TODO Auto-generated method stub
return null;
}
}
In customautheticationprovider discuss what comes from the webservice and send test parameters
Thanks and any help is welcome
Now I have two running !!!
One customAuthenticationProvider user and customAuthenticationDetailService for Administrator and implement each filter
I am using java config for spring security and I am trying to replace this code with no luck
<security:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
cant find any info about how to use the position in java config
Update i am trying to replace this code by java config but with no luck
<security:http
realm="Protected API"
use-expressions="true"
auto-config="false"
create-session="stateless"
entry-point-ref="unauthorizedEntryPoint"
authentication-manager-ref="authenticationManager">
<security:custom-filter ref="authenticationTokenProcessingFilter" position="FORM_LOGIN_FILTER" />
<security:intercept-url pattern="/rest/user/authenticate" access="permitAll" />
<security:intercept-url method="GET" pattern="/rest/news/**" access="hasRole('user')" />
<security:intercept-url method="PUT" pattern="/rest/news/**" access="hasRole('admin')" />
<security:intercept-url method="POST" pattern="/rest/news/**" access="hasRole('admin')" />
<security:intercept-url method="DELETE" pattern="/rest/news/**" access="hasRole('admin')" />
</security:http>
<bean id="unauthorizedEntryPoint" class="net.dontdrinkandroot.example.angularrestspringsecurity.rest.UnauthorizedEntryPoint" />
<bean class="net.dontdrinkandroot.example.angularrestspringsecurity.rest.AuthenticationTokenProcessingFilter" id="authenticationTokenProcessingFilter">
<constructor-arg ref="userDao" />
</bean>
and this is my AuthenticationTokenProcessingFilter
public class AuthenticationTokenProcessingFilter extends UsernamePasswordAuthenticationFilter
{
private final UserDetailsService userService;
public AuthenticationTokenProcessingFilter(UserDetailsService userService)
{
this.userService = userService;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException
{
HttpServletRequest httpRequest = this.getAsHttpRequest(request);
String authToken = this.extractAuthTokenFromRequest(httpRequest);
String userName = TokenUtils.getUserNameFromToken(authToken);
if (userName != null) {
UserDetails userDetails = this.userService.loadUserByUsername(userName);
if (TokenUtils.validateToken(authToken, userDetails)) {
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
chain.doFilter(request, response);
}
private HttpServletRequest getAsHttpRequest(ServletRequest request)
{
if (!(request instanceof HttpServletRequest)) {
throw new RuntimeException("Expecting an HTTP request");
}
return (HttpServletRequest) request;
}
private String extractAuthTokenFromRequest(HttpServletRequest httpRequest)
{
/* Get token from header */
String authToken = httpRequest.getHeader("X-Auth-Token");
/* If token not found get it from request parameter */
if (authToken == null) {
authToken = httpRequest.getParameter("token");
}
return authToken;
}
Hope this is clearer
Here are the filter classes in the order of execution and with the addFilter method of the HttpSecurity class you add your own filters:
#Override
public void configure(HttpSecurity http) throws Exception {
http.addFilter(new AuthenticationTokenProcessingFilter());
...
You have to either extend or provide an instance of the defined Spring filters. The order is based on the class or superclass so you don't have to add the position:
JavaDoc
Can't get Spring Security to work with DB authentication provider.
In-memory authentication provider works OK.
Step to reproduce:
when I logged with credentials sb,sb,login() method of AuthenticationService returned false.
There are no related log in Tomcat.
applicationContext.xml:
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/chirokDB?useUnicode=true&characterEncoding=utf8"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean id="userDetailsService" class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
<property name="dataSource" ref="dataSource"/>
</bean>
service layer:
#Service("authenticationService")
public class AuthenticationServiceImpl implements AuthenticationService {
#Resource(name = "authenticationManager")
private AuthenticationManager authenticationManager;
public boolean login(String username, String password) {
try {
Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
username, password));
if (authenticate.isAuthenticated()) {
SecurityContextHolder.getContext().setAuthentication(authenticate);
return true;
}
} catch (AuthenticationException e) {
}
return false;
}
managed bean level:
public String doLogin() {
boolean isLoggedIn = authenticationService.login(name, password);
if (isLoggedIn) {
return "index";
}
FacesContext.getCurrentInstance().addMessage("login failure", new FacesMessage());
return "failureLogin";
}
applicationContext-security.xml:
<global-method-security pre-post-annotations="enabled"/>
<http auto-config="true">
<form-login login-page="/login.xhtml" default-target-url="/index.xhtml"/>
<intercept-url pattern="/contacts.xhtml" access="ROLE_ANONYMOUS,ROLE_USER"/>
<intercept-url pattern="/delivery.xhtml" access="ROLE_USER"/>
<logout invalidate-session="true"/>
<session-management>
<concurrency-control max-sessions="1" error-if-maximum-exceeded="true"/>
</session-management>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource"/>
</authentication-provider>
</authentication-manager>
persistence level:
MySql DB has following standard tables(required by Spring):
1. users
2. authorities
users table has record with username='sb' and password='sb'
authorities table has record with username='sb' and authority='ROLE_USER'
note
with user-in memory all works OK with following config:
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="sb" password="sb" authorities="ROLE_USER"/>
</user-service>
</authentication-provider>
</authentication-manager>
assumption:
dataSource injected into org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl
As far Hibernate ORM used, perhaps some other than JdbcDaoImpl should be used?
Check if you're getting an Exception in your empty catch block (which always is a bad idea).