Spring Security: How to clear `remember me` cookie programmatically? - spring

I'm using logout method in web-app like below, but if i check remember me logout doesn't work, because cookie isn't cleared. How to clear programmatically this cookie in my method (or how to make better logout method) ?
public void logout() {
AnonymousAuthenticationToken anonymous = new AnonymousAuthenticationToken("anonymous", "anonymous", new ArrayList(Arrays.asList(new GrantedAuthorityImpl("ROLE_ANONYMOUS"))));
SecurityContextHolder.getContext().setAuthentication(anonymous);
}

If you are using the standard Spring Security cookie name (which is SPRING_SECURITY_REMEMBER_ME_COOKIE), you can do this:
void cancelCookie(HttpServletRequest request, HttpServletResponse response)
{
String cookieName = "SPRING_SECURITY_REMEMBER_ME_COOKIE";
Cookie cookie = new Cookie(cookieName, null);
cookie.setMaxAge(0);
cookie.setPath(StringUtils.hasLength(request.getContextPath()) ? request.getContextPath() : "/");
response.addCookie(cookie);
}
You'll have to change the cookieName value if you are using a custom cookie name.

The AbstractRememberMeServices class has an implementation of LogoutHandler.logout which cancels the cookie. Inject the LogoutHandler and call this method.

Related

set Domain on cookie using spring security when login success

How can I set the property "domain" on the users cookie when the user has authenticated from spring?
Edit: id like to add domain=".mydomain.com" to cookie with id JSESSIONID
I dont want to deal with spring-session-core or the particular implementation of the session like redis, and Im not using spring-boot. What is the easiest way to do this?
I dont want to jump in the rabbit hole of redis if I can avoid it.
Edit: investigated if set_cookie can be modified in custom implementation of AuthenticationSuccessHandlerImpl that extends AbstractAuthenticationTargetUrlRequestHandler, but "set_cookie" isnt set until
response.sendRedirect(redirectUrl);
of DefaultRedirectStrategy implements RedirectStrategy, but the also isCommitted()==True so set_cookie cant be changed.
I varified this by implementing my redirect strategy:
#Override
public void sendRedirect(HttpServletRequest request, HttpServletResponse response, java.lang.String url)
throws IOException {
LOGGER.info("sendRedirect cookie size: "+response.getHeaders(HttpHeaders.SET_COOKIE).size()+ " is commited:"+response.isCommitted());
String redirectUrl = calculateRedirectUrl(request.getContextPath(), url);
redirectUrl = response.encodeRedirectURL(redirectUrl);
LOGGER.info("sendRedirect cookie size: "+response.getHeaders(HttpHeaders.SET_COOKIE).size()+ " is commited:"+response.isCommitted());
response.sendRedirect(redirectUrl);
}
Looks like set_cookie is set in response.sendRedirect and is committed at the same time.

Spring security - Get SESSION cookie value in AuthenticationSuccessHandler

