How do I make logout possible using Google OAuth2? - spring-boot

I am trying to do log-out, and I am using Spring Boot 2.1.7.RELEASE, and Google OAuth2.
This is my class implementing WebSecurityConfigurerAdapter.
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.headers().frameOptions().disable()
.and()
.authorizeRequests()
.antMatchers("/", "/css/**", "/images/**", "/js/**", "/h2-console/**").permitAll()
.antMatchers("/**").hasRole(Role.USER.name())
.anyRequest().authenticated()
.and()
.logout().logoutUrl("/logout").invalidateHttpSession(true)
.clearAuthentication(true)
.logoutSuccessUrl("/").deleteCookies("JSESSIONID").permitAll()
.and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
.and()
.oauth2Login()
.userInfoEndpoint()
.userService(customOAuth2UserService);
}
And this is my #Controller code for Http-GET request, "/logout".
#GetMapping("/logout")
public String logout(HttpServletRequest request, HttpServletResponse response) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication != null) {
new SecurityContextLogoutHandler().logout(request, response, authentication);
}
SecurityContextHolder.getContext().setAuthentication(null);
return "index";
}
I tried almost everything I googled and saw on Stackoverflow, but I seem to fail to completely logout every time.

Related

Ajax call after session expired not redirecting to login page - spring boot

I want to redirect to the login page if while doing an ajax call the session is expired. I'm following the instructions on this link to do that, but every time I do an ajax call with the session expired it returns the login page as part of the response instead of redirecting to the login page, this never fails and response always goes to success piece of the ajax call with readyState: 4 and status: 200 and this is giving me a jquery error because I'm expecting a list and it's returning the html code for the login page.
My code is as below:
WebSecurityConfig.java
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(URL_LOGIN, "/css/**", "/img/**").permitAll()
.antMatchers("/admin/**").hasAnyAuthority(authorizedRolesAdmin)
.antMatchers("/**").hasAnyAuthority(ArrayUtils.addAll(authorizedRolesUser, authorizedRolesAdmin))
.and()
.formLogin()
.loginPage(URL_LOGIN)
.defaultSuccessUrl("/", true)
.failureUrl(URL_LOGIN_FAILED)
.permitAll()
.and()
.logout()
.logoutSuccessUrl(URL_LOGOUT)
.deleteCookies("JSESSIONID")
.invalidateHttpSession(true)
.permitAll()
.and()
.exceptionHandling()
.accessDeniedPage(URL_LOGIN_UNAUTHORIZED)
.authenticationEntryPoint(new AjaxAwareAuthenticationEntryPoint(URL_LOGIN))
.and()
.sessionManagement()
.maximumSessions(1)
.expiredUrl(URL_LOGOUT)
.and()
.invalidSessionUrl(URL_LOGOUT);
}
AjaxAwareAuthenticationEntryPoint.java
public class AjaxAwareAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
public AjaxAwareAuthenticationEntryPoint(String loginFormUrl) {
super(loginFormUrl);
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
String ajaxHeader = request.getHeader("X-Requested-With");
if ("XMLHttpRequest".equals(ajaxHeader)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Ajax Request Denied (Session Expired)");
} else {
super.commence(request, response, authException);
}
}
}
While debugging after session expired, I noticed that it doesn't even enter to: AjaxAwareAuthenticationEntryPoint java class commence method.
What I'm missing here?
I know, that it is probably too late for the answer, but anyway the code you've attached helped me to resolve the absolutely same issue. To be honest, I don't see any issues in your code that makes it not to enter to the AjaxAwareAuthenticationEntryPoint, only may be you have some other configs behind the scene. But anyway, let my answer be an example for everyone, who struggles with the same issue, cause for me it works fine, and returns 403 if session is expired. I am using Spring Boot v2.3.5 and this is my code:
AjaxAwareAuthenticationEntryPoint.java
public class AjaxAwareAuthenticationEntryPoint extends LoginUrlAuthenticationEntryPoint {
public AjaxAwareAuthenticationEntryPoint(String loginFormUrl) {
super(loginFormUrl);
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
String ajaxHeader = ((HttpServletRequest) request).getHeader("X-Requested-With");
if ("XMLHttpRequest".equals(ajaxHeader)) {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Ajax Request Denied (Session Expired)");
} else {
super.commence(request, response, authException);
}
}
}
WebSecurityConfig.java
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private AuthenticationFailureHandler authenticationFailureHandler;
#Autowired
private AccessDeniedHandler accessDeniedHandler;
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf()
.disable()
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.antMatchers("/registration*").permitAll()
.antMatchers("/admin/**").hasAuthority("ADMIN")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error=true")
.defaultSuccessUrl("/admin", true)
.failureHandler(authenticationFailureHandler)
.and()
.logout()
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login")
.and()
.exceptionHandling()
.accessDeniedHandler(accessDeniedHandler)
.and()
.exceptionHandling()
.authenticationEntryPoint(new AjaxAwareAuthenticationEntryPoint("/login"));
}
}
and inside my main.js where I have some jquery ajax calls I have this:
$(document).ajaxError(function myErrorHandler(event, xhr, ajaxOptions, thrownError) {
if (xhr.status == 403) {
window.location.href ="/login";
}
});

