I am working on a spring MVC application And we are using Spring Security.
Now I have a requirement that as soon I enter into the application, a pop up should be displayed. So the application might enter directly into home page or to his profile page or to any other flow in the application. But I need to show the pop up irrespective of where the user enters.
How do I achieve this using Spring security or any other alternative please?
I have tried:
config.xml:
<bean id="popUpFilter" class="myPackage.security.popUpClass" />
<security:http entry-point-ref="myAppAuthEntryPoint" use-expressions="true">
.............
<security:custom-filter after="LOGIN_FILTER" ref="popUpFilter"/>
</security:http>
And My Code:
public class popUpClass implements AuthenticationSuccessHandler {
private static final Logger log = LoggerFactory.getLogger(popUpClass.class);
#Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
//do some logic here if you want something to be done whenever
//the user successfully logs in.
log.debug("Entered into customfilter");
HttpSession session = httpServletRequest.getSession();
User user = SecurityClass.getUserDetails();
session.setAttribute("id", user.ID());
session.setAttribute("state", user.State());
//set our response to OK status
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
//since we have created our custom success handler, its up to us to where
//we will redirect the user after successfully login
httpServletResponse.sendRedirect("home");
}
}
NOTE: Popup should appear only once after the user log in.
Related
I have an implementation of AuthenticationSuccessHandler that catches the request after user is successfully logged in. So when processing is finished inside a handler, I want to redirect a user to the page that he first desired to go, before he was redirected to the login page, and not to some hardcoded page. Is this possible?
This is how my handler implementation looks like:
#Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
Util.setUserdata(userBean, authentication, request);
proceed(request, response, authentication);
}
To explain the problem more clearly, a short example:
User wants to land to a page app/test/page.html
He gets redirected login page and logs in successfully
Handler method gets invoked and I do some logic after which I want to redirect him back to app/test/page.html, but I don't know how to access the URL he wanted to land on before redirection to login page.
Spring security's ExceptionTranslationFilter actually stores the request in session before redirecting to login.
ExceptionTranslationFilter.java
And then it has SavedRequestAwareAuthenticationSuccessHandler which is a AuthenticationSuccessHandler that retrieves and forwards to it.
SavedRequestAwareAuthenticationSuccessHandler.java
You don't need to use that SavedRequestAwareAuthenticationSuccessHandler directly if you have some customization. You can get the previous url directly from session like session.getAttribute(""SPRING_SECURITY_SAVED_REQUEST") as well and it has url and method etc so you can do the redirect yourself. You will have to cast it to SavedRequest before you can the url etc if you are going this route
In a Spring MVC application I am trying to implement a custom logout success handler. This handler should access a session attribute and make some queries and logging bases on its value.
Relevant parts of the implementation:
Security configuration:
<http ...>
<logout success-handler-ref="logoutSuccessHandler"/>
</http>
<beans:bean id="logoutSuccessHandler" class="some.package.LogoutSuccessHandler">
<beans:constructor-arg value="/login" />
</beans:bean>
The handler itself:
public class LogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler {
#Autowired
private SomeService someService;
public LogoutSuccessHandler(String defaultTargetUrl) {
this.setDefaultTargetUrl(defaultTargetUrl);
}
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
String sessionAttribute = request.getSession().getAttribute("someAttribute").toString();
someService.doSomething(sessionAttribute);
super.onLogoutSuccess(request, response, authentication);
}
}
I am adding some attributes to the session when a user logs in. They are visible during different controller requests. The problem is, when I try to access session attributes during logout, they are all gone. Does that mean that by that time the logout has already taken place and session information is wiped out? I can see that SessionId is the same as before though.
So, my question is: what happens to the session attributes and is there a way to access them in LogoutSuccessHandler?
<logout success-handler-ref="logoutSuccessHandler" invalidate-session="false"/>
the default value of invalidate-session is true, so you will get a new session in your handler.
When you set this value to false, then you can get the old session, and don't forget to invalidate session after you finished your business.
I'm using Spring Boot and Spring Security. I have 2 apps. They works in couple. And when I want to logout from one, it should also logout from another. I use default logout flow. On application A I click logout link:
<logout invalidate-session="true" delete-cookies="JSESSIONID" logout-success-url="/app-b-logout" />
#RequestMapping("/app-b-logout")
public RedirectView appB_Logout() {
return new RedirectView("http://appB/logout");
}
On application B I have following settings:
.logout().permitAll().logoutUrl("/logout")
And logout success handler:
public class MyLogoutSuccessHandler extends AbstractAuthenticationTargetUrlRequestHandler
implements LogoutSuccessHandler {
#Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println(authentication == null); // MAGIC HERE
}
}
And in line System.out.println(authentication == null); I have different results. If I redirect from application A, authentication is null, when I click LOGOUT button on app B (using post form), I have authentication object.
But in both cases user is logged out in result. But I need to do some stuff with authentication object. How to make redirect on app A to make a POST request or just how to get this authentication when I redirect from app A?
I've been trying to implement OAuth2 password expiration filter and I'm unsure about what the proper way would be to do so. The idea is as follows:
User tries to login.
User gets response with a header containing token if the password is expired.
User get's redirected to password change page using that token (i.e. /password-change/{token}).
He submits his old and new passwords, it gets changed.
Some rest controller retrieves user id by that token and does the rest password changing logic.
User should be redirected back to the initial login page where he logins with his new password (if he would be logged in instantly after the password change, he could navigate through secured pages even if the password would not be changed in background due to some exception, etc.).
So... I set a custom flag in user details for password expiration because I can't use credentialsNonExpired as it gets validated in DaoAuthenticationProvider and thrown as an exception which gets processed as InvalidGrantException which doesn't give me much control. I've figured out that in order to access user details right after it's authentication my filter should be in the inner Spring Security filter chain placed after OAuth2AuthenticationProcessingFilter:
#Configuration
#EnableResourceServer
protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
...
http.addFilterAfter(new PasswordExpirationFilter(), BasicAuthenticationFilter.class
}
}
Why does my filter get placed after OAuth2AuthenticationProcessingFilter while there's no BasicAuthenticationFilter in the chain? I've digged through Spring Security and OAuth2 documentation and sources and couldn't find the right answer.
If that user's password is expired my filter generates some random string and it saves it to retrieve user details later during the password change request (at least it should be):
public class PasswordExpirationFilter extends OncePerRequestFilter implements Filter, InitializingBean {
private static final String TOKEN_HEADER = ...;
private ExpiredPasswordRepository repo; // gets set in a constructor and is basically holding a concurrent map of tokens
...
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
UserDetails details = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (details.isPasswordExpired) {
String uuid = UUID.randomUUID().toString();
repo.push(uuid, details.getId());
SecurityContextHolder.clearContext();
SecurityContextHolder.getContext().setAuthentication(null);
request.getSession(false).invalidate(); // don't create a new session
response.addHeader(TOKEN_HEADER, uuid);
response.sendError(HttpStatus.SC_PRECONDITION_FAILED, "Credentials have expired");
} else {
filterChain.doFilter(request, response);
}
}
}
Do I have to revoke the OAuth token as well? It gets reused in later requests and I keep getting the last userDetails object and therefore I keep getting the same response from my filter.
Is it even the right place to do all this validation? How should one validate the password for the concrete user and not the OAuth client?
Ok, I think I resolved this issue by revoking the access token via injected TokenStore in my filter (I used BearerTokenExtractor to get the token value) which seems pretty logical in this situtation. I still had no time to figure out, why my filter gets placed after OAuth2AuthenticationProcessingFilter, though.
I fail to retrieve the Spring remember me cookie after the login request, but it works fine in the next request to a protected page. Could anyone please tell me how I can get hold of it right away?
I am setting the remember me cookie in the login request, but fail to retrive it after Spring redirects back to the original (protected) url.
Step by step:
Browser goes to example.com/protected
Spring redirects to login form page
Upon successful login, the SPRING_SECURITY_REMEMBER_ME_COOKIE is set in a very thin custom sub class of org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices
It looks like Spring redirects back to example.com/protected, whithout a roundtrip to the browser, and both login "servlet" and protected page is handled by the same thread in Tomcat 6.
Our subclass of org.springframework.security.web.access.expression.WebSecurityExpressionRoot has methods that is invoked from a <intercept-url pattern="..." access="method()" />
In our method() request.getCookies() does not give the remember me cookie on the first request, but on all requests after that.
Our app has some problems because the cookie is missing...
My theory so far is that I don't understand SavedRequest properly.
Condensed config here:
<http auto-config="false" use-expressions="true" authentication-manager-ref="myAuthenticationManager" path-type="regex">
<form-login authentication-success-handler-ref="myAuthenticationSuccessHandler" login-page="..." login-processing-url="..." authentication-failure-url="..." username-parameter="username" password-parameter="password" />
<custom-filter ref="logoutFilter" position="LOGOUT_FILTER"/>
<expression-handler ref="myWebSecurityExpressionHandler" />
<custom-filter ref="myCustomeFilter1" before="FORM_LOGIN_FILTER"/>
<custom-filter ref="myCustomeFilter2" position="BASIC_AUTH_FILTER"/>
<custom-filter ref="mySecurityClientTokenAuthenticationFilter" after="LOGOUT_FILTER" />
<access-denied-handler ref="myAccessDeniedHandler"/>
<intercept-url pattern="xxx"
access="method()"/>
<intercept-url pattern="yyy"
access="method()"/>
<remember-me services-ref="rememberMeServices" key="my_remember"/>
</http>
I tried adding the following, with the only result that the user does not get redirected to the original page.
<http ...
<request-cache ref="nullRequestCache"/>
</http>
<bean:bean id="nullRequestCache" class="org.springframework.security.web.savedrequest.NullRequestCache"/>
When using request.getCookie() in autoLogin() method of RememberMeService, the request passed in is SavedRequestAwareWrapper which encapsulates original request and saved request and overrides the getCookies method.
#Override
public Cookie[] getCookies() {
List<Cookie> cookies = savedRequest.getCookies();
return cookies.toArray(new Cookie[cookies.size()]);
}
Therefore, when you want to get cookie from request, you actually get cookie from the savedRequest. However, the cookie may exist in the original request.
You probably should get the original request for getting cookies you want. For example:
public class ApplicationRememberMeServiceImpl implements RememberMeService, LogoutHandler {
public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {
HttpServletRequestWrapper savedRequestWrapper = (HttpServletRequestWrapper) ((HttpServletRequestWrapper) request).getRequest();
HttpServletRequest httpServletRequest = (HttpServletRequest) savedRequestWrapper.getRequest();
Cookie cookie = WebUtils.getCookie(httpServletRequest, cookieName);
// logic continues...
}
}
Update 03/05/2015
Because spring security will wrap the original HttpServletRequest multiple times, it is more safe to extracting the original request in the way below:
public class ApplicationRememberMeServiceImpl implements RememberMeService, LogoutHandler {
public Authentication autoLogin(HttpServletRequest request, HttpServletResponse response) {
HttpServletRequest httpServletRequest = request;
// Get the original request from multiple wrapped HttpServletRequest
if(httpServletRequest instanceof HttpServletRequestWrapper) {
HttpServletRequestWrapper httpServletRequestWrapper = (HttpServletRequestWrapper) httpServletRequest;
while(httpServletRequestWrapper.getRequest() instanceof HttpServletRequestWrapper) {
httpServletRequestWrapper = (HttpServletRequestWrapper) httpServletRequestWrapper.getRequest();
}
httpServletRequest = (HttpServletRequest) httpServletRequestWrapper.getRequest();
}
Cookie cookie = WebUtils.getCookie(httpServletRequest, cookieName);
// logic continues...
}
}