Adding Parameters to Spring Security Logout - spring

Hai can I add parameters to Spring Security Logout. I have configured logout request in security.xml as below.
<sec:logout invalidate-session="true" logout-success-url="/logoutsuccess.do" logout-url="/logout.do" />
while Login, after successful login, I am validating various aspects of user account on Custom Success Handler to validate the Account Subscription Status, Approve/DisApprove etc and based on it will send Logout request if any of the condition fails. I would like to display custom error message on logout page and so would like to send that parameter along with logout request.

Write a custom logout handler. Put attribute success-handler-ref in xml configuration file.
e.g
<sec:logout invalidate-session="true" logout-success-url="/logoutsuccess.do"
logout-url="/logout.do"
success-handler-ref="YourCustomLogoutSuccessHandler"/>
Then extend the SimpleUrlLogoutSuccessHandler or implement the LogoutHandler.
e.g
public class YourCustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
//Do what you want to do here
//.......
//below does the 'standard' spring logout handling
super.onLogoutSuccess(request, response, authentication);
}
}
An alternate way of doing this is shown here. This also shows how to redirect to a particular url and manually handle session management.

Related

is there any way to "reset" the csrf token after successful login?

I just enabled the csrf token protection on my spring security (with xml) by adding the csrf tag.
It works great but I noticed when I hit the login form I am sending a csrf token, after a successful login the csrf token is still the same, is there anyway I can reset it after hit the login form?
After checking the docs I found no clue how to do this or if is due my repository? (Im not using any custom csrf repository)
Ideas?
The official documentation states that the CSRF token is stored in the HttpSession by default. Since the token is stored in the session, it will continue to get reused after the user has logged in.
If you really want to reset the token on a successful login, you will have to handle successful login events.
public class AuthenticationSuccessCsrfTokenResetHandler
extends SimpleUrlAuthenticationSuccessHandler {
private final CsrfTokenRepository repository;
public AuthenticationSuccessCsrfTokenResetHandler(final CsrfTokenRepository repository) {
this.repository = repository;
}
#Override
public void onAuthenticationSuccess(final HttpServletRequest request
, final HttpServletResponse response
, final Authentication authentication)
throws ServletException, IOException {
repository.saveToken(repository.generateToken(request), request, response)
}
}
Then, configure this handler in your Spring Security configuration.

Spring Security: Redirect to Login Page in case of 401

I have an application that exposes a REST API and is secured using Spring Security. Is there a way to automatically redirect the client (from the server side) to the login page if a request sent to my server results in 401 - unauthorised?
For spring-security application based on spring-boot.
Define a handler bean:
#Component
public class CommenceEntryPoint implements AuthenticationEntryPoint, Serializable {
private static final long serialVersionUID = 565662170056829238L;
// invoked when user tries to access a secured REST resource without supplying any credentials,
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
// send a json object, with http code 401,
// response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
// redirect to login page, for non-ajax request,
response.sendRedirect("/login.html");
}
}
In security config class (e.g WebSecurityConfig):
Autowire the bean:
#Autowired
private CommenceEntryPoint unauthorizedHandler; // handle unauthorized request,
Specify handler:
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() // excepion handler,
Tips:
This is suitable only for non-ajax request,
For ajax request, better return 401 code, and let the frontend handle it.
If you want to use 401 response, in CommenceEntryPoint.commence() just use response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized"); instead of response.sendRedirect().
You can specify how your application handles exception or HTTP status codes by specifying it in error-page element of web.xml
eg: web.xml
<error-page>
<error-code>401</error-code>
<location>/login.html</location>
</error-page>
Same way you handle other HTTP status code viz 404 for page not found page.
I solved this issue by adding the following elements to my Spring Security XML under an http node:
<security:access-denied-handler error-page="/#/login" />
<security:session-management invalid-session-url="/#/login" session-fixation-protection="changeSessionId" />

Call a bean AFTER successful spring security login?

If I have spring security working, how can I have it call a bean to initialize all my user data once it has logged in? I can do a Servlet Filter but it calls that on every request. I want to just call some init code to load some user data into the session after the user logs in.
When the user logs in correctly spring security call an instance of AuthenticationSuccessHandler. What you want to do is create your own bean and use that to perform whatever extra actions you want.
Your class would probably look something like this:
public class YourAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//do whatever you want
super.onAuthenticationSuccess(request, response, authentication);
}
}
Also register your class as a spring bean
<beans:bean id="authenticationSuccessHandler"
class="your.package.YourAuthenticationSuccessHandler"/>
and add it to the form login security configuration as the value of authentication-success-handler-ref

Integrating Token based security into existing Spring Security web application

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.

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