I am playing around with Spring Security.
I noticed something strange and this makes me wonder what's the difference between
org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic;
and
org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user;
?
what troubles me is this unit test:
#Test
public void testHelpUnauthorized() throws Exception {
mvc.perform(get("/api/help")).andExpect(status().isUnauthorized());
mvc.perform(get("/api/help").with(user("user").password("jj"))).andExpect(status().isOk());
mvc.perform(get("/api/help").with(httpBasic("user",""))).andExpect(status().isUnauthorized());
mvc.perform(get("/api/help").with(httpBasic("user","dd"))).andExpect(status().isUnauthorized());
}
#Test
public void testHelp() throws Exception {
mvc.perform(get("/api/help")
.with(httpBasic("correctUser","CorrectPassword"))).andExpect(status().isOk());
}
all this succeeds.
notice the second call, from the first test:
mvc.perform(get("/api/help").with(user("user").password("jj"))).andExpect(status().isOk());
why does this returns 200 OK?
The only difference is how I pass the username-password pair.
More details:
1 - the REST endpoint returns just a string, made it so that I can test the authentication, no real functionality.
2 - All my users are defined, for the sake of just playing around with Spring Security in new InMemoryUserDetailsManager(user); And when I test the behaviour through Postman/curl/browser, I get the correct behaviour, but not in the unit test, why?
The difference can be found in the Javadoc of each method.
From the Javadoc of httpBasic(String username, String password):
Convenience mechanism for setting the Authorization header to use HTTP Basic with the given username and password.
This means if you perform a request with httpBasic("user","password"), then the credentials "user" and "password" are Base64 encoded and included in the request in the Authorization header.
The request then goes through the filter chain, which checks if the credentials are correct.
From the Javadoc of user(String username):
Establish a SecurityContext that has a UsernamePasswordAuthenticationToken for the Authentication#getPrincipal() and a User for the UsernamePasswordAuthenticationToken#getPrincipal(). All details are declarative and do not require that the user actually exists.
The last sentence states that the user does not need to exist.
This means that if you perform a request with user("user").password("password"), a user with the username "user" and the password "password" is added to the SecurityContext.
This does not check if the user exists.
This is useful for testing your business logic, rather than testing the credentials.
For example if your logic requires you to retrieve the user's username. Another example is if you have different behaviour for different user roles (ADMIN / USER).
Related
I’m migrating an application from Spring Security 3 to 4. The applications utilizes both form based username/password and smart card authentication. It also has a custom AuthenticationFailureHandler that redirects the user to a particular page based on what type of error occurred and the roles associated to the user. For example a locked exception should be handled differently for internal vs external users.
In Spring Security 3 the org.springframework.security.authentication.AccountStatusUserDetailsChecker used to place the UserDetails object into the extraInformation property of the AuthenticationException it threw. The custom AuthenticationFailureHandler we have utilized that to extract the roles from the user who failed authentication so it could handle the different user types appropriately:
#Override
public void onAuthenticationFailure(HttpServletRequest request,
HttpServletResponse response, AuthenticationException exception)
throws IOException, ServletException {
User user = (User)exception.getExtraInformation();
if(exception instanceof LockedException){
if(user.hasAnyRole(Role.INTERNAL)){
//Send to internal user page
}else{
//Send to external user page
}
}
}
However now with Spring Security 4, I’m not sure the best way to get the information about the user into the failure handler so I can appropriately route the request. What would be considered the ‘best practice’ approach for this?
One approach is to extract the relevant information from the request (Either the form based username or the X509 cert) and then look up the roles using a database query but since that is already handled earlier in the Spring Security chain it seems like duplicating that effort in the failure handler isn’t the best approach.
Thanks
I'm look at Web API 2 with a project that I created as a "proof of concept". I'm trying to see where I inject my own code for customer authentication. I have an internal auth/login service that I would like to call to determine if login credentials are valid and then get user values (id, roles, etc) if it was valid.
I created the project with "Individual Accounts" as the authentication type but I'm having a hard time figuring out where I'm going to call my service and then map the result to an IdentityUser (or some IUser) object.
In the generated ApplicationOAuthProvider class there is code that passes username and password from a context object like so:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
using (UserManager<IdentityUser> userManager = _userManagerFactory())
{
IdentityUser user = await userManager.FindAsync(context.UserName, context.Password);
// ...
How do I hook into that call?
You should do this:
Create your own HTTP Message Handler to authenticate the user. You can put your custom code there. This will execute every request, then you can set the credential in the pipeline of the execution.
HTTP Message Handlers
Create or use the default filters to handle the Authorization
Authentication and Authorization in ASP.NET Web API
I'm developing an app based on Grails and Vaadin 7. I managed to make them work with SpringSecurity for authentication and authorization, but I had to develop my own Service that calls the Spring Security authentication manager to make it work with Vaadin:
class SecurityService {
static transactional = true
def springSecurityService
def authenticationManager
void signIn(String username, String password) {
try {
def authentication = new UsernamePasswordAuthenticationToken(username, password)
SCH.context.authentication = authenticationManager.authenticate(authentication)
} catch (BadCredentialsException e) {
throw new SecurityException("Invalid username/password")
}
}
}
The problem is that now I need to implement a remember me authentication and I don't know from where to start.
How do I make the authenticationManager know that I want it to use remeberMeAuthentication? I can get a boolean value from a checkbox on the login View, but what do I do with it next?
Since your question is specific to the handling of checkbox value (remember me flag) coming from login page, the answer is that you have to call loginSuccess or loginFail method of RememberMeServices. The loginSuccess adds auto-login cookie in the response and loginFail removes that cookie.
But I guess above answer won't help you much unless you are sure that you have RememberMeServices configured in your app. Maybe following steps that configure RememberMeServices will help you do whole thing your way (or help you understand the out of the box functionality):
(1) Create a class (call it myRememberMeServices) that implements RememberMeServices and LogoutHandler.
(2) In autoLogin method, create an authentication object (UsernamePasswordAuthenticationToken) after parsing the cookie value.
(3) In loginFail method, cancel the cookie.
(4) In loginSuccess method, create an auto-login cookie. Add value that you would use in autoLogin method. Usually cookie value is encrypted.
(5) In logout method , cancel the cookie.
(6) Inject myRememberMeServices in following four places and call appropriate method:
(a) At the time of successful login (if checkbox value is set),
(b) At the time of failed login,
(c) On logout, and
(d) In filter that does autologin
It is worth noting that RememberMeAuthenticationFilter takes authenticationManager and RememberMeServices in its constructor.
Answer to your other question is that the authenticationManager doesn't need to know anything about remember me. It is the filter (or any class handling auto login) that needs to know about authenticationManager and RememberMeServices. (In other words, ask RememberMeServices for a token and pass it to authenticationManager to do auto login).
Spring Security's architecture is based on servlet filters. The sign-in mechanism you have implemented above is normally done by the UsernamePasswordAuthenticationFilter. Another filter called RememberMeAuthenticationFilter takes the responsibility for the remember-me functionality. The authenticationManager is not aware at all whether the remember-me feature is used by the application or not.
If you want to integrate Spring Security with another web-framework, first try to find out how the filters of the two frameworks can play together.
I am simply trying to allow a user access to a method if they are authenticated, but nothing I am doing seems to work. Is there a way to just check if the user has been authenticated? The following still denies the user even when authenticated... Is there a built in role for an authenticated user?
#RequestMapping("/secure")
#PreAuthorize("hasRole('IS_AUTHENTICATED_FULLY')")
public String secure(ModelMap map){
return("secure");
}
IS_AUTHENTICATED_FULLY is not a role - it is a pre-defined credential (aka 'magic' string) recognized by the AuthenticatedVoter to indicate that you have logged in. This voter also supports anonymous and remember-me login.
Roles are processed by the RoleVoter which recognizes any sting starting with "ROLE_" (prefix is configurable). Thus hasRole('IS_AUTHENTICATED_FULLY') doesn't work because it's not a role. #RolesAllowed("IS_AUTHENTICATED_FULLY") wouldn't work for the same reason.
When using Spring expression language, the correct expression is:
#PreAuthorize("isAuthenticated()")
Alternatively, you can use:
#Secured("IS_AUTHENTICATED_FULLY")
No custom classes are required - both voters are enabled by default.
hasRole('ROLE_USER') is the traditional name for any user who is authenticated. You would typically use ROLE_ANONYMOUS for parts where you don't care if the person is authenticated or not.
(Added later:)
I think you will need to implement a custom AccessDecisionVoter that will always vote ACCESS_GRANTED whenever the parameter authentication has isAuthenticated() true, and the CONFIG_ATTRIBUTE is ROLE_USER or similar.
There is further discussion of this in this forum discussion, giving details of a web.xml and other config.
In your custom UserDetailService implementation just add the Role "IS_AUTHENTICATED_FULLY" to the User object before it's returned.
This is what I have ended up using:
#PreAuthorize("isAuthenticated()")
this should work:
#PreAuthorize("isFullyAuthenticated()")
Where do I get information about the currently connected user? That is, how does shibboleth pass the information?
Can I set some restrictions on actions using [Authorize] attribute based on data acquired from shibboleth?
Shibboleth publishes user attributes associated with
sessions into HTTP request headers, based on header names defined
in Attribute Acceptance Policy (1.3.x) or Attribute Mapping (2.x)
files. These headers are transformed into CGI variables based
on mapping rules defined by the CGI specification.
You should be aware of this security advisory:
http://shibboleth.net/community/advisories/secadv_20090615.txt
I have never user shibboleth, but you can get information about the user from Controller.User property. It will return a generic principal of current thread. Using this principal you can check whether the user is authenticated and get a login name of the user. This is due to the reason that after logon an authentication cookie is set and this cookie contains limited amount of information. And on each request after logon only this cookie is checked (if it exists and valid - user is authenticated).
So if you need in some specific information you can manually load a user (it's better to use cache here) and check whatever you want.
Also you can create and attach your own principal with necessary information to the thread on start of a request (e.g. on start of a request load the user from db/cache using user name from base principal, create and set your own principal to thread). After this you can check all properties of the user you need.
Where would you attach your own principal? You say on the start of the request but what if you don't want every request authorizing?
You'll want to create a method in Global.asax.cs that has the following signature
protected void Application_PostAuthenticateRequest()
{
//Your code here.
}
This will be called automatically before almost anything else is done (MVC will call this method if it exists, you don't have to "turn it on" anywhere), and this is where you need to set the Principal. For instance, let's assume you have a header called RolesHeader that has a comma separated value of roles and another header called UserId that has (duh) the user ID.
Your code, without any error handling, might look something like:
protected void Application_PostAuthenticateRequest()
{
var rolesheader = Context.Request.Headers["RolesHeader"];
var userId = Context.Request.Headers["UserId"];
var roles = rolesheader.Split(',');
var principal = new GenericPrincipal(new GenericIdentity(userId), roles);
Context.User = principal;
}
It's the Principal/Identity that the [Authorize] attribute uses, so setting it here at the beginning of the request lifecycle means the [Authorize] attribute will work correctly.
The rest of this is optional, but I recommend it:
I like to create my own custom classes that implement IPrincipal and IIdentity instead of using the GenericPrincipal and GenericIdentity, so I can stuff more user information in it. My custom Principal and Identity objects then have much more rich information, such as branch numbers or email addresses or whatever.
Then, I create a Controller called BaseController that has the following
protected new CustomPrincipal User
{
get
{
return (base.User as CustomPrincipal) ?? CustomPrincipal.GetUnauthorizedPrincipal();
}
}
This allows me to access all my rich, custom Principal data instead of just what's defined in IPrincipal. All of my real controllers then inherit from BaseController instead of directly from Controller.
Obviously, when using a custom Principal like this, in the Application_PostAuthenticateRequest() method, you'd set the Context.User to be your CustomPrincipal instead of a GenericPrincipal.