Integrating Token based security into existing Spring Security web application - spring

I am designing a RESTful web services that needs to be accessed by user after proper authentication. I have already developed Security for my application using Spring Security 3.0. Now I want to integrate TokenBasedAuthentication. But I stuck here for how do i do this.
My ApplicationContextSecurity.xml:
<global-method-security pre-post-annotations="enabled">
</global-method-security>
<beans:bean id="myAccessDecisionManager"
class="com.app.security.MyAccessDecisionManager">
</beans:bean>
<http auto-config="true" once-per-request="true"
access-decision-manager-ref="myAccessDecisionManager"
access-denied-page="/jsp/errorPage.jsp">
<intercept-url pattern="/*.app" access="ROLE_ANONYMOUS" />
<form-login login-page="/login.app"
login-processing-url="/j_spring_security_check" default-target-url="/login/checking.app"
authentication-failure-url="/login.app?login_error=1" />
<logout logout-url="/j_spring_security_logout"
logout-success-url="/login.app" invalidate-session="true" />
<session-management invalid-session-url="/login.app"
session-fixation-protection="newSession">
<concurrency-control max-sessions="100"
error-if-maximum-exceeded="false" />
</session-management>
</http>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="customAuthenticationProvider"></authentication-provider>
</authentication-manager>
<beans:bean id="customAuthenticationProvider"
class="com.app.security.CustomAuthenticationProvider">
</beans:bean>
My CustomAuthenticationProvider :
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Autowired
private ILoginService loginService;
protected final transient Log log = LogFactory.getLog(getClass());
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
UsernamePasswordAuthenticationToken usernamePassswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
authentication.getPrincipal(), authentication.getCredentials());
// Doing authentication process here and returning authentication token
return usernamePassswordAuthenticationToken;
}
public boolean supports(Class<? extends Object> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
My requirement is,
When user want to access rest web service at first time he should provide userName/password to the server from header.
Server will accept the request, check the authentication and generate token for future requests for specific period.
Also I need client side code for how to access secured web services.
Thanks.

When user want to access rest web service at first time he should
provide userName/password to the server from header.
Server will accept the request, check the authentication and generate
token for future requests for specific period
You can do this either using HTTP headers or a normal HTTP POST request mapped to a Spring MVC controller (this is how we do it in our apps):
#Controller
public class AuthenticationController {
#Autowired
#Qualifier("authenticationManager")
AuthenticationManager authenticationManager;
#Autowired
SecurityContextRepository securityContextRepository;
#RequestMapping(method = RequestMethod.POST, value = "/authenticate")
public #ResponseBody String authenticate(#RequestParam final String username, #RequestParam final String password, final HttpServletRequest request, final HttpServletResponse response) {
final UsernamePasswordAuthenticationToken authenticationRequest = new UsernamePasswordAuthenticationToken(username, password);
final Authentication authenticationResult = this.authenticationManager.authenticate(authenticationRequest);
final String token = <some randomly generated secure token>;
final Authentication authentication = new MyAuthenticationToken(authenticationResult, token);
SecurityContextHolder.getContext().setAuthentication(authentication);
this.securityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response);
return token;
}
}
Once this is done, the client should send the token in an HTTP header with every subsequent request.
Also I need client side code for how to access secured web services
Not sure what exactly you are looking for here. If your client is a JavaScript library running in a web browser, setting the authentication token as an HTTP header with every request should be straightforward. If your client is a device, the device could store the token in memory and include it as an HTTP header with every request using whatever HTTP client library you are using to invoke the services.

Related

Where to put custom post-authentication code using UsernamePasswordAuthenticationFilter

