I have a custom-authentication-provider defined in my Spring Security configuration. This class implements AuthenticationProvider, and I can successfully log in using the form defined on my page. The issue is I want to call this class not just on the login page, but from the registration page as well.
The registration page uses a different command class and collects more information than the login form. Right now, when the user registers, I call the appropriate controller, add the record to the database and they can then log in but they aren't logged in automatically. As they've just given me their user name/password on the registration page, can I then pass this to the custom AuthenticationProvider class so they are also logged in?
I've tried creating an org.springframework.security.Authentication class in the registration controller and calling the authenticate method on my customer AuthenticationProvider class, and this doesn't error out, but the user isn't logged in. Do I have to call a method higher in the Spring Security filter chain to accomplish this? Should I redirect the controller to the j_spring_security_check URL? If so, how would I pass the username/password?
You need to put the result of AuthenticationProvider.authenticate() into SecurityContext (obtained from SecurityContextHolder).
Also be aware of AuthenticationSuccessEvent - if your application rely on this event (some Spring Security features may use it, too), you should publish it (you can obtain the default AuthenticationEventPublisher via autowiring). It may be useful to wrap your authentication provider with ProviderManager, it publishes the event automatically using the given publisher.
The problem you are having is that although you have successfully authenticated the user you have not stored the result of this authentication in the user's SecurityContext. In a web application this is a ThreadLocal object which the SecurityContextPersistenceFilter will use to store the user's credentials in the HTTPSession
You should also avoid authenticating directly with your custom authentication provider if you can. Your xml configuration should contain an AuthenticationManager which your custom authentication provider has been wired into. For example,
<bean id="customAuthenticationProvider"
class="com.foo.CustomAuthenticationProvider">
<property name="accountService" ref="accountService"/>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="customAuthenticationProvider"/>
</security:authentication-manager>
If you wire the authenticationManager into your registration service and authenticate using that it will additionally,
allow you to swap in/out additional authentication providers at later points
publish the authentication result to other parts of the Spring Security framework (eg success/failure Exception handling code)
Our registration service does this as follows
final UsernamePasswordAuthenticationToken authRequest = new
UsernamePasswordAuthenticationToken(username, password);
final Authentication authentication =
authenticationManager.authenticate(authRequest);
SecurityContextHolder.getContext().setAuthentication(authentication);
We also optionally store the authentication result at this point in a remember-me cookie using the onLoginSuccess() method of TokenBasedRememberMeServices.
Related
I started to use Spring OAuth2 and in the process, I struggled to find relevant tutorials and content mostly because of the following
I did not want to use Spring Boot
I did not want to use Java configs rather xml configuration
I needed to customize Spring OAuth2 grant flows and other features for our specific needs
I needed to disable some grant flows
I needed to Spring OAuth2 to use custom Users and Roles
I needed to use store oauth_client details in a custom database tab
Other stuff
I have managed to write my implementation that addresses the above points and now I want to share my findings in order to save others the suffering.
See my answer for the approach I followed and feel free to share your advise, suggestions and feedback if you have any.
The main objective of this question is to
Get feedback, suggestions and advise about approach I followed
Share all that I learned the hard way with the hope of saving others the trouble and giving back to the community what I learned from community.
I started off with basic setup of Spring Security framework using mainly XML configuration.
Spring Security OAuth2
I did a ton of google searches and looked at a bunch of repositories including the main Spring OAuth 2 repo.
I started off with OAuth2 XML Configs and I needed to make changes in order to
Organize, clean up the spring-security.xml OAuth2 config file
Instruct Spring OAuth2 to lookup a different (customized) user and role tables from database
Instruct Spring OAuth2 to lookup a different (customized) oauth_client_details table (with extra columns)
Use JWT Tokens and make required changes to customize the JWT Token to include custom claims
Develop custom implementation of OAuth2RequestValidator and inject it to the Token endpoint using XML configuration
Disable a grant flow
Enable verify token endpiont /oauth/check_token and validate JWT token custom claims
And, I have achieved the above as follow
1. Organize and clean up spring-security.xml
The default spring-security.xml linked above comes with the following assumptions
Both Authorization server and Resource server are in the same machine.
Use in-memory users
Use in-memory oauth clients
I would like to keep the Authentication and Resource server separate hence, I stripped off all the protected endpoints configs and the in-memory user-service and oauth-client-details.
2. Instruct OAuth2 to lookup different user and roles database table
To achieve this, I made sure that
MyUser object implements the following org.springframework.security.core.userdetails.UserDetails
and overrides the getAuthorities which return a collection of GrantedAuthority
MyRole object implements the org.springframework.security.core.GrantedAuthorityand override the method getAuthority
I now need to inform the Spring OAuth2 about the above customised MyUser and MyRole and in order to do that, I needed to do the following
Provide custom implementation for org.springframework.security.core.userdetails.UserDetailsService interface and override the inherited loadByUsername method to query my custom user database table and retrieve the user with its roles and construct an instance of org.springframework.security.core.userdetails.User and return it.
Create a <bean> of the above custom implementation and let's call it MyUserDetailsService and place it in spring-security.xml config file. Something as follow
<bean id="myUserDetailsService" class="your.package.hierarcy.goes.here.MyUserDetailsService" />
Just defining a bean is once again not enough, we have to tell Spring OAuth2 to use the MyUserDetailsService and to do that we need to inject the myUserDetailsService into Spring OAuth2's default authentication provider or our own authentication provider that will then get passed to authentication-manager element, as shown below
<bean id="daoAuthenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="myUserDetailsService"/>
<!-- if you encode or encrypt your password, then pass encoder-->
<!--<property name="passwordEncoder" ref="passwordEncoder"/>-->
</bean>
Finally we need to inject the above Authentication Provider into the Authentication Manager specified in spring-security.xml as shown below
<!-- Original -->
<authentication-manager alias="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider>
<user-service id="userDetailsService">
<user name="marissa" password="koala" authorities="ROLE_USER" />
<user name="paul" password="emu" authorities="ROLE_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
Change the above with below
<!-- Modified with our own implementation of UserDetailsService -->
<authentication-manager alias="authenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider ref="daoAuthenticationProvider" />
</authentication-manager>
And now to use the above Authentication Manager which uses, pass it to a grant flow in the <oauth:authorization-server> as follow
<oauth:password authentication-manager-ref="authenticationManager"/>
3. Instruct Spring OAuth2 to look up different oauth_client_table
If you look closely at the default spring-security.xml from the official Spring OAuth2 repo linked above, you will see the following chain of references
clientCredentialsTokenEndpointFilter bean
references
clientAuthenticationManager bean
references
clientDetailsUserDetailsService
references
clientDetails
And clientDetails is nothing but a list of fixed oauth clients declared at the end under <oauth:client-details-service id="clientDetails"> tag.
Alright, so the objective is to instruct Spring OAuth2 to read and store oauth_clients to/from a database.
If we do not need to customize the the default spring oauth database tables to meet our specific needs, then its quite easy and the process is as follow
Setup the default Spring OAuth2 database tables as shown in this link
In the spring-security.xml change the clientDetailsUserDetailsService to pass the default Spring OAuth2 org.springframework.security.oauth2.provider.client.JdbcClientDetailsService and declare the same as a bean, as shown below.
Defautlt Spring OAuth2 JdbcClientDetailsService bean definition
<bean class="org.springframework.security.oauth2.provider.client.JdbcClientDetailsService" id="myClientDetails">
<constructor-arg index="0">
<!-- This is your jdbc datasource, i.e. db details-->
<ref bean="dataSource" />
</constructor-arg>
</bean>
and now the clientDetailsUserDetailsService bean should look as follow
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="myClientDetails" />
</bean>
And everything else the stays the same. The above changes, will instruct the Spring OAuth2 to read oath_clients from the database (oauth_client_details) rather than hard-coded xml config.
What if, you wanted to modify the default oauth_client_details table to adda few custom columns to meet your specific needs, will in that case you need to make a different set of changes. So we have the following objective
Add extra columns to the default oauth_client_details table
given the following (in the default spring-security.xml)
clientCredentialsTokenEndpointFilter bean
references
clientAuthenticationManager bean
references
clientDetailsUserDetailsService
references
clientDetails
We need to transform the above workflow (or chain of references) in order for Spring OAuth2 to be able to access our new customized oauth_client_details database table. So the new workflow or chain of references should be similar to below
clientCredentialsTokenEndpointFilter bean (no change)
references
clientAuthenticationManager bean (no change)
references
clientDetailsUserDetailsService (to be updated)
references
clientDetails (to be replaced)
And to achieve the above, lets move from bottom to top. The default Spring OAuth2 uses org.springframework.security.oauth2.provider.ClientDetails to load oauth_client from the default oauth_client_details table. We need to provide a custom implementation for org.springframework.security.oauth2.provider.ClientDetails by implementing it hence, something as follow
public class MyClientDetails implements ClientDetails { ... }
Before we move on, I just wanted to mention that Spring OAuth2 already provides an implementation for the above interface meaning that we could make our life a lot easier by actually extending the only implementation of the above interface (ClientDetails) which is org.springframework.security.oauth2.provider.client.BaseClientDetails rather than implementing it from the beginning (leverage all that can be done from BaseClientDetails and add our own custom fields) hence, the MyClientDetails looks as follow then
public class MyClientDetails extends BaseClientDetails {
//fields representing custom column for oauth_client
//getters and setters
//make sure to call super() in the inherited constructors, before
//setting custom fields.
}
Alright, now that we have our own ClientDetails object, just like #2 we need to implement our own JdbcClientDetailsService that will get injected to clientDetailsUserDetailsService. In order to implement our own JdbcClientDetailsService let's look at the signature of the default method
public class JdbcClientDetailsService
extends Object
implements ClientDetailsService, ClientRegistrationService
As you can see, the above class implements ClientDetailsService & ClientRegistrationService interfaces. While implementing our own JdbcClientDetailsService I do not recommend extending the default JdbcClientDetailsService because there are quite a few private class variables (and methods) which will not be inherited hence, let's use the default implementation to write our own.
public class MyJdbcClientDetailsService implements ClientDetailsService, ClientRegistrationService {
//override loadClientByClientId method, query the custom
//oauth_client_details database table and populate the
//MyClientDetails object created above and return it.
//Implement other methods to CRUD oauth_clients
}
Now that you implemented MyJdbcClientDetailsService create a bean for it in spring-security.xml, in the following lines
Now inject the above bean to clientDetailsUserDetailsService, and looking into default spring-security.xml, we have the following
<!-- Original referencing hardcoded clients -->
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="clientDetails" />
</bean>
And the above will need to be changed to as follow
<bean id="clientDetailsUserService"
class="org.springframework.security.oauth2.provider.client.ClientDetailsUserDetailsService">
<constructor-arg ref="myJdbcClientDetailsService" />
</bean>
There we go, now the chain looks as follow after specifying our own ClientDetailsService:
clientCredentialsTokenEndpointFilter bean (no change)
references
clientAuthenticationManager bean (no change)
references
clientDetailsUserDetailsService (ref updated)
references
myJdbcClientDetailsService (our customized client details service)
The above instructs the Spring OAuth2 to look up a customized database table for oauth_client details.
4. Using JWT Token and want to add extra claims
JWT Token or JSON Web Token can be used among three different actors of OAuth2 (Authorization server actor, Resource Server actor, Client actor) in order to communicate with each other in performing different actions relating to authorization and access of protected resources. The JWT token is used by Authorization server and it is signed using a public/private key and the objective is to make sure that the content of the JWT token do not get updated (unless someone have access to the private key). The basic workflow can be as follow (Let's assume password grant flow)
Client actor makes a request on behalf of the Resource owner actor (user) to the Authorization server actor asking for an OAuth2AccessToken
Authorization server actor verifies that the requesting client is trusted or not (by checking the requesting clients passed client_id and client_secret - the MyJdbcClientDetailsService is used to lookup the client), Once the client is verified and client secret matched, then it will verify the username and password (this could use the MyUserDetailsService to lookup the user in our database user table) that's also been passed by the Client actor (on behalf of user). If a user is found, then its password is matched (maybe using a custom Password encoder - i.e. BCrypt recommended due to slow hash function) and if all well, then it will retrieve the User's role and construct a JWT token, then sign it with it's own public/private key, store the JWT Token with client details in the database (oauth_access_token default table) and return a copy of the JWT Token to the requesting client.
The Client actor then sends the user's request to the Resource server asking for a protected resource passing along the JWT token. The Resource server validates that the JWT is valid and not tampered, and then accordingly serve the Client actor.
Above briefly describes how the JWT token is used by OAuth2. There is a ton of more details on JWT and varieties of JWT out there (signed, signed and encrypted, etc etc).
For more information on JWT implementation of Spring OAuth2, see the official repo here and JWT webpage.
Let's see, we have the following JWT
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
and we would like to include a set of scopes to the above token, so the Resource server actor know whether this user is allowed to make this request or not. The change could look as follow
{
"sub": "1234567890",
"name": "John Doe",
"admin": true,
"scope": "read write delete"
}
To add custom claims (each of above key/value is referred to as claims), we need to create a class MyTokenEnhancer which implement org.springframework.security.oauth2.provider.token.TokenEnhacer interface and override it's enhance method OR extend org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter which in turn implements the default TokenEnhancer and override it's enhance method.
By overriding the enhance method, you can add custom claims to the OAuth2AccessToken. Please see the above linked repo for more details on this.
5.Develop custom implementation of OAuth2RequestValidator and inject it to the Token endpoint
For me, the oauth clients send a customized OAuth2Request and I needed more than the deafult DefaultOAuth2RequestValidator implementation hence, I had to write my own and implemented the org.springframework.security.oauth2.provider.OAuth2RequestValidator. Something in the following lines
public class MyOAuth2RequestValidator implements OAuth2RequestValidator {
//override the necessary methods
}
Now that we have created our own custom MyOAuth2RequestValidator how should we instruct the Token endpoint to use it using XML configuration? Well, this one took me a little time for figure it out. Looking into the default spring-security.xml we have the following
<oauth:authorization-server
client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password />
</oauth:authorization-server>
When we make an OAuth2 request to the /oauth/token endpoint, the request is mapped to ClientCredentialsTokenEndpointFilter first, and from there at some stage the request is delegated to org.springframework.security.oauth2.provider.endpoint.TokenEndpoint and if you look at the source code TokenEndpoint you will see the following
private OAuth2RequestValidator oAuth2RequestValidator = new DefaultOAuth2RequestValidator();
Now to replace that with our Custom validator MyOAuth2RequestValidator we need to do the following
Create a bean that references our custom MyOAuth2RequestValidator and name give it id of "myOAuth2RequestValidator"
Update the <oauth:authorization-server> in the spring-security to use our custom validator from #1
See below the updated authorization-server tag
<oauth:authorization-server
client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler"
request-validator-ref="myOAuth2RequestValidator">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password />
</oauth:authorization-server>
And that's it. Now, every time the TokenEndpoint is hit, it will use our custom validator instead of default one.
6. Disable a grant flow
We might not use all of the available grant flows hence, make sense to disable those not used. Let's say, I don't want to use refresh-token grant flow (just an example) and to disable it we have to update the <oauth:authorization-server>
The authorization server with disabled refresh-token grant flow looks as follow
You can also disable other flows. Obviously you can get away with not disabling it because, if you do not support let's say Authorization Code grant flow then simply do not register an oauth_client that has a value of authorization_code in it's oauth_client_table (if default oauth table)'s authorized_grant_types column.
Also to share with you an experience that helped me understand Spring OAuth2, I actually debugged the Spring OAuth2 classes to understand how each workflow worked and kept track of all the classes that got hit during different grant flows. It's helpful to give you an overall understanding of how Spring OAuth2 works and then it will become less painful to implement your own OAuth2 implementation on top of Spring OAuth2.
7. Enable Verify token endpoint and Validate JWT Custom claims
If the Resource and Authorization server are not in the same server and not sharing the same database, then Resource server requires to double check with Authorization server after it receives a request for a resource to make sure that the token is still valid (this is useful when tokens don't expire too soon) and has the right permissions/claims. In order to achieve this Spring OAuth provides Check Token Endpoint that can be enabled by adding the following
check-token-enabled="true"
to the <oauth:authorization-server ...> element in the XML configuration file. Once the above is added, a POST request to {server-url}/oauth/check_token with a form parameter with key token and value JWT access token will instruct the Authorization server to validate that the token is valid. The default implementation does the default checks such as
Expiry date
Signature verification
Etc
And you will have to do a little bit of customization to validate your custom claims. See my other post in here for more details.
Spring's SecurityContextLogoutHandler notes that the clearAuthentication flag is used to:
removes the Authentication from the SecurityContext to prevent issues with concurrent requests.
What specific issue is being prevented by removing the Authentication from the SecurityContext? Why isn't simply invalidating the session (which is the other responsibility of SecurityContextLogoutHandler) sufficient?
By not clearing the SecurityContext is the concern that a SecurityContextPersistenceFilter may preserve the current authentication to a new session id? Effectively leaving the user logged in just with a new session?
What is SecurityContextLogoutHandler?
SecurityContextLogoutHandler is a handler which implements LogoutHandler.
What SecurityContextLogoutHandler does?
It performs a logout by modifying the SecurityContextHolder.
It will also invalidate the HttpSession if isInvalidateHttpSession()
is true and the session is not null.
It will also remove the Authentication from the current
SecurityContext if clearAuthentication is set to true (default).
Is SecurityContextHolder thread safe?
Yes, it's thread safe with the default strategy (MODE_THREADLOCAL) (as long as you don't try to change the strategy on the fly). However, if you want spawned threads to inherit SecurityContext of the parent thread, you should set MODE_INHERITABLETHREADLOCAL.
Also aspects don't have any "threading logic", they are executed at the same thread as the advised method.
Credit goes to #axtavt
What is authentication in Spring Security?
Authentication: The framework tries to identify the end user with the provided credentials. The authentication can be done against a third party system plugged into Spring Security.
Let's consider a standard authentication scenario that everyone is familiar with.
A user is prompted to log in with a username and password.
The system (successfully) verifies that the password is correct for
the username.
The context information for that user is obtained (their list of
roles and so on).
A security context is established for the user
The user proceeds, potentially to perform some operation which is potentially protected by an access control mechanism which checks the required permissions for the operation against the current security context information.
The first three items constitute the authentication process so we'll take a look at how these take place within Spring Security.
The username and password are obtained and combined into an instance
of UsernamePasswordAuthenticationToken (an instance of the
Authentication interface, which we saw earlier).
The token is passed to an instance of AuthenticationManager for
validation.
The AuthenticationManager returns a fully populated Authentication
instance on successful authentication.
The security context is established by calling
SecurityContextHolder.getContext().setAuthentication(...), passing
in the returned authentication object.
SecurityContextPersistentFilter
The name is quite explicit. The SecurityContextPersistentFilter interface purpose is to store the security context in some repository.
To achieve this task, the filter delegates the job to a SecurityContextRepository interface.
Spring provides a default implementation for this interface: org.springframework.security.web.context.HttpSessionSecurityContextRepository. This is quite self-explanatory. The repository for the security context is simply the current user HTTP session.
Below is the XML configuration for the SecurityContextPersistentFilter
<!-- Filter to store the Authentication object in the HTTP Session -->
<bean id="securityContextPersistentFilter"
class="org.springframework.security.web.context.SecurityContextPersistenceFilter">
<property name="securityContextRepository" ref="securityContextRepository" />
</bean>
<bean id="securityContextRepository"
class="org.springframework.security.web.context.HttpSessionSecurityContextRepository" />
LogoutFilter
The LogoutFilter is in charge of logging out the current user and invalidating the security context. The task of invalidating the HTTP session is again delegated to another actor, the SecurityContextLogoutHandler.
This handler is injected in the LogoutFilter constructor:
<bean id="logoutFilter"
class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg value="/pages/Security/logout.html" />
<constructor-arg>
<list>
<bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</list>
</constructor-arg>
<property name="filterProcessesUrl" value="/j_myApplication_logout"/>
</bean>
<constructor-arg value="/pages/Security/logout.html" /> - it defines the URL of the logout page.
The SecurityContextLogoutHandler is injected as constructor argument at <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
The HTML URL for the logout action is define by the filterProcessesUrl parameter at <property name="filterProcessesUrl" value="/j_myApplication_logout"/>
Resource Link:
https://doanduyhai.wordpress.com/2012/01/22/spring-security-part-i-configuration-and-security-chain/
https://doanduyhai.wordpress.com/2012/02/05/spring-security-part-ii-securitycontextpersistentfilter-logoutfilter/
http://shazsterblog.blogspot.com/2014/02/spring-security-custom-filterchainproxy.html
http://docs.spring.io/spring-security/site/docs/3.0.x/apidocs/org/springframework/security/web/context/SecurityContextPersistenceFilter.html
clearAuthentication flag was added in this commit with comment
Previously there was a race condition could occur when the user attempts to access
a slow resource and then logs out which would result in the user not being logged
out.SecurityContextLogoutHandler will now remove the Authentication from the
SecurityContext to protect against this scenario.
It fixed this issue (same issue on github). Quote:
HttpSessionSecurityContextRepository restores authentication to the session if session is invalidated from another thread if SecurityContextPersistenceFilter execution takes significant amount of time.
I am using Spring + JSF + DWR framework + GWT event service (ajax push). In any time there is at least one thread waiting at the server side for push events. This request is handled by SecurityContextPersistenceFilter which remembers the authentication at the moment of request's arriving to the server. If during the processing of this filter the session is being invalidated (by clicking logout in another tab of invalidating session by id from admin area) then HttpSessionSecurityContextRepository put the outdated authentication to the new session(which is created by JSF framework, so the session is changed during the processing of SecurityContextPersistenceFilter ).
This easily reproducable if some processing delay is inserted to SecurityContextPersistenceFilter.
SaveToSessionResponseWrapper should remember the initial HttpSession and check if the original session was invalidated so it won't set the current authentication to the new session.
http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html
Storing the SecurityContext between requests
Depending on the type of application, there may need to be a strategy in place to store the security context between user operations. In a typical web application, a user logs in once and is subsequently identified by their session Id. The server caches the principal information for the duration session. In Spring Security, the responsibility for storing the SecurityContext between requests falls to the SecurityContextPersistenceFilter, which by default stores the context as an HttpSession attribute between HTTP requests. It restores the context to the SecurityContextHolder for each request and, crucially, clears the SecurityContextHolder when the request completes. You shouldn't interact directly with the HttpSession for security purposes. There is simply no justification for doing so - always use the SecurityContextHolder instead.
Many other types of application (for example, a stateless RESTful web service) do not use HTTP sessions and will re-authenticate on every request. However, it is still important that the SecurityContextPersistenceFilter is included in the chain to make sure that the SecurityContextHolder is cleared after each request.
[Note] Note
In an application which receives concurrent requests in a single session, the same SecurityContext instance will be shared between threads. Even though a ThreadLocal is being used, it is the same instance that is retrieved from the HttpSession for each thread. This has implications if you wish to temporarily change the context under which a thread is running. If you just use SecurityContextHolder.getContext(), and call setAuthentication(anAuthentication) on the returned context object, then the Authentication object will change in all concurrent threads which share the same SecurityContext instance. You can customize the behaviour of SecurityContextPersistenceFilter to create a completely new SecurityContext for each request, preventing changes in one thread from affecting another. Alternatively you can create a new instance just at the point where you temporarily change the context. The method SecurityContextHolder.createEmptyContext() always returns a new context instance.
The SecurityContextLogoutHandler invalidates the Servlet session, in the standard Servlet way, calling the
invalidate method on the HttpSession object and also clearing the SecurityContext from Spring Security. SecurityContextLogoutHandler implements the LogoutHandler interface
Traditionally in Java web applications, user session information is managed with the HttpSession object.
In Spring Security(session clearing), at a low level, this is still the case ,
Spring security introduced new way of handling sessions or user session information.
In an application using Spring Security, you will rarely access the Session object directly for retrieving user
details. Instead, you will use SecurityContext (and its implementation class) and SecurityContextHolder
(and its implementing classes). The SecurityContextHolder allows quick access to the SecurityContext, the
SecurityContext allows quick access to the Authentication object, and the Authentication object allows quick
access to the user details.
for example following programing illustrates accesing authentication object and displaying message
#Controller
#RequestMapping("/admin")
public class AdminController {
#RequestMapping(method = RequestMethod.POST, value = "/movies")
#ResponseBody
public String createMovie(#RequestBody String movie) {
System.out.println("Adding movie!! "+movie);
return "created";
}
#RequestMapping(method = RequestMethod.GET, value = "/movies")
#ResponseBody
public String createMovie() {
UserDetails user = (UserDetails)SecurityContextHolder.getContext().getAuthentication().
getPrincipal();
System.out.println("returned movie!");
return "User "+user.getUsername()+" is accessing movie x";
}
}
once authentication is done it creates a new session is created;
Once session is created it contains information of user .on logout u need
not only to invalidate session but also need to clear the session information
by default in
`isInvalidateHttpSession(`)
checks whether session is valid or not
if session is valid
setInvalidateHttpSession(boolean invalidateHttpSession)
is called . howver invalidateing session object invalidates but session object still contains information.
to clear session information u need to call
setClearAuthentication(boolean clearAuthentication)
method thus becomes thread safe if u dont it third method it information can be retrieved at low level
I'm new to Spring Security, so forgive me if this is straight forward.
We are in the process of rewriting the UI layer of a legacy web app. We decided that the new UI layer would be based on Spring MVC with Spring Security to handle security and authorization.
I've been looking at setting up security in the new app to mimic what we had in the previous app. In the old app, we basically have two entry points for users:
Internal users are authenticated via HTTP basic authentication which
performs the actual authentication using the clients LDAP server.
This authentication mechanism is configured on a JBoss server, so is
container-managed.
External users logs in via a third-party authentication service that validates the credentials. External user roles are stored in the LDAP server. When the third-party authentication service authenticates the credentials, a username and hardcoded password is used to authenticate them on the JBoss configured security domain so their roles are loaded.
I figured I would try and mimic this functionality in Spring Security but have so far come up short. I use an in-memory authentication provider in place of LDAP in my tests since its easier. I've got http basic authentication working for internal users.
I've tried subclassing AbstractPreAuthenticatedProcessingFilter and supplying the credentials through this, but it does seem to forward the credentials properly to the "default" authentication provider.
<http>
...
<http-basic />
<custom-filter position="PRE_AUTH_FILTER" ref="ExternalLoginFilter" />
</http>
<beans:bean id="ExternalLoginFilter" class="com.foo.ExternalLoginPreAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager" />
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider>
<user-service>
<user name="internal-user" password="password" authorities="ROLE_USER, ROLE_INTERNAL" />
<user name="external-user" password="password" authorities="ROLE_USER, ROLE_EXTERNAL" />
</user-service>
</authentication-provider>
</authentication-manager>`
Here is my ExternalLoginPreAuthenticationFilter:
public class ExternalLoginPreAuthenticationFilter extends AbstractPreAuthenticatedProcessingFilter {
#Override
protected Object getPreAuthenticatedCredentials(HttpServletRequest req) {
return "password";
}
#Override
protected Object getPreAuthenticatedPrincipal(HttpServletRequest req) {
HttpSession session = req.getSession(false);
if(session != null){
return session.getAttribute("app.external-user.username");
}
return null;
}
}
I also tried setting up a "preAuthenticatedAuthenticationProvider" like some examples propose, but that seems to expect that my ExternalLoginPreAuthenticationFilter has resolved user roles as well.
Any ideas how I can configure Spring MVC to allow the scenario above? Basically, I need to be able to tell Spring Security to perform the login against the default authentication provider with a specific username/password in the least intrusive way, preferably without too many hacks (which the old application uses).
Note on solution: While Ralph's solution seem to work, specifically this portion:
I think using the PreAuthenticatedAuthenticationProvider and set the preAuthenticatedUserDetailsService variable to your in memory AuthenticationUserDetailsService should be the way to go.
However, it also seems to play badly with CSRF protection. When I log in, and is redirected to the homepage, any HTTP POST from this page will fail the CSRF check. A subsequent GET of the homepage before POST'ing fixes the issue, so it seems Spring somehow overwrites the current CSRF token improperly. I found a bug report detailing the problem. Even though it claims to be fixed, I have not been able to work around it. While the bug report links to a workaround in the forum, I have instead used to following workaround, which seems to work.
The trick is to inject the AuthenticationManager into your Controller and do the login yourself:
#Controller
#RequestMapping(value = "/external-login")
public class ExternalLoginController {
private AuthenticationManager authenticationManager;
#Autowired
public ExternalLoginController(AuthenticationManager authenticationManager){
this.authenticationManager = authenticationManager;
}
// ...
#RequestMapping(method = RequestMethod.POST)
public String login(){
// Do this after third-party authentication service accepts credentials
String username = "external-user"; // or whatever username was authenticated by third-party
UsernamePasswordAuthenticationToken credentials = new UsernamePasswordAuthenticationToken(username, "password");
Authentication auth = authenticationManager.authenticate(credentials);
SecurityContextHolder.getContext().setAuthentication(auth);
return "redirect:/";
}
}
The problem is, that the AuthenticationProvider is selected in the AuthenticationManager by the authentication credential class that is provided (often a subclass of AbstractAuthenticationToken).
Your PreAuthenticationProcessingFilter will create a PreAuthenticatedAuthenticationToken, that is normaly "consumed" by an PreAuthenticatedAuthenticationProvider.
So either:
you register a AuthenticationProvider that "consume" the PreAuthenticatedAuthenticationProvider token, and do what you want, or
you change the PreAuthenticationProcessingFilter to create an other kind of token (for example a UsernamePasswordAuthenticationToken that is "consumed" by the "normal" authentication provider you use (subclass of AbstractUserDetailsAuthenticationProvider))
I think using the PreAuthenticatedAuthenticationProvider and set the preAuthenticatedUserDetailsService variable to your in memory AuthenticationUserDetailsService should be the way to go.
I want to make an automatic login into web application, which will be accessible on company's intranet.
The login will function in a way that when user is accessing the application, he will automatically send its credentials (username and password), example (company.com/myapplication/login?user=jhon&pass=123).
How can I implement that instead standard Spring Security login using HTML forms? Maybe using hidden form which will be then filled with GET parameters? I can't find any examples for that scenario.
My part is only after user has sent the link with parameters.
You can do this is two ways (or more). (after our comment, it seams that you need to go with way two, because you do not have a username and password)
First way:
Use the standard spring form login and then modify you application so that is send login request like the normal web form login would do.
Assume you have configured the login-processing-url="/login/j_spring_security_check"
<security:form-login
login-processing-url="/login/j_spring_security_check"
login-page="/login"
authentication-failure-url="/login?login_error=t" />
then send a
HTTP POST to https://yourApplication/login/j_spring_security_check with the two POST parameters
j_username=<login>
j_password=<password>
Second way:
Write your own Authentication Processing filter. That is a class that extends AbstractAuthenticationProcessingFilter and it is responsible for
taking stuff that the user used to authenticate (normally username and password) from the request,
forming some the users authentication token object from them (for example an UsernamePasswordAuthenticationToken)
and invoking AuthenticationManager.authenticate(Authentication authentication) with this authentication token
To register your filter, you only need to add them to the spring security filter chain:
<security:custom-filter ref="yourFilter" after="FORM_LOGIN_FILTER"/>
I recommend to have a view on the UsernamePasswordAuthenticationFitler (and keep in mind that is extends AbstractAuthenticationProcessingFilter) - this will explain it best.
If you do not have an username and password, then you need to create your own token (extends Authentication) and then you have to implement your own AuthenticationProvider (and register with the AuthenticationManager). A AuthenticationProvider is reponsible to
- consume an (special type of) Authentication Token and
- validating that the stuff in the Authentication Token is valid
- creating an OTHER Authentication object with UserDetails and Privileges
- or, if the Authentication Token is not valid, throwing an AuthenticationException
Have a look at AbstractUserDetailsAuthenticationProvider and its subclass, for an example.
Is there a way to pass URL parameters to an authentication provider in Spring Security 3?
Our login page will need to receive an email token as a parameter that the authentication system will need to be aware of when it sets the status of the user. Specifically, it will let a user with a correct token log in that would not otherwise be able to.
I have a custom class extending the DaoAuthenticationProvider class. My authentication logic is in that class's authenticate method.
I'm hoping there is some way to pass this data into the authenticate method.
You could inject the HttpServletRequest object on your authentication provider class:
private #Autowired HttpServletRequest request;
Now, you should be able to access the request parameters with APIs such as request.getParameterValues(paramName)
You need to override UsernamePasswordAuthenticationFilter.setDetails() and pass extra information to your custom authentication provider via details property of UsernamePasswordAuthenticationToken.