How to disable multiple logins for same user in spring security + spring boot

I have the below spring configuration :-
#Override
protected void configure(HttpSecurity http) throws Exception
{
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint((request, response,
authException) ->
response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS,
"/api/v2/customers/**").permitAll()
.antMatchers(HttpMethod.OPTIONS,
"/oauth/**").permitAll()
.antMatchers(HttpMethod.GET, "/saml/**").permitAll()
.antMatchers(HttpMethod.GET,
"/api/internal/v2/**").permitAll()
.antMatchers("/**").authenticated()
.antMatchers("/api/admin/**").authenticated()
.and()
.httpBasic()
.and()
.sessionManagement()
.maximumSessions(1)
.maxSessionsPreventsLogin(true)
.sessionRegistry(SR);
}
I was expecting sessionManagement().maximumSessions(1) to disable multiple login for the same user. It is working, but first user logout the application, so i am trying login in another browser but it showing This account is already using by someone.
Try this. you are not clearing/ closing the previous session properly.
#EnableWebMvcSecurity
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/expired").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.sessionManagement()
.maximumSessions(1)
.expiredUrl("/expired")
.maxSessionsPreventsLogin(true)
.sessionRegistry(sessionRegistry());
}
#Bean
public SessionRegistry sessionRegistry() {
SessionRegistry sessionRegistry = new SessionRegistryImpl();
return sessionRegistry;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
// Register HttpSessionEventPublisher
#Bean
public static ServletListenerRegistrationBean httpSessionEventPublisher() {
return new ServletListenerRegistrationBean(new HttpSessionEventPublisher());
}
}
Missing is .expiredUrl("/expired").maxSessionsPreventsLogin(true)
.sessionRegistry(sessionRegistry());

Spring security only allowed oauth login