I'm using Spring and custom implementation of UsernamePasswordAuthenticationFilter. I want to perform some custom code after successful authentication (for example: log a message with username that just got authenticated).
Which method should I override or how to register a handler for successful authentication ?
Is it good idea to override successfulAuthentication() method, put there my custom code and finish it with call to original method (super.successfulAuthentication();) ? Or there is some other best practise?
My approach for performing custom tasks after a successful
authentication is to use a Custom Authentication Success Handler in
Spring Security.
You can achieve this as below:
Create your custom AuthenticationSuccessHandler like TMGAuthenticationSuccessHandler. I have created a sample code which redirects user to the password change page, if the user is detected to be using the default machine generated password.
#Component("tMGAuthSuccessHandler")
public class TMGAuthSuccessHandler implements AuthenticationSuccessHandler {
private AuthenticationSuccessHandler target = new SavedRequestAwareAuthenticationSuccessHandler();
#Autowired
private UserService userService;
private static final Logger LOGGER = LoggerFactory.getLogger(TMGAuthSuccessHandler.class);
#Override
public void onAuthenticationSuccess(HttpServletRequest servletRequest, HttpServletResponse servletResponse, Authentication authentication)
throws IOException, ServletException {
if (hasDefaultPassword(authentication)) {
LOGGER.debug("Default password detected for username: " + authentication.getName());
servletResponse.sendRedirect("changePassword");
} else {
target.onAuthenticationSuccess(servletRequest, servletResponse, authentication);
}
}
/**
* Checks whether default password is used in login.
*/
private boolean hasDefaultPassword(Authentication authentication) {
String username = authentication.getName();
User user = userService.findOnUsername(username, true, false, false, false);
if (user != null && user.getLoginAuditTrail() != null && user.getLoginAuditTrail().isDefaultPasswordUsed() != null) {
return user.getLoginAuditTrail().isDefaultPasswordUsed();
}
return false;
}
/**
* Proceeds to the requested URL.
*/
public void proceed(HttpServletRequest servletRequest, HttpServletResponse servletResponse, Authentication authentication) throws IOException,
ServletException {
target.onAuthenticationSuccess(servletRequest, servletResponse, authentication);
}
}
Modify the securityContext.xml or similar file that contains spring security related configurations. Add this customHander to http configuration as authentication-success-handler-ref="tMGAuthSuccessHandler". Code snippet is shown below:
<security:http use-expressions="true" authentication-manager-ref="webAppAuthManager">
<!-- signin and signout -->
<security:intercept-url pattern="/signin" access="permitAll" />
<security:intercept-url pattern="/logout" access="permitAll" />
<security:intercept-url pattern="/accessDenied" access="permitAll"/>
<security:intercept-url pattern="/**" access="isAuthenticated()" />
<!-- sign in Configuration -->
<security:form-login login-page="/signin"
username-parameter="username"
password-parameter="password"
authentication-failure-url="/signin?authFail=true"
authentication-success-handler-ref="inoticeAuthSuccessHandler" />
<security:logout logout-url="/signout" invalidate-session="true" delete-cookies="JSESSIONID" logout-success-url="/signin?logout=true" />
</security:http>
You are good to go now.
Reference credit: How to use custom filter with authentication-success-handler-ref equivalent in spring security
You have at least two options:
AuthenticationSuccessHandler
ApplicationListener<E extends ApplicationEvent> with AbstractAuthenticationEvent

How does spring security work with client certificate authentication when using a POST method

