|
@@ -15,10 +15,20 @@
|
|
*/
|
|
*/
|
|
package org.springframework.security.config.annotation.web.configurers.oauth2.client;
|
|
package org.springframework.security.config.annotation.web.configurers.oauth2.client;
|
|
|
|
|
|
|
|
+import java.time.Instant;
|
|
|
|
+import java.util.ArrayList;
|
|
|
|
+import java.util.Arrays;
|
|
|
|
+import java.util.Collections;
|
|
|
|
+import java.util.HashMap;
|
|
|
|
+import java.util.List;
|
|
|
|
+import java.util.Map;
|
|
|
|
+
|
|
import org.apache.http.HttpHeaders;
|
|
import org.apache.http.HttpHeaders;
|
|
import org.junit.After;
|
|
import org.junit.After;
|
|
import org.junit.Before;
|
|
import org.junit.Before;
|
|
|
|
+import org.junit.Rule;
|
|
import org.junit.Test;
|
|
import org.junit.Test;
|
|
|
|
+
|
|
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
|
import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.context.ApplicationListener;
|
|
import org.springframework.context.ApplicationListener;
|
|
@@ -35,17 +45,22 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
|
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider;
|
|
import org.springframework.security.config.oauth2.client.CommonOAuth2Provider;
|
|
|
|
+import org.springframework.security.config.test.SpringTestRule;
|
|
import org.springframework.security.core.Authentication;
|
|
import org.springframework.security.core.Authentication;
|
|
import org.springframework.security.core.GrantedAuthority;
|
|
import org.springframework.security.core.GrantedAuthority;
|
|
|
|
+import org.springframework.security.core.authority.AuthorityUtils;
|
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
|
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
|
import org.springframework.security.core.context.SecurityContextImpl;
|
|
import org.springframework.security.core.context.SecurityContextImpl;
|
|
|
|
+import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
|
|
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
|
import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
|
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
|
import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
|
|
|
+import org.springframework.security.oauth2.client.web.oidc.logout.OidcClientInitiatedLogoutSuccessHandler;
|
|
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
|
|
import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
|
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
|
import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
|
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
|
import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
|
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
|
import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
|
|
|
+import org.springframework.security.oauth2.client.registration.TestClientRegistrations;
|
|
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
|
import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
|
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
|
|
import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
|
|
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
|
|
import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
|
|
@@ -61,6 +76,7 @@ import org.springframework.security.oauth2.core.oidc.endpoint.OidcParameterNames
|
|
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
|
|
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
|
|
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
|
import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
|
import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
|
|
import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
|
|
|
|
+import org.springframework.security.oauth2.core.oidc.user.TestOidcUsers;
|
|
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
|
|
import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
|
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
|
import org.springframework.security.oauth2.core.user.OAuth2User;
|
|
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
|
|
import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
|
|
@@ -71,21 +87,18 @@ import org.springframework.security.web.FilterChainProxy;
|
|
import org.springframework.security.web.context.HttpRequestResponseHolder;
|
|
import org.springframework.security.web.context.HttpRequestResponseHolder;
|
|
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
|
import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
|
import org.springframework.security.web.context.SecurityContextRepository;
|
|
import org.springframework.security.web.context.SecurityContextRepository;
|
|
|
|
+import org.springframework.test.web.servlet.MockMvc;
|
|
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
|
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
|
|
|
|
|
-import java.time.Instant;
|
|
|
|
-import java.util.ArrayList;
|
|
|
|
-import java.util.Arrays;
|
|
|
|
-import java.util.Collections;
|
|
|
|
-import java.util.HashMap;
|
|
|
|
-import java.util.List;
|
|
|
|
-import java.util.Map;
|
|
|
|
-
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.assertj.core.api.Assertions.assertThat;
|
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.Mockito.mock;
|
|
import static org.mockito.Mockito.mock;
|
|
import static org.mockito.Mockito.when;
|
|
import static org.mockito.Mockito.when;
|
|
|
|
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
|
|
|
+import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
|
|
|
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
|
|
|
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
|
|
|
|
|
|
/**
|
|
/**
|
|
* Tests for {@link OAuth2LoginConfigurer}.
|
|
* Tests for {@link OAuth2LoginConfigurer}.
|
|
@@ -115,6 +128,12 @@ public class OAuth2LoginConfigurerTests {
|
|
@Autowired
|
|
@Autowired
|
|
SecurityContextRepository securityContextRepository;
|
|
SecurityContextRepository securityContextRepository;
|
|
|
|
|
|
|
|
+ @Rule
|
|
|
|
+ public final SpringTestRule spring = new SpringTestRule();
|
|
|
|
+
|
|
|
|
+ @Autowired(required = false)
|
|
|
|
+ MockMvc mvc;
|
|
|
|
+
|
|
private MockHttpServletRequest request;
|
|
private MockHttpServletRequest request;
|
|
private MockHttpServletResponse response;
|
|
private MockHttpServletResponse response;
|
|
private MockFilterChain filterChain;
|
|
private MockFilterChain filterChain;
|
|
@@ -455,6 +474,21 @@ public class OAuth2LoginConfigurerTests {
|
|
"available: expected single matching bean but found 2: jwtDecoderFactory1,jwtDecoderFactory2");
|
|
"available: expected single matching bean but found 2: jwtDecoderFactory1,jwtDecoderFactory2");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @Test
|
|
|
|
+ public void logoutWhenUsingOidcLogoutHandlerThenRedirects() throws Exception {
|
|
|
|
+ this.spring.register(OAuth2LoginConfigWithOidcLogoutSuccessHandler.class).autowire();
|
|
|
|
+
|
|
|
|
+ OAuth2AuthenticationToken token = new OAuth2AuthenticationToken(
|
|
|
|
+ TestOidcUsers.create(),
|
|
|
|
+ AuthorityUtils.NO_AUTHORITIES,
|
|
|
|
+ "registration-id");
|
|
|
|
+
|
|
|
|
+ this.mvc.perform(post("/logout")
|
|
|
|
+ .with(authentication(token))
|
|
|
|
+ .with(csrf()))
|
|
|
|
+ .andExpect(redirectedUrl("http://logout?id_token_hint=id-token"));
|
|
|
|
+ }
|
|
|
|
+
|
|
private void loadConfig(Class<?>... configs) {
|
|
private void loadConfig(Class<?>... configs) {
|
|
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
|
|
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
|
|
applicationContext.register(configs);
|
|
applicationContext.register(configs);
|
|
@@ -591,6 +625,31 @@ public class OAuth2LoginConfigurerTests {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ @EnableWebSecurity
|
|
|
|
+ static class OAuth2LoginConfigWithOidcLogoutSuccessHandler extends CommonWebSecurityConfigurerAdapter {
|
|
|
|
+ @Override
|
|
|
|
+ protected void configure(HttpSecurity http) throws Exception {
|
|
|
|
+ http
|
|
|
|
+ .logout()
|
|
|
|
+ .logoutSuccessHandler(oidcLogoutSuccessHandler());
|
|
|
|
+ super.configure(http);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Bean
|
|
|
|
+ OidcClientInitiatedLogoutSuccessHandler oidcLogoutSuccessHandler() {
|
|
|
|
+ return new OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository());
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ @Bean
|
|
|
|
+ ClientRegistrationRepository clientRegistrationRepository() {
|
|
|
|
+ Map<String, Object> providerMetadata =
|
|
|
|
+ Collections.singletonMap("end_session_endpoint", "http://logout");
|
|
|
|
+ return new InMemoryClientRegistrationRepository(
|
|
|
|
+ TestClientRegistrations.clientRegistration()
|
|
|
|
+ .providerConfigurationMetadata(providerMetadata).build());
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
private static abstract class CommonWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
|
private static abstract class CommonWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
|
@Override
|
|
@Override
|
|
protected void configure(HttpSecurity http) throws Exception {
|
|
protected void configure(HttpSecurity http) throws Exception {
|