In my project, i just want to allow oauth login. my spring security config as follow:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/login.html", "/oauth/**", "/sign**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin().disable()
.httpBasic().disable()[enter image description here][1]
.exceptionHandling().accessDeniedPage("/login.html")
.and()
.apply(new SpringSocialConfigurer());
}
The problem is the access denied page not working. I want to get login.html content as follow:
login.html
in fact i got 403 page as follow:
403
How to solve this problem?
I solve this problem, the code as follow:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/login.html", "/oauth/**", "/sign**").permitAll()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.defaultAuthenticationEntryPointFor(new HttpForbiddenEntryPoint(), AnyRequestMatcher.INSTANCE)
.and()
.logout()
.logoutUrl("/logout.html")
.clearAuthentication(true)
.logoutSuccessUrl("/login.html")
.and()
.apply(new SpringSocialConfigurer());
}
The entry point:
public class HttpForbiddenEntryPoint implements AuthenticationEntryPoint {
private String redirect_url = "/login.html";
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendRedirect(redirect_url);
}
public String getRedirect_url() {
return redirect_url;
}
public void setRedirect_url(String redirect_url) {
this.redirect_url = redirect_url;
}
}

Authentication failure redirect with request params not working

I am trying to configure my own success and authentication failure handlers. On authentication failure I want to redirect back to my login page with a request parameter, the presence of this parameter will output the error message on my login page. However although on error I am getting redirected back to my login page, the request parameter is always null.
Code below:
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login.html").permitAll()
.usernameParameter("username")
.passwordParameter("password")
.loginProcessingUrl("/login")
.successHandler(successHandler())
.failureHandler(handleAuthenticationFailure());
}
#Autowired
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//database checks
}
};
}
/**
* Authentication success handler defines action when successfully authenticated
* #return
*/
#Bean
public AuthenticationSuccessHandler successHandler(){
return new AuthenticationSuccessHandler() {
#Override
public void onAuthenticationSuccess(HttpServletRequest httpRequest, HttpServletResponse httpResponse, Authentication authentication)
throws IOException, ServletException {
// custom auth success here
httpResponse.setStatus(HttpServletResponse.SC_OK);
SavedRequest savedRequest = (SavedRequest) httpRequest.getSession().getAttribute("SPRING_SECURITY_SAVED_REQUEST");
httpResponse.sendRedirect(savedRequest.getRedirectUrl());
}
};
}
#Bean
public AuthenticationFailureHandler handleAuthenticationFailure() {
return new SimpleUrlAuthenticationFailureHandler() {
#Override
public void onAuthenticationFailure(HttpServletRequest httpRequest, HttpServletResponse httpResponse,
AuthenticationException authenticationException) throws IOException, ServletException {
// custom failure code here
setDefaultFailureUrl("/login.html?error=fail");
super.onAuthenticationFailure(httpRequest, httpResponse, authenticationException);
}
};
}
Try with this:
#Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
// .......
response.sendRedirect("/login.html?error=fail");
}
Update:
It's really important that the "/login.html?error=fail" is added to an authorizeRequests() section otherwise the controller won't pick up the error parameter.
Replace .antMatchers("/login").permitAll() with .antMatchers("/login**").permitAll()
Also had problem with params (in my case when login was failed and some request params was added to url it redirected to login page without params).
This solved my problem
.antMatchers("/login**").permitAll()
I'm new in springBoot, if you are using spring boot 2.1.4.RELEASE, try this configuration:
http.csrf().disable()
.authorizeRequests()
// URLs matching for access rights
.antMatchers("/").permitAll()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and()
// form login
.formLogin()
.loginPage("/login")
.failureUrl("/login?error=true")
.successHandler(sucessHandler)
.usernameParameter("email")
.passwordParameter("password")
.and()
// logout
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/").and()
.exceptionHandling()
.accessDeniedPage("/access-denied");
To use the above-defined Spring Security configuration, we need to attach it to the web application. In this case, we don’t need any web.xml:
public class SpringApplicationInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
protected Class<?>[] getRootConfigClasses() {
return new Class[] {SecSecurityConfig.class};
}}
this means you create the following class which will be instanciated autoatically
SecSecurityConfig.class : is the class where you do all http.csrf().disable().authorizeRequests()... configurations
source : https://www.baeldung.com/spring-security-login
hope it helps :)

AuthenticationSuccessHandler in Spring MVC Java based configuration

I have three roles, and i want to redirect user to different pages after login according to their roles. I know this can be done by AuthenticationSuccessHandler, but I am having trouble in declaring it in Java based configuration.
So far I have done this.
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/resources/**", "/login").permitAll()
.antMatchers("/admin/**").hasRole("USER")
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/")
.successHandler(successHandler) //----- to handle user role
.failureUrl("/loginfailed")
.permitAll()
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.deleteCookies("JSESSIONID")
.invalidateHttpSession( true )
.and();
}
My question is where to declare successHandler and how to autowire it in this class, or how to declare successHandler method in this class and use it.
Try this: Moving Spring Security To Java Config, where does authentication-success-handler-ref go?
Code from the post above:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("")
.defaultSuccessUrl("/")
.failureUrl("")
.successHandler(//declare your bean here)
.and()
.logout()
.permitAll()
.and()
}
Then in the authentication handler you can apply the required logic
public class MYSuccessHandler implements AuthenticationSuccessHandler {
private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
#Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException {
handle(request, response, authentication);
}
protected void handle(HttpServletRequest request,
// logic
redirectStrategy.sendRedirect(request, response, targetUrl);
}
/** Builds the target URL according to the logic defined in the main class Javadoc. */
protected String determineTargetUrl(Authentication authentication) {
}
}
Tutorial listed here http://www.baeldung.com/spring_redirect_after_login

Resources