When I use RestTemplate of spring framework to connect to my web service which is secured by HTTPS with client authentication by spring security through Restful API, I found problem to use POST method. It seems that the X509AuthenticationFilter don't get the client certificate when I use POST method. I don't have the same problem when I use GET method.
The following is the XML configuration file for spring security in the server side.
<http pattern="/resources/**" security="none" />
<http auto-config="true" use-expressions="true" entry-point-ref="forbiddenAuthEntryPoint">
<intercept-url pattern="/" access="permitAll" />
<intercept-url pattern="/service/**" access="hasRole('ROLE_ABC_USER')" />
<intercept-url pattern="/**" access="permitAll" />
<!-- <x509 subject-principal-regex="CN=(.*?)," user-service-ref="userDetailsService"
/> -->
<custom-filter position="X509_FILTER" ref="myX509AuthenticationFilter" />
</http>
<bean:bean id="myX509AuthenticationFilter"
class="com.ray.MyX509AuthenticationFilter">
<bean:property name="authenticationManager" ref="authenticationManager" />
</bean:bean>
<bean:bean id="preauthAuthenticationProvider"
class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<bean:property name="preAuthenticatedUserDetailsService" ref="authenticationUserDetailsService" />
</bean:bean>
<bean:bean id="authenticationUserDetailsService"
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<bean:property name="userDetailsService" ref="userDetailsService" />
</bean:bean>
<bean:bean id="forbiddenAuthEntryPoint"
class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
<authentication-manager alias="authenticationManager">
<authentication-provider ref="preauthAuthenticationProvider" />
<authentication-provider>
<user-service id="userDetailsService">
<user name="www.ray.insight" password="dummy" authorities="ROLE_ABC_USER" />
</user-service>
</authentication-provider>
</authentication-manager>
Originally, I use the standard x509 element in the security namespace as you can see from the comment out line. During my testing, I use the following MyX509AuthenticationFilter for debugging purpose.
public class MyX509AuthenticationFilter extends X509AuthenticationFilter {
private static final Logger LOGGER = LoggerFactory.getLogger(MyX509AuthenticationFilter.class);
protected Object getPreAuthenticatedPrincipal(HttpServletRequest request) {
X509Certificate[] certs = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
if (certs != null && certs.length > 0) {
LOGGER.debug("X.509 client authentication certificate:" + certs[0]);
} else {
LOGGER.debug("No client certificate found in request.");
}
return super.getPreAuthenticatedPrincipal(request);
}
}
In order to further debug the request. I have added the following servlet filter in web.xml before spring security to print out the client certificate.
public class MyRequestFilter implements Filter {
Logger LOGGER = LoggerFactory.getLogger(MyRequestFilter.class);
#Override
public void doFilter(ServletRequest _servletRequest, ServletResponse _servletResponse, FilterChain _filterChain)
throws IOException, ServletException {
LOGGER.debug("MyRequestFilter doFilter(): Entering");
if (_servletRequest instanceof HttpServletRequest) {
HttpServletRequest httpServletRequest = (HttpServletRequest) _servletRequest;
String requestURI = httpServletRequest.getRequestURI();
String queryString = httpServletRequest.getQueryString();
StringBuffer requestURL = httpServletRequest.getRequestURL();
LOGGER.debug("requestURI ->" + requestURI + "<-");
LOGGER.debug("queryString ->" + queryString + "<-");
LOGGER.debug("requestURL ->" + requestURL.toString() + "<-");
X509Certificate[] certs = (X509Certificate[]) httpServletRequest
.getAttribute("javax.servlet.request.X509Certificate");
if (certs != null && certs.length > 0) {
LOGGER.debug("X.509 client authentication certificate:" + certs[0]);
} else {
LOGGER.debug("No client certificate found in request.");
}
} else {
LOGGER.debug("get non HttpServletRequest!!" + _servletRequest);
}
_filterChain.doFilter(_servletRequest, _servletResponse);
}
}
In order to use client authentication, I have also setup the tomcat to use client authentication and the following line is added to the server.xml.
<Connector SSLEnabled="true" acceptCount="100" clientAuth="true"
disableUploadTimeout="true" enableLookups="false" keyAlias="abcServer"
keypass="password" keystoreFile="tomcat8Cert2.jks" keystorePass="password"
maxHttpHeaderSize="8192" maxSpareThreads="75" maxThreads="150"
minSpareThreads="25" port="443" scheme="https" secure="true"
sslProtocol="TLS" truststoreFile="trustStoreCert2.jks"
truststorePass="password" />
By using the above program and configuration, if I involve web service through GET method, everything work fine. However, if I involve web service through POST method, the MyRequestFilter can print out the certificate with the correct CN, but the MyX509AuthenticationFilter has not printed out anything and spring security just return "org.springframework.web.client.HttpClientErrorException: 403 Forbidden". This exception should come from Http403ForbiddenEntryPoint of spring security.
I have further test the same web service after comment out spring security filter in my web.xml of the server side and involve it through the same client code. It work. Hence, I suspect something wrong with my setting that make the spring security cannot work property with the POST method to do the client certificate authentication. Any body has idea what I have missed in spring security?
=====================
In case you may interesting to know my client code. The following is the code snippet in the client side.
I use the following to initialize the RestTemplate.
private void initialise() {
restTemplate = new RestTemplate();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient());
factory.setReadTimeout(30000);
factory.setConnectTimeout(30000);
restTemplate.setRequestFactory(factory);
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
}
The following code is used to return the httpclient with all the required keystore.
KeyStore trustStore = KeyStore.getInstance(this.getKeyStoreType());
FileInputStream instream = new FileInputStream(new File(this.getKeyStorePath()));
try {
trustStore.load(instream, this.getKeyStorePassword().toCharArray());
} finally {
instream.close();
}
// TODO: Should trust only authorized client
TrustStrategy allTrust = new TrustStrategy() {
#Override
public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
return true;
}
};
SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(
trustStore, allTrust)
.loadKeyMaterial(trustStore, this.getKeyStorePassword()
.toCharArray())
.build();
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext,
SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
Then the following code is used to involve the web service through POST.
response = restTemplate.postForEntity(this.getBasePath() + path, httpEntity, String.class);
And the following code is used to involve the web service through GET.
response = restTemplate.exchange(this.getBasePath() + path, HttpMethod.GET, httpEntity,
String.class);

