|
|
|
@ -16,8 +16,13 @@ |
|
|
|
|
|
|
|
|
|
|
|
package org.springframework.security.config.annotation.web.configurers.openid; |
|
|
|
package org.springframework.security.config.annotation.web.configurers.openid; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import okhttp3.mockwebserver.MockResponse; |
|
|
|
|
|
|
|
import okhttp3.mockwebserver.MockWebServer; |
|
|
|
import org.junit.Rule; |
|
|
|
import org.junit.Rule; |
|
|
|
import org.junit.Test; |
|
|
|
import org.junit.Test; |
|
|
|
|
|
|
|
import org.openid4java.consumer.ConsumerManager; |
|
|
|
|
|
|
|
import org.openid4java.discovery.DiscoveryInformation; |
|
|
|
|
|
|
|
import org.openid4java.message.AuthRequest; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
import org.springframework.beans.factory.annotation.Autowired; |
|
|
|
import org.springframework.context.annotation.Bean; |
|
|
|
import org.springframework.context.annotation.Bean; |
|
|
|
import org.springframework.security.config.annotation.ObjectPostProcessor; |
|
|
|
import org.springframework.security.config.annotation.ObjectPostProcessor; |
|
|
|
@ -26,13 +31,23 @@ 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.test.SpringTestRule; |
|
|
|
import org.springframework.security.config.test.SpringTestRule; |
|
|
|
|
|
|
|
import org.springframework.security.openid.OpenIDAttribute; |
|
|
|
import org.springframework.security.openid.OpenIDAuthenticationFilter; |
|
|
|
import org.springframework.security.openid.OpenIDAuthenticationFilter; |
|
|
|
import org.springframework.security.openid.OpenIDAuthenticationProvider; |
|
|
|
import org.springframework.security.openid.OpenIDAuthenticationProvider; |
|
|
|
import org.springframework.test.web.servlet.MockMvc; |
|
|
|
import org.springframework.test.web.servlet.MockMvc; |
|
|
|
|
|
|
|
import org.springframework.test.web.servlet.MvcResult; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import static org.assertj.core.api.Assertions.assertThat; |
|
|
|
import static org.mockito.ArgumentMatchers.any; |
|
|
|
import static org.mockito.ArgumentMatchers.any; |
|
|
|
|
|
|
|
import static org.mockito.ArgumentMatchers.anyBoolean; |
|
|
|
|
|
|
|
import static org.mockito.Mockito.mock; |
|
|
|
import static org.mockito.Mockito.spy; |
|
|
|
import static org.mockito.Mockito.spy; |
|
|
|
import static org.mockito.Mockito.verify; |
|
|
|
import static org.mockito.Mockito.verify; |
|
|
|
|
|
|
|
import static org.mockito.Mockito.when; |
|
|
|
|
|
|
|
import static org.openid4java.discovery.yadis.YadisResolver.YADIS_XRDS_LOCATION; |
|
|
|
|
|
|
|
import static org.springframework.security.config.Customizer.withDefaults; |
|
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; |
|
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; |
|
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; |
|
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; |
|
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; |
|
|
|
@ -128,4 +143,167 @@ public class OpenIDLoginConfigurerTests { |
|
|
|
// @formatter:on
|
|
|
|
// @formatter:on
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void requestWhenOpenIdLoginPageInLambdaThenRedirectsToLoginPAge() throws Exception { |
|
|
|
|
|
|
|
this.spring.register(OpenIdLoginPageInLambdaConfig.class).autowire(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
this.mvc.perform(get("/")) |
|
|
|
|
|
|
|
.andExpect(status().isFound()) |
|
|
|
|
|
|
|
.andExpect(redirectedUrl("http://localhost/login/custom")); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@EnableWebSecurity |
|
|
|
|
|
|
|
static class OpenIdLoginPageInLambdaConfig extends WebSecurityConfigurerAdapter { |
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
protected void configure(HttpSecurity http) throws Exception { |
|
|
|
|
|
|
|
// @formatter:off
|
|
|
|
|
|
|
|
http |
|
|
|
|
|
|
|
.authorizeRequests(authorizeRequests -> |
|
|
|
|
|
|
|
authorizeRequests |
|
|
|
|
|
|
|
.anyRequest().authenticated() |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.openidLogin(openIdLogin -> |
|
|
|
|
|
|
|
openIdLogin |
|
|
|
|
|
|
|
.loginPage("/login/custom") |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
// @formatter:on
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void requestWhenAttributeExchangeConfiguredThenFetchAttributesMatchAttributeList() throws Exception { |
|
|
|
|
|
|
|
OpenIdAttributesInLambdaConfig.CONSUMER_MANAGER = mock(ConsumerManager.class); |
|
|
|
|
|
|
|
AuthRequest mockAuthRequest = mock(AuthRequest.class); |
|
|
|
|
|
|
|
DiscoveryInformation mockDiscoveryInformation = mock(DiscoveryInformation.class); |
|
|
|
|
|
|
|
when(mockAuthRequest.getDestinationUrl(anyBoolean())).thenReturn("mockUrl"); |
|
|
|
|
|
|
|
when(OpenIdAttributesInLambdaConfig.CONSUMER_MANAGER.associate(any())) |
|
|
|
|
|
|
|
.thenReturn(mockDiscoveryInformation); |
|
|
|
|
|
|
|
when(OpenIdAttributesInLambdaConfig.CONSUMER_MANAGER.authenticate(any(DiscoveryInformation.class), any(), any())) |
|
|
|
|
|
|
|
.thenReturn(mockAuthRequest); |
|
|
|
|
|
|
|
this.spring.register(OpenIdAttributesInLambdaConfig.class).autowire(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try ( MockWebServer server = new MockWebServer() ) { |
|
|
|
|
|
|
|
String endpoint = server.url("/").toString(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
server.enqueue(new MockResponse() |
|
|
|
|
|
|
|
.addHeader(YADIS_XRDS_LOCATION, endpoint)); |
|
|
|
|
|
|
|
server.enqueue(new MockResponse() |
|
|
|
|
|
|
|
.setBody(String.format("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", endpoint))); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MvcResult mvcResult = this.mvc.perform(get("/login/openid") |
|
|
|
|
|
|
|
.param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint)) |
|
|
|
|
|
|
|
.andExpect(status().isFound()) |
|
|
|
|
|
|
|
.andReturn(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Object attributeObject = mvcResult.getRequest().getSession().getAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST"); |
|
|
|
|
|
|
|
assertThat(attributeObject).isInstanceOf(List.class); |
|
|
|
|
|
|
|
List<OpenIDAttribute> attributeList = (List<OpenIDAttribute>) attributeObject; |
|
|
|
|
|
|
|
assertThat(attributeList.stream().anyMatch(attribute -> |
|
|
|
|
|
|
|
"nickname".equals(attribute.getName()) |
|
|
|
|
|
|
|
&& "https://schema.openid.net/namePerson/friendly".equals(attribute.getType()))) |
|
|
|
|
|
|
|
.isTrue(); |
|
|
|
|
|
|
|
assertThat(attributeList.stream().anyMatch(attribute -> |
|
|
|
|
|
|
|
"email".equals(attribute.getName()) |
|
|
|
|
|
|
|
&& "https://schema.openid.net/contact/email".equals(attribute.getType()) |
|
|
|
|
|
|
|
&& attribute.isRequired() |
|
|
|
|
|
|
|
&& attribute.getCount() == 2)) |
|
|
|
|
|
|
|
.isTrue(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@EnableWebSecurity |
|
|
|
|
|
|
|
static class OpenIdAttributesInLambdaConfig extends WebSecurityConfigurerAdapter { |
|
|
|
|
|
|
|
static ConsumerManager CONSUMER_MANAGER; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
protected void configure(HttpSecurity http) throws Exception { |
|
|
|
|
|
|
|
// @formatter:off
|
|
|
|
|
|
|
|
http |
|
|
|
|
|
|
|
.authorizeRequests(authorizeRequests -> |
|
|
|
|
|
|
|
authorizeRequests |
|
|
|
|
|
|
|
.anyRequest().permitAll() |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.openidLogin(openIdLogin -> |
|
|
|
|
|
|
|
openIdLogin |
|
|
|
|
|
|
|
.consumerManager(CONSUMER_MANAGER) |
|
|
|
|
|
|
|
.attributeExchange(attributeExchange -> |
|
|
|
|
|
|
|
attributeExchange |
|
|
|
|
|
|
|
.identifierPattern(".*") |
|
|
|
|
|
|
|
.attribute(nicknameAttribute -> |
|
|
|
|
|
|
|
nicknameAttribute |
|
|
|
|
|
|
|
.name("nickname") |
|
|
|
|
|
|
|
.type("https://schema.openid.net/namePerson/friendly") |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.attribute(emailAttribute -> |
|
|
|
|
|
|
|
emailAttribute |
|
|
|
|
|
|
|
.name("email") |
|
|
|
|
|
|
|
.type("https://schema.openid.net/contact/email") |
|
|
|
|
|
|
|
.required(true) |
|
|
|
|
|
|
|
.count(2) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
// @formatter:on
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Test |
|
|
|
|
|
|
|
public void requestWhenAttributeNameNotSpecifiedThenAttributeNameDefaulted() |
|
|
|
|
|
|
|
throws Exception { |
|
|
|
|
|
|
|
OpenIdAttributesNullNameConfig.CONSUMER_MANAGER = mock(ConsumerManager.class); |
|
|
|
|
|
|
|
AuthRequest mockAuthRequest = mock(AuthRequest.class); |
|
|
|
|
|
|
|
DiscoveryInformation mockDiscoveryInformation = mock(DiscoveryInformation.class); |
|
|
|
|
|
|
|
when(mockAuthRequest.getDestinationUrl(anyBoolean())).thenReturn("mockUrl"); |
|
|
|
|
|
|
|
when(OpenIdAttributesNullNameConfig.CONSUMER_MANAGER.associate(any())) |
|
|
|
|
|
|
|
.thenReturn(mockDiscoveryInformation); |
|
|
|
|
|
|
|
when(OpenIdAttributesNullNameConfig.CONSUMER_MANAGER.authenticate(any(DiscoveryInformation.class), any(), any())) |
|
|
|
|
|
|
|
.thenReturn(mockAuthRequest); |
|
|
|
|
|
|
|
this.spring.register(OpenIdAttributesNullNameConfig.class).autowire(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try ( MockWebServer server = new MockWebServer() ) { |
|
|
|
|
|
|
|
String endpoint = server.url("/").toString(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
server.enqueue(new MockResponse() |
|
|
|
|
|
|
|
.addHeader(YADIS_XRDS_LOCATION, endpoint)); |
|
|
|
|
|
|
|
server.enqueue(new MockResponse() |
|
|
|
|
|
|
|
.setBody(String.format("<XRDS><XRD><Service><URI>%s</URI></Service></XRD></XRDS>", endpoint))); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MvcResult mvcResult = this.mvc.perform(get("/login/openid") |
|
|
|
|
|
|
|
.param(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, endpoint)) |
|
|
|
|
|
|
|
.andExpect(status().isFound()) |
|
|
|
|
|
|
|
.andReturn(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Object attributeObject = mvcResult.getRequest().getSession().getAttribute("SPRING_SECURITY_OPEN_ID_ATTRIBUTES_FETCH_LIST"); |
|
|
|
|
|
|
|
assertThat(attributeObject).isInstanceOf(List.class); |
|
|
|
|
|
|
|
List<OpenIDAttribute> attributeList = (List<OpenIDAttribute>) attributeObject; |
|
|
|
|
|
|
|
assertThat(attributeList).hasSize(1); |
|
|
|
|
|
|
|
assertThat(attributeList.get(0).getName()).isEqualTo("default-attribute"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@EnableWebSecurity |
|
|
|
|
|
|
|
static class OpenIdAttributesNullNameConfig extends WebSecurityConfigurerAdapter { |
|
|
|
|
|
|
|
static ConsumerManager CONSUMER_MANAGER; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
protected void configure(HttpSecurity http) throws Exception { |
|
|
|
|
|
|
|
// @formatter:off
|
|
|
|
|
|
|
|
http |
|
|
|
|
|
|
|
.authorizeRequests(authorizeRequests -> |
|
|
|
|
|
|
|
authorizeRequests |
|
|
|
|
|
|
|
.anyRequest().permitAll() |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
.openidLogin(openIdLogin -> |
|
|
|
|
|
|
|
openIdLogin |
|
|
|
|
|
|
|
.consumerManager(CONSUMER_MANAGER) |
|
|
|
|
|
|
|
.attributeExchange(attributeExchange -> |
|
|
|
|
|
|
|
attributeExchange |
|
|
|
|
|
|
|
.identifierPattern(".*") |
|
|
|
|
|
|
|
.attribute(withDefaults()) |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
// @formatter:on
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|