|
15 | 15 | */
|
16 | 16 | package org.springframework.security.config.annotation.web.configurers.oauth2.client;
|
17 | 17 |
|
| 18 | +import java.time.Instant; |
| 19 | +import java.util.ArrayList; |
| 20 | +import java.util.Arrays; |
| 21 | +import java.util.Collections; |
| 22 | +import java.util.HashMap; |
| 23 | +import java.util.List; |
| 24 | +import java.util.Map; |
| 25 | + |
18 | 26 | import org.apache.http.HttpHeaders;
|
19 | 27 | import org.junit.After;
|
20 | 28 | import org.junit.Before;
|
| 29 | +import org.junit.Rule; |
21 | 30 | import org.junit.Test;
|
| 31 | + |
22 | 32 | import org.springframework.beans.factory.NoUniqueBeanDefinitionException;
|
23 | 33 | import org.springframework.beans.factory.annotation.Autowired;
|
24 | 34 | import org.springframework.context.ApplicationListener;
|
|
35 | 45 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
36 | 46 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
37 | 47 | import org.springframework.security.config.oauth2.client.CommonOAuth2Provider;
|
| 48 | +import org.springframework.security.config.test.SpringTestRule; |
38 | 49 | import org.springframework.security.core.Authentication;
|
39 | 50 | import org.springframework.security.core.GrantedAuthority;
|
| 51 | +import org.springframework.security.core.authority.AuthorityUtils; |
40 | 52 | import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
41 | 53 | import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
|
42 | 54 | import org.springframework.security.core.context.SecurityContextImpl;
|
| 55 | +import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken; |
43 | 56 | import org.springframework.security.oauth2.client.endpoint.OAuth2AccessTokenResponseClient;
|
44 | 57 | import org.springframework.security.oauth2.client.endpoint.OAuth2AuthorizationCodeGrantRequest;
|
| 58 | +import org.springframework.security.oauth2.client.web.oidc.logout.OidcClientInitiatedLogoutSuccessHandler; |
45 | 59 | import org.springframework.security.oauth2.client.oidc.userinfo.OidcUserRequest;
|
46 | 60 | import org.springframework.security.oauth2.client.registration.ClientRegistration;
|
47 | 61 | import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository;
|
48 | 62 | import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository;
|
| 63 | +import org.springframework.security.oauth2.client.registration.TestClientRegistrations; |
49 | 64 | import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest;
|
50 | 65 | import org.springframework.security.oauth2.client.userinfo.OAuth2UserService;
|
51 | 66 | import org.springframework.security.oauth2.client.web.AuthorizationRequestRepository;
|
|
61 | 76 | import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
|
62 | 77 | import org.springframework.security.oauth2.core.oidc.user.OidcUser;
|
63 | 78 | import org.springframework.security.oauth2.core.oidc.user.OidcUserAuthority;
|
| 79 | +import org.springframework.security.oauth2.core.oidc.user.TestOidcUsers; |
64 | 80 | import org.springframework.security.oauth2.core.user.DefaultOAuth2User;
|
65 | 81 | import org.springframework.security.oauth2.core.user.OAuth2User;
|
66 | 82 | import org.springframework.security.oauth2.core.user.OAuth2UserAuthority;
|
|
71 | 87 | import org.springframework.security.web.context.HttpRequestResponseHolder;
|
72 | 88 | import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
73 | 89 | import org.springframework.security.web.context.SecurityContextRepository;
|
| 90 | +import org.springframework.test.web.servlet.MockMvc; |
74 | 91 | import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
75 | 92 |
|
76 |
| -import java.time.Instant; |
77 |
| -import java.util.ArrayList; |
78 |
| -import java.util.Arrays; |
79 |
| -import java.util.Collections; |
80 |
| -import java.util.HashMap; |
81 |
| -import java.util.List; |
82 |
| -import java.util.Map; |
83 |
| - |
84 | 93 | import static org.assertj.core.api.Assertions.assertThat;
|
85 | 94 | import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
86 | 95 | import static org.mockito.ArgumentMatchers.any;
|
87 | 96 | import static org.mockito.Mockito.mock;
|
88 | 97 | import static org.mockito.Mockito.when;
|
| 98 | +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication; |
| 99 | +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; |
| 100 | +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; |
| 101 | +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; |
89 | 102 |
|
90 | 103 | /**
|
91 | 104 | * Tests for {@link OAuth2LoginConfigurer}.
|
@@ -115,6 +128,12 @@ public class OAuth2LoginConfigurerTests {
|
115 | 128 | @Autowired
|
116 | 129 | SecurityContextRepository securityContextRepository;
|
117 | 130 |
|
| 131 | + @Rule |
| 132 | + public final SpringTestRule spring = new SpringTestRule(); |
| 133 | + |
| 134 | + @Autowired(required = false) |
| 135 | + MockMvc mvc; |
| 136 | + |
118 | 137 | private MockHttpServletRequest request;
|
119 | 138 | private MockHttpServletResponse response;
|
120 | 139 | private MockFilterChain filterChain;
|
@@ -455,6 +474,21 @@ public void oidcLoginCustomWithNoUniqueJwtDecoderFactory() {
|
455 | 474 | "available: expected single matching bean but found 2: jwtDecoderFactory1,jwtDecoderFactory2");
|
456 | 475 | }
|
457 | 476 |
|
| 477 | + @Test |
| 478 | + public void logoutWhenUsingOidcLogoutHandlerThenRedirects() throws Exception { |
| 479 | + this.spring.register(OAuth2LoginConfigWithOidcLogoutSuccessHandler.class).autowire(); |
| 480 | + |
| 481 | + OAuth2AuthenticationToken token = new OAuth2AuthenticationToken( |
| 482 | + TestOidcUsers.create(), |
| 483 | + AuthorityUtils.NO_AUTHORITIES, |
| 484 | + "registration-id"); |
| 485 | + |
| 486 | + this.mvc.perform(post("/logout") |
| 487 | + .with(authentication(token)) |
| 488 | + .with(csrf())) |
| 489 | + .andExpect(redirectedUrl("http://logout?id_token_hint=id-token")); |
| 490 | + } |
| 491 | + |
458 | 492 | private void loadConfig(Class<?>... configs) {
|
459 | 493 | AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
|
460 | 494 | applicationContext.register(configs);
|
@@ -591,6 +625,31 @@ protected void configure(HttpSecurity http) throws Exception {
|
591 | 625 | }
|
592 | 626 | }
|
593 | 627 |
|
| 628 | + @EnableWebSecurity |
| 629 | + static class OAuth2LoginConfigWithOidcLogoutSuccessHandler extends CommonWebSecurityConfigurerAdapter { |
| 630 | + @Override |
| 631 | + protected void configure(HttpSecurity http) throws Exception { |
| 632 | + http |
| 633 | + .logout() |
| 634 | + .logoutSuccessHandler(oidcLogoutSuccessHandler()); |
| 635 | + super.configure(http); |
| 636 | + } |
| 637 | + |
| 638 | + @Bean |
| 639 | + OidcClientInitiatedLogoutSuccessHandler oidcLogoutSuccessHandler() { |
| 640 | + return new OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository()); |
| 641 | + } |
| 642 | + |
| 643 | + @Bean |
| 644 | + ClientRegistrationRepository clientRegistrationRepository() { |
| 645 | + Map<String, Object> providerMetadata = |
| 646 | + Collections.singletonMap("end_session_endpoint", "http://logout"); |
| 647 | + return new InMemoryClientRegistrationRepository( |
| 648 | + TestClientRegistrations.clientRegistration() |
| 649 | + .providerConfigurationMetadata(providerMetadata).build()); |
| 650 | + } |
| 651 | + } |
| 652 | + |
594 | 653 | private static abstract class CommonWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
|
595 | 654 | @Override
|
596 | 655 | protected void configure(HttpSecurity http) throws Exception {
|
|
0 commit comments