spring security authentication using ip address and username password

I am using loadUserByUsername method to authenticate user, however, I need to validate against allowed ip addresses as well.
But when I am trying
SecurityContextHolder.getContext().getAuthentication();
getting null.
Please advice, how I can access users client ip address while authenticating user.
To solve your problem you should implement custom authentication provider (that can be based on DaoAuthenticationProvider or can be implemented from scratch, etc). This authentication provider should be registered in Authentication manager providers set. Also, this provider will have autowired HttpServletRequest type property, related to context http request. Then, when you performing client authenticationv via that provider, you can obtain user IP address by invoking HttpServletRequest.getRemoteAddr().
Code:
/**
* IP address based authentication provider
*/
#Service
public class IPAddressBasedAuthenticationProvider extends AuthenticationProvider {
/**
* Context http request
*/
#Autowired
private HttpServletRequest request;
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String ipAddress = request.getRemoteAddr();
//do authentication specific stuff (accessing users table in database, etc.)
//return created authentication object (if user provided valid credentials)
}
}
Configuration:
<security:http auto-config="true" authentication-manager-ref="authenticationManager" use-expressions="true"/>
<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
<constructor-arg name="providers">
<list>
<ref bean="iPAddressBasedAuthenticationProvider"/>
</list>
</constructor-arg>
</bean>
Also, you can add other authentication providers (if you need to).
Hope this helps.
Links: AuthenticationProvider
ProviderManager
/**
* IP address based authentication provider
*/
#Service
public class IPAddressBasedAuthenticationProvider extends AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
final WebAuthenticationDetails details = (WebAuthenticationDetails) auth.getDetails();
details.getRemoteAddress();
}
}
You are implementing UserDetailsService's loadUserByUsername method.
As per documentation
There is often some confusion about UserDetailsService. It is purely a DAO for user data and performs no other function other than to supply that data to other components within the framework. In particular, it does not authenticate the user, which is done by the AuthenticationManager. In many cases it makes more sense to implement AuthenticationProvider directly if you require a custom authentication process.
UserDetails userDetails= customUserDetailsService.loadUserByUsername("name");
this will give a userDetails object.You can do all authority related code in loadUserByUsername().If you would like to manually set an authenticated user in Spring Security.follow the code
Authentication authentication= new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()) ;
SecurityContextHolder.getContext().setAuthentication(authentication);
You will get IP address from request header.
How can I retrieve IP address from HTTP header in Java
you can do that somewhere in spring security filterchain.

Spring Security login with a rest web service

I have a SpringMVC web application that needs to authenticate to a RESTful web service using Spring Security.And i need to access this same application through a rest client.
Here is What I need to implement
The accept header is application/json(For a java rest client )
After a successful login, It will be sent a token(Or sessionId) to rest client in the format of json
After a login failure,It will be sent error message in the format of json.
For a web request
After a successful login,It will be redirecting to a success jsp page.
After a login failure,It will be sent error message to the same loin page.
How can i do this with spring mvc and spring security?.I have very less time to do this,any one please give me an example with spring-security.xml.
Thanks
my recommendation is as below. you can use standard web security to call RESTFul service, first authenticate with user and password and get cookies, if using java based server, send this as cookie to server on subsequent rest calls. I have written is Spring Java code which can get session cookies for you.
There is no need for separate json service to get token.
public class RestAuthClient {
String baseUrl = "http://localhost:8888/ecom";
public String authenticateGetCookie(String user, String password){
HttpMessageConverter<MultiValueMap<String, ?>> formHttpMessageConverter = new FormHttpMessageConverter();
HttpMessageConverter<String> stringHttpMessageConverternew = new StringHttpMessageConverter();
List<HttpMessageConverter<?>> messageConverters = new LinkedList<HttpMessageConverter<?>>();
messageConverters.add(formHttpMessageConverter);
messageConverters.add(stringHttpMessageConverternew);
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("j_username", user);
map.add("j_password", password);
String authURL = baseUrl+"/j_spring_security_check";
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(messageConverters);
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<MultiValueMap<String, String>>(map,
requestHeaders);
ResponseEntity<String> result = restTemplate.exchange(authURL, HttpMethod.POST, entity, String.class);
HttpHeaders respHeaders = result.getHeaders();
System.out.println(respHeaders.toString());
System.out.println(result.getStatusCode());
String cookies = respHeaders.getFirst("Set-Cookie");
return cookies;
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
}
Consider implementing your custom AuthenticationSuccessHandler and AuthenticationFailureHandler as described below.
You might also need to implement some simple controllers which you will be redirecting to from AuthenticationHandlers. There's a good explanation of how to implement REST auth in Spring. So I beleive combining these two answers will give you a solution.
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// get accept headers from request
// Redirect successfully logged in user to another url depending on the accept headers)
// put session id in response if needed
((WebAuthenticationDetails)SecurityContextHolder.getContext().getAuthentication().getDetails()).getSessionId();
String targetUrl = ""; //TODO insert here
response.sendRedirect(targetUrl);
}
}
public class AuthenticationFailureHandlerImpl extends SimpleUrlAuthenticationFailureHandler implements AuthenticationFailureHandler {
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
// get accept headers from request
// set failure url
// Do redirecting job
setDefaultFailureUrl(FAILURE_URL);
super.onAuthenticationFailure(request, response, exception);
}
}
In your security.xml
<http entry-point-ref="loginUrlAuthenticationEntryPoint" access-denied-page="/WEB-INF/views/errors/error403.jsp" access-decision-manager-ref="accessDecisionManager">
...
<custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER"/>
...
</http>
<!-- Login filter and entry point -->
<beans:bean id="loginUrlAuthenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/signin" /></beans:bean>
<beans:bean id="loginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager"/>
<beans:property name="filterProcessesUrl" value="/j_spring_security_check"/>
<beans:property name="authenticationSuccessHandler" ref="authSuccessHandler"/>
<beans:property name="authenticationFailureHandler" ref="authFailureHandler"/></beans:bean>
<!-- Login filter and entry point -->
<beans:bean id="authSuccessHandler" class="com.example.security.AuthenticationSuccessHandlerImpl"/>
<beans:bean id="authFailureHandler" class="com.example.security.AuthenticationFailureHandlerImpl"/>
</beans:beans>

remember-me and authentication-success-handler

