parent
							
								
									af669a2166
								
							
						
					
					
						commit
						4602e9a661
					
				|  | @ -16,12 +16,15 @@ | |||
| 
 | ||||
| package org.springframework.security.config.annotation.web.configurers.oauth2.server.resource; | ||||
| 
 | ||||
| import java.util.Arrays; | ||||
| import java.util.Collections; | ||||
| import java.util.function.Supplier; | ||||
| 
 | ||||
| import javax.servlet.http.HttpServletRequest; | ||||
| 
 | ||||
| import org.springframework.context.ApplicationContext; | ||||
| import org.springframework.core.convert.converter.Converter; | ||||
| import org.springframework.http.MediaType; | ||||
| import org.springframework.security.authentication.AbstractAuthenticationToken; | ||||
| import org.springframework.security.authentication.AuthenticationManager; | ||||
| import org.springframework.security.authentication.AuthenticationManagerResolver; | ||||
|  | @ -48,8 +51,15 @@ import org.springframework.security.oauth2.server.resource.web.DefaultBearerToke | |||
| import org.springframework.security.oauth2.server.resource.web.access.BearerTokenAccessDeniedHandler; | ||||
| import org.springframework.security.web.AuthenticationEntryPoint; | ||||
| import org.springframework.security.web.access.AccessDeniedHandler; | ||||
| import org.springframework.security.web.util.matcher.AndRequestMatcher; | ||||
| import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher; | ||||
| import org.springframework.security.web.util.matcher.NegatedRequestMatcher; | ||||
| import org.springframework.security.web.util.matcher.OrRequestMatcher; | ||||
| import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher; | ||||
| import org.springframework.security.web.util.matcher.RequestMatcher; | ||||
| import org.springframework.util.Assert; | ||||
| import org.springframework.web.accept.ContentNegotiationStrategy; | ||||
| import org.springframework.web.accept.HeaderContentNegotiationStrategy; | ||||
| 
 | ||||