I know that spring security creates a cookies names SESSION on successful authentication. Is it possible to get hold of that cookie value in AuthenticationSuccessHandler.
I have a following implementation inside which I need that SESSION cookie value. I looked as response headers of HttpServletResponse, but they have XSRF-TOKEN set-cookie headers,
#Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
#Override
public void onAuthenticationSuccess(
HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException {
// GET SESSION, COOKIE VALUE HERE
}
}
Can you please help.
The SESSION cookie is created by Spring Session's DefaultCookieSerializer, which is called every time a new Session is created, and not necessarily after successful authentication.
Spring Session's SessionRepositoryFilter wraps the HttpServletRequest in such a way that whenever you obtain an HttpSession from the request at any point in your application, you're actually getting a Spring Session object. However, this cookie is written to the response after your handler has been called, as you can see in SessionRepositoryFilter:
try {
filterChain.doFilter(wrappedRequest, wrappedResponse);
}
finally {
wrappedRequest.commitSession(); //the SESSION cookie is created if necessary
}
So if the session has just been created for this request...
The cookie won't be available in the HttpServletRequest because the cookie hasn't been sent yet (and so the browser couldn't have sent it)
The cookie won't be HttpServletResponse as a "Set-Cookie" header because it will be written after your application has handled the request.
However, you could get the cookie value:
String cookieValue = request.getSession().getId();
Note: The above code will force Spring Session to create a session backed Redis/Jdbc/etc that will be used later to generate the SESSION cookie.
I got it using the getSession().getId() method from request. My example is using the Webflux implementation with Kotlin but apparently works similar in HttpServletRequest implementation see https://javaee.github.io/javaee-spec/javadocs/javax/servlet/http/HttpServletRequest.html#getSession--
class AuthenticationSuccessHandler : ServerAuthenticationSuccessHandler {
private val location = URI.create("https://redirect.page")
private val redirectStrategy: ServerRedirectStrategy = DefaultServerRedirectStrategy()
override fun onAuthenticationSuccess(webFilterExchange: WebFilterExchange?, authentication: Authentication?): Mono<Void> {
val exchange = webFilterExchange!!.exchange
return exchange.session.flatMap {
it.id // 87b5639c-7404-48a1-b9da-3ca47691a962
this.redirectStrategy.sendRedirect(exchange, location)
}
}
}

How to disable Session cookie in Apache HttpAsyncClientBuilder

I'm talking to a service that fails in getting the user authentication cookie if there is a JSESSIONID cookie in the request, and I can't modify this service.
It also returns this session cookie on each response, so my first request work (no other cookie than the user's one), but next requests will always fail.
My restTemplate configuration uses a custom request factory that extends Spring's HttpComponentsAsyncClientHttpRequestFactory with an AsyncClient from Apache's HttpAsyncClientBuilder.
Is there a way to configure that to always ignore the session cookie ?
Thanks in advance!
It would have been nice to find a solution impliying only configuration, but I couldn't so I ended up extending the BasicCookieStore:
public class DefaultCookieStore extends BasicCookieStore {
private static String SESSION_COOKIE_NAME = "JSESSIONID";
#Override
public void addCookie(Cookie cookie) {
if (!SESSION_COOKIE_NAME.equals(cookie.getName())) {
super.addCookie(cookie);
}
}
}
And adding it to my HttpAsyncClientBuilder and HttpClientBuilder with the method setDefaultCookieStore.
Probably not the best thing, but it works well.

Spring Security no controller for login page

New at Spring Security here. I was looking at this link 'https://docs.spring.io/spring-security/site/docs/current/guides/html5/form-javaconfig.html#grant-access-to-remaining-resources' and got really stumped at the section Configuring a login view controller`.
When I'm creating a typical form, I usually make the html page that, on click, calls a method in my custom #controller, which sends to my logic, etc.
However, in their example, they state that no controller is needed because everything is 'default'. Can someone explain exactly how their login form can 'connect' to their authentication object? It looks like somehow the credentials can magically pass into the Authentication object despite having no controller method.
Thanks!
There is no controller. When you use the formLogin() method, a UsernamePasswordAuthenticationFilter is registred in the security filter chain and does the authentication job. You can look at the source code here:
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
String password = obtainPassword(request);
if (username == null) {
username = "";
}
if (password == null) {
password = "";
}
username = username.trim();
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
Take again a look into https://docs.spring.io/spring-security/site/docs/current/guides/html5/form-javaconfig.html#configuring-a-login-view-controller. In the code snippet you can actually see, that an internal controller with the request mapping /login is registered. That is why you do not have to implement it on your own. All authentication transfer between view, internal controller and the authentication manager in the background is handled completely transparent to you.

logout specific session Id in spring security

in spring security:
i think with tow way logout called: when a session timeout occurred or a user logout itself...
anyway in these ways , destroyedSession called in HttpSessionEventPublisher and SessionRegistry remove SessionInformation from sessionIds list...
when i use below method for force logout specific user , this method just "expired" SessionInformation in SessionRegistry. now when i get all online user "getAllPrincipals()" from SessionRegistry, the user that session expired, is in the list!
#Override
public boolean forceLogOut(int userId){
for (Object username: sessionRegistry.getAllPrincipals()) {
User temp = (User) username;
if(temp.getId().equals(userId)){
for (SessionInformation session : sessionRegistry.getAllSessions(username, false)) {
session.expireNow();
}
}
}
return true;
}
how can i logout 'specific user' or 'sessionId' that session object remove from "Web Server" and "Session Registry" ?
i googling and found HttpSessionContext in Servlet API that can get HttpSession from specific sessionId. and then invalidate session. but i think this method is not completely useful!
(note. this class is deprecated!)
what is the best way? Whether I'm wrong?
Try like this:
#RequestMapping(value="/logout", method = RequestMethod.GET)
public String logoutPage (HttpServletRequest request, HttpServletResponse response){
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null){
//new SecurityContextLogoutHandler().logout(request, response, auth);
persistentTokenBasedRememberMeServices.logout(request, response, auth);
SecurityContextHolder.getContext().setAuthentication(null);
}
return "redirect:/login?logout";
}
To logout specific session Id check that link:
how to log a user out programmatically using spring security

Resources