i have strange issue of for login sucess and redirect to page.
below is my spring security configuration.
<http auto-config="true" use-expressions="true">
<intercept-url pattern="/login.hst**" access="anonymous or authenticated" />
<intercept-url pattern="/**/*.hst" access="authenticated" />
<form-login login-page="/login.hst"
authentication-failure-url="/login.hst?error=true"
authentication-success-handler-ref="loginSucessHandler" />
<logout invalidate-session="true" logout-success-url="/home.hst"
logout-url="/logout.hst" />
<remember-me key="jbcpHaverERP" authentication-success-handler-ref="loginSucessHandler"/>
<session-management>
<concurrency-control max-sessions="1" />
</session-management>
</http>
LoginSuessHandler class:
#Service
public class LoginSucessHandler extends
SavedRequestAwareAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws ServletException, IOException {
...
super.setUseReferer(true);
super.onAuthenticationSuccess(request, response, authentication);
}
}
now problem of redirect to requested page on success. if i directly refer to any secure url spring redirects me to login page and on successful login to original requested link.
but this is not working in case if user had earlier selected remember-me and then closing browser and now requesting direct URL, he is being properly authenticated but instead of redirecting him to requested page spring redirects to /. i have checked log and some spring source code and found it is not able to determine target url.
i have tried to set refer but referer value is null. but one strange thing i have noticed that in spring security configuration if i remove authentication-success-handler from remember-me configuration then it works.
<remember-me key="jbcpHaverERP" authentication-success-handler-ref="loginSucessHandler"/>
not able to figure out issue. is authentication-success-handler implementation requied to be different for form login and remember-me?
Remember-me differs from form-login in that authentication occurs during the actual request the user makes. For form-login, the user must first be redirected to the login page, submit the login form and after that they are redirected to the original target (which is usually cached in the session). So form-login requires a redirect, whereas remember-me doesn't. With a remember-me request, the user can be authenticated, and the request allowed to proceed without any intervention.
The primary purpose of an AuthenticationSuccessHandler is to control the navigation flow after authentication, so you wouldn't normally use one with remember-me at all. Using SavedRequestAwareAuthenticationSuccessHandler isn't a good idea, as there won't be a saved request available. If there is no saved request, then by default it will perform a redirect to "/" as you have observed.
If all you want is to add some functionality during a remember-me login, then you can implement the AuthenticationSuccessHandler interface directly without performing a redirect or a forward. As I explained above, you can't use the same implementation for form-login, since the current request is the submission of the login form (usually to the URL j_spring_security_check), and not a request to a URL within your application. So you need a redirect for form-login.
You would rather use ApplicationListener and look for the event InteractiveAuthenticationSuccessEvent.
InteractiveAuthenticationSuccessEvent has a property generatedBy which will be the filter, ie UsernamePasswordAuthenticationFilter (form logins) and RememberMeAuthenticationFilter (remeber me logins)
#Component
class AuthenticationApplicationListener implements ApplicationListener<InteractiveAuthenticationSuccessEvent> {
#Override
void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {
//do something
}
}
using a custom implementation of AuthenticationSuccessHandler on rememberMe will cause problems. Take a look at the flow in RememberMeAuthenticationFilter. if the successHandler is used, the filter chain is bypassed
Using an AuthenticationSuccessHandler does not work. As stated in another answer, the spring security filter chain will be bypassed!
What works, is to use an ApplicationListener - as another answer also proposes. But to find out, if your user is authenticated by remember me, the idea to use InteractiveAuthenticationSuccessEvent.getGeneratedBy() is not working: getGeneratedBy returns Class<T>, that means a generic. Therefore at runtime you cannot find out, if T is a RememberMeAuthenticationFilter.
What worked fine for me: Use InteractiveAuthenticationSuccessEvent.getAuthentication().
Here an example (by the way: #EventListener is used since Spring Security 4.2 - if you use an earlier version, do the following via implementing ApplicationListener<InteractiveAuthenticationSuccessEvent>):
#Component
public class AuthenticationApplicationListener {
#EventListener
public void handleInteractiveAuthenticationSuccess(InteractiveAuthenticationSuccessEvent event) {
if (RememberMeAuthenticationToken.class.isAssignableFrom(event.getAuthentication().getClass())) {
.... do some stuff
}
}
}
You should implement different authentication-success-handler for login form and for remember-me.
If you want to perform redirect in remeber-me handler you can use SimpleUrlAuthenticationSuccessHandler and set DefaultTargetUrl.
public class RememberMeAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
// ...
super.setAlwaysUseDefaultTargetUrl(true);
super.setDefaultTargetUrl(request.getRequestURL().toString());
super.onAuthenticationSuccess(request, response, authentication);
}

Resources