Spring Security, Logout: Pass parameter from /logout to /login

gene b. :

I'm using default Spring Security to handle logout/login. I have a Controller method that handles /login.

When I log out, I see that Spring Security redirects me to app/login?logout. The existence of this Spring-created parameter (and also sometimes app/login?error) allows me to write my Login handler as:

@GetMapping("/participant/login")
public ModelAndView  loginPage(HttpServletRequest request, HttpServletResponse response, 
        @RequestParam(value = "error", required = false) String error,
        @RequestParam(value = "logout", required = false) String logout) {
    log.info("Entering participant login page");
    ModelAndView mav = new ModelAndView(LOGIN_JSP);
    if (null != error) {
        // We're coming to the login page after an Error
        mav.addObject("info", "My generic error message");
    } else if(null != logout){
        // We're coming to the login page after a Logout
        mav.addObject("info", "My generic logout message");
    }
    // ...Otherwise, normal Login page, no extra information

Now the problem is that when I log out, I need to pass a custom parameter to /logout with a transfer to /login. The goal is I need to receive a param in /login that I can examine just like the system-created error and logout.

Suppose this custom param is exitMsg.

From my app I issue this Spring Security Logout URL (logout is automatic, so I don't have a specific handler for it):

myapp.com/app/logout?exitMsg=MyMessage

Right away, the Login handler loses this param and I don't have it.

I considered writing my own /logout handler, where I manually log out (invalidate the session), and then redirect to Login myself with this param. This is the suggestion here. But if I do that, I lose the ability to get Spring's automatic ?logout and ?error Request Params. In the automatic scenario I was getting them, and now I'm not. I'm only getting the custom parameter I specify myself. I need to keep ?logout and ?error and also test for my own new param.

Any thoughts highly appreciated.

Spring Security Config:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.antMatcher("/participant/**").authorizeRequests()
                .antMatchers("/participant/id/**").permitAll()
                .antMatchers("/participant/faq").permitAll()
                .antMatchers("/participant/forgetPassword").permitAll()
                .antMatchers("/participant/securityQuestions").permitAll()
                .antMatchers("/participant/securityCheck").permitAll()
                .antMatchers("/participant/resetPassword").permitAll()
                .antMatchers("/participant/**").authenticated()
            .and()
                .formLogin().loginPage("/participant/login").permitAll()
                .failureUrl("/participant/login?error").permitAll()
                .defaultSuccessUrl("/participant/home")
                .usernameParameter("username").passwordParameter("password")
            .and()
                .logout().logoutUrl("/participant/logout")
                .logoutSuccessUrl("/participant/login?logout").permitAll()
            .and()
                .csrf().disable();
    }
PraveenKumar Lalasangi :

You need logoutSuccessHandler instead of .logoutSuccessUrl("/login?logout")
Configure logoutSuccessHandler as given below

@Override
protected void configure(final HttpSecurity http) throws Exception
{
    http
        .authorizeRequests()
            .antMatchers("/resources/**", "/", "/login", "/api/**")
                .permitAll()
            .antMatchers("/app/admin/*")
                .hasRole("ADMIN")
            .antMatchers("/app/user/*")
                .hasAnyRole("ADMIN", "USER")
        .and().exceptionHandling().accessDeniedPage("/403")
        .and().formLogin()
            .loginPage("/login").usernameParameter("userName")
            .passwordParameter("password")
            .defaultSuccessUrl("/app/user/dashboard")
            .failureUrl("/login?error=true")
        .and().logout()
            .logoutSuccessHandler(new CustomLogoutSuccessHandler())
            .invalidateHttpSession(true)
        .and().csrf().disable();

    http.sessionManagement().maximumSessions(1).expiredUrl("/login?expired=true");
}

I considered writing my own /logout handler

In fact that is not logout handler but it is logout initiator.
Use CustomLogoutSuccessHandler, where you can get request param's and you can set it again, as given below.

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;

public class CustomLogoutSuccessHandler extends SimpleUrlLogoutSuccessHandler
{

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException
    {
        Cookie cookie = new Cookie("JSESSIONID", null);
        cookie.setPath(request.getContextPath());
        cookie.setMaxAge(0);
        response.addCookie(cookie);

        if(request.getParameter("expired") != null)
        {
            response.sendRedirect(request.getContextPath()+"/login?expired=true");
        }
        else
        {
            response.sendRedirect(request.getContextPath() + "/login?logout=true");
        }
    }
}

From my app I issue this Spring Security Logout URL (logout is automatic, so I don't have a specific handler for it)

There is no automatic logout feature in servlet/spring security. Only what we can achieve is
1. Automate client to send logout request
2. In server we can set session's maxInactiveInterval, so that session can be invalidated by deleting cookie/setting age of cookie to past date. Once session is invalidated for the next request one of filter in spring security filter chain redirects it to /login page with param expired./login?expired
If you initiates logout spring security will delete the cookie/invalidate the session and redirects to /login page with param logout./login?logout
There are two types of configuration of achieving logout in spring security.

.and().logout()
.invalidateHttpSession(true)
//or
.deleteCookies("JSESSIONID")

EDIT: After Seeing OP's Answer. Missing info adding here. OP and i had a long chat in temporary answer(That chat and answer has been deleted) where we found the LOGIN-WALL.

"login-wall" is a outcome of bad* configuration where you will define a custom login page and it is configured as resource that is allowed to access after authentication. (access=isAuthenticated) but from CustomLogoutSuccessHandler if we redirect to login page after invalidating session spring security blocks login page access(401-Un Authorized) since that page is allowed only for authenticated-user. After blocking spring security takes care of redirects to the page configured in configuration. `.loginPage("/someloginpage"). What it forces to think is logout happening correctly, redirecting to login page correctly but params i sent in query string are not coming to loginpage. Nothing wrong if i call this as puzzle which is very hard to guess.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=322890&siteId=1