| /** | ||||
|  * | ||||
|  | @ -130,6 +140,9 @@ import org.springframework.util.Assert; | |||
| public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder<H>> | ||||
| 		extends AbstractHttpConfigurer<OAuth2ResourceServerConfigurer<H>, H> { | ||||
| 
 | ||||
| 	private static final RequestHeaderRequestMatcher X_REQUESTED_WITH = new RequestHeaderRequestMatcher( | ||||
| 			"X-Requested-With", "XMLHttpRequest"); | ||||
| 
 | ||||
| 	private final ApplicationContext context; | ||||
| 
 | ||||
| 	private AuthenticationManagerResolver<HttpServletRequest> authenticationManagerResolver; | ||||
|  | @ -273,7 +286,25 @@ public final class OAuth2ResourceServerConfigurer<H extends HttpSecurityBuilder< | |||
| 	private void registerDefaultEntryPoint(H http) { | ||||
| 		ExceptionHandlingConfigurer<H> exceptionHandling = http.getConfigurer(ExceptionHandlingConfigurer.class); | ||||
| 		if (exceptionHandling != null) { | ||||
| 			exceptionHandling.defaultAuthenticationEntryPointFor(this.authenticationEntryPoint, this.requestMatcher); | ||||
| 			ContentNegotiationStrategy contentNegotiationStrategy = http | ||||
| 					.getSharedObject(ContentNegotiationStrategy.class); | ||||
| 			if (contentNegotiationStrategy == null) { | ||||
| 				contentNegotiationStrategy = new HeaderContentNegotiationStrategy(); | ||||
| 			} | ||||
| 			MediaTypeRequestMatcher restMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy, | ||||
| 					MediaType.APPLICATION_ATOM_XML, MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON, | ||||
| 					MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_XML, MediaType.MULTIPART_FORM_DATA, | ||||
| 					MediaType.TEXT_XML); | ||||
| 			restMatcher.setIgnoredMediaTypes(Collections.singleton(MediaType.ALL)); | ||||
| 			MediaTypeRequestMatcher allMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.ALL); | ||||
| 			allMatcher.setUseEquals(true); | ||||
| 			RequestMatcher notHtmlMatcher = new NegatedRequestMatcher( | ||||
| 					new MediaTypeRequestMatcher(contentNegotiationStrategy, MediaType.TEXT_HTML)); | ||||
| 			RequestMatcher restNotHtmlMatcher = new AndRequestMatcher( | ||||
| 					Arrays.<RequestMatcher>asList(notHtmlMatcher, restMatcher)); | ||||
| 			RequestMatcher preferredMatcher = new OrRequestMatcher( | ||||
| 					Arrays.asList(this.requestMatcher, X_REQUESTED_WITH, restNotHtmlMatcher, allMatcher)); | ||||
| 			exceptionHandling.defaultAuthenticationEntryPointFor(this.authenticationEntryPoint, preferredMatcher); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
|  | @ -89,6 +89,10 @@ import org.springframework.security.core.Authentication; | |||
| import org.springframework.security.core.GrantedAuthority; | ||||
| import org.springframework.security.core.authority.SimpleGrantedAuthority; | ||||
| import org.springframework.security.core.userdetails.UserDetailsService; | ||||
| import org.springframework.security.oauth2.client.registration.ClientRegistration; | ||||
| import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; | ||||
| import org.springframework.security.oauth2.client.registration.InMemoryClientRegistrationRepository; | ||||
| import org.springframework.security.oauth2.client.registration.TestClientRegistrations; | ||||
| import org.springframework.security.oauth2.core.DefaultOAuth2AuthenticatedPrincipal; | ||||
| import org.springframework.security.oauth2.core.OAuth2AuthenticationException; | ||||
| import org.springframework.security.oauth2.core.OAuth2Error; | ||||
|  | @ -1108,7 +1112,8 @@ public class OAuth2ResourceServerConfigurerTests { | |||
| 		JwtDecoder decoder = this.spring.getContext().getBean(JwtDecoder.class); | ||||
| 		given(decoder.decode(anyString())).willThrow(JwtException.class); | ||||
| 		// @formatter:off | ||||
| 		MvcResult result = this.mvc.perform(get("/authenticated")) | ||||
| 		MvcResult result = this.mvc.perform(get("/authenticated") | ||||
| 				.header("Accept", "text/html")) | ||||
| 				.andExpect(status().isFound()) | ||||
| 				.andExpect(redirectedUrl("http://localhost/login")) | ||||
| 				.andReturn(); | ||||
|  | @ -1122,6 +1127,15 @@ public class OAuth2ResourceServerConfigurerTests { | |||
| 		assertThat(result.getRequest().getSession(false)).isNull(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void unauthenticatedRequestWhenFormOAuth2LoginAndResourceServerThenNegotiates() throws Exception { | ||||
| 		this.spring.register(OAuth2LoginAndResourceServerConfig.class, JwtDecoderConfig.class).autowire(); | ||||
| 		this.mvc.perform(get("/any").header("X-Requested-With", "XMLHttpRequest")).andExpect(status().isUnauthorized()); | ||||
| 		this.mvc.perform(get("/any").header("Accept", "application/json")).andExpect(status().isUnauthorized()); | ||||
| 		this.mvc.perform(get("/any").header("Accept", "text/html")).andExpect(status().is3xxRedirection()); | ||||
| 		this.mvc.perform(get("/any").header("Accept", "image/jpg")).andExpect(status().is3xxRedirection()); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void requestWhenDefaultAndResourceServerAccessDeniedHandlersThenMatchedByRequest() throws Exception { | ||||
| 		this.spring | ||||
|  | @ -1721,6 +1735,31 @@ public class OAuth2ResourceServerConfigurerTests { | |||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	@EnableWebSecurity | ||||
| 	static class OAuth2LoginAndResourceServerConfig extends WebSecurityConfigurerAdapter { | ||||
| 
 | ||||
| 		@Override | ||||
| 		protected void configure(HttpSecurity http) throws Exception { | ||||
| 			// @formatter:off | ||||
| 			http | ||||
| 				.authorizeRequests((authz) -> authz | ||||
| 					.anyRequest().authenticated() | ||||
| 				) | ||||
| 				.oauth2Login(withDefaults()) | ||||
| 				.oauth2ResourceServer((oauth2) -> oauth2 | ||||
| 					.jwt() | ||||
| 				); | ||||
| 			// @formatter:on | ||||
| 		} | ||||
| 
 | ||||
| 		@Bean | ||||
| 		ClientRegistrationRepository clients() { | ||||
| 			ClientRegistration registration = TestClientRegistrations.clientRegistration().build(); | ||||
| 			return new InMemoryClientRegistrationRepository(registration); | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	@EnableWebSecurity | ||||
| 	static class JwtHalfConfiguredConfig extends WebSecurityConfigurerAdapter { | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue