I'm learning Spring Security with some sample application. I got few problems.
I'm using Spring 4.2.2.RELEASE and Spring Security 4.0.2.RELEASE. Here is my Spring Security Context.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">
<context:component-scan base-package="com.mvc.sslspring.security" />
<security:authentication-manager id="authenticationManager">
<security:authentication-provider>
<security:user-service>
<security:user name="aa" password="aa" authorities="ROLE_USER" />
<security:user name="bb" password="bb"
authorities="ROLE_USER, ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
<security:http realm="Protected API" use-expressions="true"
auto-config="false" create-session="stateless" entry-point-ref="restAuthenticationEntryPoint"
authentication-manager-ref="authenticationManager">
<security:custom-filter ref="restAuthenticationTokenProcessingFilter"
position="FORM_LOGIN_FILTER" />
<security:intercept-url pattern="/authenticate"
access="permitAll" />
<security:intercept-url pattern="/persons"
access="isAuthenticated() and hasRole('ROLE_ADMIN')" />
<security:intercept-url pattern="/persons/*"
access="isAuthenticated() and hasRole('ROLE_ADMIN')" />
<security:intercept-url pattern="/tasks"
access="isAuthenticated() and hasRole('ROLE_USER')" />
<security:intercept-url pattern="/tasks/*"
access="isAuthenticated() and hasRole('ROLE_USER')" />
<security:access-denied-handler ref="restAccessDeniedHandler" />
<security:csrf disabled="true" />
</security:http>
</beans>
(I have disabled CSRF because it was giving some problem with POSTMAN client.) I'm creating token when user enters username and password and send a s JSON, and using that token in header, I'm accessing the resources. It's working fine for me including the Roles, except few things.
Here are my handlers.
Authentication Entry Point Handler
@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, ServletException {
// response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
PrintWriter out = response.getWriter();
out.print("{\"message\":\""+ authException.getMessage() + "\", \"access-denied\":true,\"cause\":\"SC_UNAUTHORIZED\"}");
out.flush();
out.close();
}
}
Access denied Handler
@Component
public class RestAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException, ServletException {
// response.sendError(HttpServletResponse.SC_FORBIDDEN,
// accessDeniedException.getMessage());
response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
PrintWriter out = response.getWriter();
out.print("{\"message\":\"" + accessDeniedException.getMessage()
+ "\", \"access-denied\":true,\"cause\":\"SC_FORBIDDEN\"}");
out.flush();
out.close();
}
}
I have few controllers for tasks and persons and it's working well and returning JSON.
First I have problem with authentication of user.
Here is authentication method in controller
@RequestMapping(value = "/authenticate", method = RequestMethod.POST)
public String authenticate(@RequestBody User user, HttpServletRequest request) throws Exception {
UserDetails userDetails = userService.loadUserByUsername(user.getUsername());
String tokenString = TokenUtils.createToken(user);
return tokenString;
}
User.java
import java.util.Collection;
import java.util.Collections;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
public class User implements UserDetails {
private String username;
private String password;
// getters and setters
// overridden methods
}
If I enter correct username and wrong password, it's creating and returning token. If I enter wrong username only it will go to RestAuthenticationEntryPoint and sends back 401 error with JSON message.
How to authenticate user in controller method with username ans password from configuration file? If the credentials are wrong, it should send 401 status with custom JSON.
Also in case any exception happens in any controler, I should be able to send 500 error with JSON message. Is there any common way to send error response and handle authentications?
I know there can be Authentication failure handler. But in XML configuration, where to mention it. I don't see that option other than in <security:form login/> but I'm not using it.