mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-30 22:28:46 +00:00 
			
		
		
		
	Replace whitelist with allowlist
Issue gh-8676
This commit is contained in:
		
							parent
							
								
									a907026eae
								
							
						
					
					
						commit
						ca1252be94
					
				| @ -2,7 +2,7 @@ buildscript { | ||||
| 	dependencies { | ||||
| 		classpath 'io.spring.gradle:spring-build-conventions:0.0.32.RELEASE' | ||||
| 		classpath "org.springframework.boot:spring-boot-gradle-plugin:$springBootVersion" | ||||
| 		classpath 'io.spring.nohttp:nohttp-gradle:0.0.2.RELEASE' | ||||
| 		classpath 'io.spring.nohttp:nohttp-gradle:0.0.5.RELEASE' | ||||
| 		classpath "io.freefair.gradle:aspectj-plugin:5.0.1" | ||||
| 		classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion" | ||||
| 	} | ||||
| @ -39,3 +39,7 @@ subprojects { | ||||
| 		options.encoding = "UTF-8" | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| nohttp { | ||||
| 	allowlistFile = project.file("etc/nohttp/allowlist.lines") | ||||
| } | ||||
|  | ||||
| @ -90,7 +90,7 @@ public final class SecurityJackson2Modules { | ||||
| 		if (mapper != null) { | ||||
| 			TypeResolverBuilder<?> typeBuilder = mapper.getDeserializationConfig().getDefaultTyper(null); | ||||
| 			if (typeBuilder == null) { | ||||
| 				mapper.setDefaultTyping(createWhitelistedDefaultTyping()); | ||||
| 				mapper.setDefaultTyping(createAllowlistedDefaultTyping()); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @ -148,11 +148,11 @@ public final class SecurityJackson2Modules { | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Creates a TypeResolverBuilder that performs whitelisting. | ||||
| 	 * @return a TypeResolverBuilder that performs whitelisting. | ||||
| 	 * Creates a TypeResolverBuilder that restricts allowed types. | ||||
| 	 * @return a TypeResolverBuilder that restricts allowed types. | ||||
| 	 */ | ||||
| 	private static TypeResolverBuilder<? extends TypeResolverBuilder> createWhitelistedDefaultTyping() { | ||||
| 		TypeResolverBuilder<? extends TypeResolverBuilder>  result = new WhitelistTypeResolverBuilder(ObjectMapper.DefaultTyping.NON_FINAL); | ||||
| 	private static TypeResolverBuilder<? extends TypeResolverBuilder> createAllowlistedDefaultTyping() { | ||||
| 		TypeResolverBuilder<? extends TypeResolverBuilder>  result = new AllowlistTypeResolverBuilder(ObjectMapper.DefaultTyping.NON_FINAL); | ||||
| 		result = result.init(JsonTypeInfo.Id.CLASS, null); | ||||
| 		result = result.inclusion(JsonTypeInfo.As.PROPERTY); | ||||
| 		return result; | ||||
| @ -164,9 +164,9 @@ public final class SecurityJackson2Modules { | ||||
| 	 * and overrides the {@code TypeIdResolver} | ||||
| 	 * @author Rob Winch | ||||
| 	 */ | ||||
| 	static class WhitelistTypeResolverBuilder extends ObjectMapper.DefaultTypeResolverBuilder { | ||||
| 	static class AllowlistTypeResolverBuilder extends ObjectMapper.DefaultTypeResolverBuilder { | ||||
| 
 | ||||
| 		WhitelistTypeResolverBuilder(ObjectMapper.DefaultTyping defaultTyping) { | ||||
| 		AllowlistTypeResolverBuilder(ObjectMapper.DefaultTyping defaultTyping) { | ||||
| 			super( | ||||
| 					defaultTyping, | ||||
| 					//we do explicit validation in the TypeIdResolver | ||||
| @ -182,17 +182,17 @@ public final class SecurityJackson2Modules { | ||||
| 				PolymorphicTypeValidator subtypeValidator, | ||||
| 				Collection<NamedType> subtypes, boolean forSer, boolean forDeser) { | ||||
| 			TypeIdResolver result = super.idResolver(config, baseType, subtypeValidator, subtypes, forSer, forDeser); | ||||
| 			return new WhitelistTypeIdResolver(result); | ||||
| 			return new AllowlistTypeIdResolver(result); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * A {@link TypeIdResolver} that delegates to an existing implementation and throws an IllegalStateException if the | ||||
| 	 * class being looked up is not whitelisted, does not provide an explicit mixin, and is not annotated with Jackson | ||||
| 	 * class being looked up is not in the allowlist, does not provide an explicit mixin, and is not annotated with Jackson | ||||
| 	 * mappings. See https://github.com/spring-projects/spring-security/issues/4370 | ||||
| 	 */ | ||||
| 	static class WhitelistTypeIdResolver implements TypeIdResolver { | ||||
| 		private static final Set<String> WHITELIST_CLASS_NAMES = Collections.unmodifiableSet(new HashSet(Arrays.asList( | ||||
| 	static class AllowlistTypeIdResolver implements TypeIdResolver { | ||||
| 		private static final Set<String> ALLOWLIST_CLASS_NAMES = Collections.unmodifiableSet(new HashSet(Arrays.asList( | ||||
| 			"java.util.ArrayList", | ||||
| 			"java.util.Collections$EmptyList", | ||||
| 			"java.util.Collections$EmptyMap", | ||||
| @ -209,7 +209,7 @@ public final class SecurityJackson2Modules { | ||||
| 
 | ||||
| 		private final TypeIdResolver delegate; | ||||
| 
 | ||||
| 		WhitelistTypeIdResolver(TypeIdResolver delegate) { | ||||
| 		AllowlistTypeIdResolver(TypeIdResolver delegate) { | ||||
| 			this.delegate = delegate; | ||||
| 		} | ||||
| 
 | ||||
| @ -238,7 +238,7 @@ public final class SecurityJackson2Modules { | ||||
| 			DeserializationConfig config = (DeserializationConfig) context.getConfig(); | ||||
| 			JavaType result = delegate.typeFromId(context, id); | ||||
| 			String className = result.getRawClass().getName(); | ||||
| 			if (isWhitelisted(className)) { | ||||
| 			if (isInAllowlist(className)) { | ||||
| 				return result; | ||||
| 			} | ||||
| 			boolean isExplicitMixin = config.findMixInClassFor(result.getRawClass()) != null; | ||||
| @ -249,14 +249,14 @@ public final class SecurityJackson2Modules { | ||||
| 			if (jacksonAnnotation != null) { | ||||
| 				return result; | ||||
| 			} | ||||
| 			throw new IllegalArgumentException("The class with " + id + " and name of " + className + " is not whitelisted. " + | ||||
| 			throw new IllegalArgumentException("The class with " + id + " and name of " + className + " is not in the allowlist. " + | ||||
| 				"If you believe this class is safe to deserialize, please provide an explicit mapping using Jackson annotations or by providing a Mixin. " + | ||||
| 				"If the serialization is only done by a trusted source, you can also enable default typing. " + | ||||
| 				"See https://github.com/spring-projects/spring-security/issues/4370 for details"); | ||||
| 		} | ||||
| 
 | ||||
| 		private boolean isWhitelisted(String id) { | ||||
| 			return WHITELIST_CLASS_NAMES.contains(id); | ||||
| 		private boolean isInAllowlist(String id) { | ||||
| 			return ALLOWLIST_CLASS_NAMES.contains(id); | ||||
| 		} | ||||
| 
 | ||||
| 		@Override | ||||
|  | ||||
| @ -44,20 +44,20 @@ public class SecurityJackson2ModulesTests { | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void readValueWhenNotWhitelistedOrMappedThenThrowsException() { | ||||
| 		String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotWhitelisted\",\"property\":\"bar\"}"; | ||||
| 	public void readValueWhenNotAllowedOrMappedThenThrowsException() { | ||||
| 		String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotAllowlisted\",\"property\":\"bar\"}"; | ||||
| 		assertThatThrownBy(() -> { | ||||
| 				mapper.readValue(content, Object.class); | ||||
| 			} | ||||
| 		).hasStackTraceContaining("whitelisted"); | ||||
| 		).hasStackTraceContaining("allowlist"); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void readValueWhenExplicitDefaultTypingAfterSecuritySetupThenReadsAsSpecificType() throws Exception { | ||||
| 		mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); | ||||
| 		String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotWhitelisted\",\"property\":\"bar\"}"; | ||||
| 		String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotAllowlisted\",\"property\":\"bar\"}"; | ||||
| 
 | ||||
| 		assertThat(mapper.readValue(content, Object.class)).isInstanceOf(NotWhitelisted.class); | ||||
| 		assertThat(mapper.readValue(content, Object.class)).isInstanceOf(NotAllowlisted.class); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| @ -65,29 +65,29 @@ public class SecurityJackson2ModulesTests { | ||||
| 		mapper = new ObjectMapper(); | ||||
| 		mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY); | ||||
| 		SecurityJackson2Modules.enableDefaultTyping(mapper); | ||||
| 		String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotWhitelisted\",\"property\":\"bar\"}"; | ||||
| 		String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotAllowlisted\",\"property\":\"bar\"}"; | ||||
| 
 | ||||
| 		assertThat(mapper.readValue(content, Object.class)).isInstanceOf(NotWhitelisted.class); | ||||
| 		assertThat(mapper.readValue(content, Object.class)).isInstanceOf(NotAllowlisted.class); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void readValueWhenAnnotatedThenReadsAsSpecificType() throws Exception { | ||||
| 		String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotWhitelistedButAnnotated\",\"property\":\"bar\"}"; | ||||
| 		String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotAllowlistedButAnnotated\",\"property\":\"bar\"}"; | ||||
| 
 | ||||
| 		assertThat(mapper.readValue(content, Object.class)).isInstanceOf(NotWhitelistedButAnnotated.class); | ||||
| 		assertThat(mapper.readValue(content, Object.class)).isInstanceOf(NotAllowlistedButAnnotated.class); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void readValueWhenMixinProvidedThenReadsAsSpecificType() throws Exception { | ||||
| 		mapper.addMixIn(NotWhitelisted.class, NotWhitelistedMixin.class); | ||||
| 		String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotWhitelisted\",\"property\":\"bar\"}"; | ||||
| 		mapper.addMixIn(NotAllowlisted.class, NotAllowlistedMixin.class); | ||||
| 		String content = "{\"@class\":\"org.springframework.security.jackson2.SecurityJackson2ModulesTests$NotAllowlisted\",\"property\":\"bar\"}"; | ||||
| 
 | ||||
| 		assertThat(mapper.readValue(content, Object.class)).isInstanceOf(NotWhitelisted.class); | ||||
| 		assertThat(mapper.readValue(content, Object.class)).isInstanceOf(NotAllowlisted.class); | ||||
| 	} | ||||
| 
 | ||||
| 	@Test | ||||
| 	public void readValueWhenHashMapThenReadsAsSpecificType() throws Exception { | ||||
| 		mapper.addMixIn(NotWhitelisted.class, NotWhitelistedMixin.class); | ||||
| 		mapper.addMixIn(NotAllowlisted.class, NotAllowlistedMixin.class); | ||||
| 		String content = "{\"@class\":\"java.util.HashMap\"}"; | ||||
| 
 | ||||
| 		assertThat(mapper.readValue(content, Object.class)).isInstanceOf(HashMap.class); | ||||
| @ -99,7 +99,7 @@ public class SecurityJackson2ModulesTests { | ||||
| 	public @interface NotJacksonAnnotation {} | ||||
| 
 | ||||
| 	@NotJacksonAnnotation | ||||
| 	static class NotWhitelisted { | ||||
| 	static class NotAllowlisted { | ||||
| 		private String property = "bar"; | ||||
| 
 | ||||
| 		public String getProperty() { | ||||
| @ -111,7 +111,7 @@ public class SecurityJackson2ModulesTests { | ||||
| 	} | ||||
| 
 | ||||
| 	@JsonIgnoreType(false) | ||||
| 	static class NotWhitelistedButAnnotated { | ||||
| 	static class NotAllowlistedButAnnotated { | ||||
| 		private String property = "bar"; | ||||
| 
 | ||||
| 		public String getProperty() { | ||||
| @ -126,7 +126,7 @@ public class SecurityJackson2ModulesTests { | ||||
| 	@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, | ||||
| 		isGetterVisibility = JsonAutoDetect.Visibility.NONE) | ||||
| 	@JsonIgnoreProperties(ignoreUnknown = true) | ||||
| 	abstract class NotWhitelistedMixin { | ||||
| 	abstract class NotAllowlistedMixin { | ||||
| 
 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -1082,7 +1082,7 @@ In this case, you construct `JwtIssuerReactiveAuthenticationManagerResolver` wit | ||||
| This approach allows us to add and remove elements from the repository (shown as a `Map` in the snippet) at runtime. | ||||
| 
 | ||||
| NOTE: It would be unsafe to simply take any issuer and construct an `ReactiveAuthenticationManager` from it. | ||||
| The issuer should be one that the code can verify from a trusted source like a whitelist. | ||||
| The issuer should be one that the code can verify from a trusted source like an allowed list of issuers. | ||||
| 
 | ||||
| [[webflux-oauth2resourceserver-bearertoken-resolver]] | ||||
| == Bearer Token Resolution | ||||
|  | ||||
| @ -1857,7 +1857,7 @@ In this case, you construct `JwtIssuerAuthenticationManagerResolver` with a stra | ||||
| This approach allows us to add and remove elements from the repository (shown as a `Map` in the snippet) at runtime. | ||||
| 
 | ||||
| NOTE: It would be unsafe to simply take any issuer and construct an `AuthenticationManager` from it. | ||||
| The issuer should be one that the code can verify from a trusted source like a whitelist. | ||||
| The issuer should be one that the code can verify from a trusted source like a list of allowed issuers. | ||||
| 
 | ||||
| ===== Parsing the Claim Only Once | ||||
| 
 | ||||
| @ -1907,7 +1907,7 @@ public class TenantJWSKeySelector | ||||
| ---- | ||||
| <1> A hypothetical source for tenant information | ||||
| <2> A cache for `JWKKeySelector`s, keyed by tenant identifier | ||||
| <3> Looking up the tenant is more secure than simply calculating the JWK Set endpoint on the fly - the lookup acts as a tenant whitelist | ||||
| <3> Looking up the tenant is more secure than simply calculating the JWK Set endpoint on the fly - the lookup acts as a list of allowed tenants | ||||
| <4> Create a `JWSKeySelector` via the types of keys that come back from the JWK Set endpoint - the lazy lookup here means that you don't need to configure all tenants at startup | ||||
| 
 | ||||
| The above key selector is a composition of many key selectors. | ||||
|  | ||||
| @ -45,7 +45,7 @@ import org.springframework.util.Assert; | ||||
|  * | ||||
|  * To use, this class must be able to determine whether or not the `iss` claim is trusted. Recall that | ||||
|  * anyone can stand up an authorization server and issue valid tokens to a resource server. The simplest way | ||||
|  * to achieve this is to supply a whitelist of trusted issuers in the constructor. | ||||
|  * to achieve this is to supply a list of trusted issuers in the constructor. | ||||
|  * | ||||
|  * This class derives the Issuer from the `iss` claim found in the {@link HttpServletRequest}'s | ||||
|  * <a href="https://tools.ietf.org/html/rfc6750#section-1.2" target="_blank">Bearer Token</a>. | ||||
| @ -60,7 +60,7 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat | ||||
| 	/** | ||||
| 	 * Construct a {@link JwtIssuerAuthenticationManagerResolver} using the provided parameters | ||||
| 	 * | ||||
| 	 * @param trustedIssuers a whitelist of trusted issuers | ||||
| 	 * @param trustedIssuers a list of trusted issuers | ||||
| 	 */ | ||||
| 	public JwtIssuerAuthenticationManagerResolver(String... trustedIssuers) { | ||||
| 		this(Arrays.asList(trustedIssuers)); | ||||
| @ -69,7 +69,7 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat | ||||
| 	/** | ||||
| 	 * Construct a {@link JwtIssuerAuthenticationManagerResolver} using the provided parameters | ||||
| 	 * | ||||
| 	 * @param trustedIssuers a whitelist of trusted issuers | ||||
| 	 * @param trustedIssuers a list of trusted issuers | ||||
| 	 */ | ||||
| 	public JwtIssuerAuthenticationManagerResolver(Collection<String> trustedIssuers) { | ||||
| 		Assert.notEmpty(trustedIssuers, "trustedIssuers cannot be empty"); | ||||
| @ -82,7 +82,7 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat | ||||
| 	 * Construct a {@link JwtIssuerAuthenticationManagerResolver} using the provided parameters | ||||
| 	 * | ||||
| 	 * Note that the {@link AuthenticationManagerResolver} provided in this constructor will need to | ||||
| 	 * verify that the issuer is trusted. This should be done via a whitelist. | ||||
| 	 * verify that the issuer is trusted. This should be done via an allowlist. | ||||
| 	 * | ||||
| 	 * One way to achieve this is with a {@link Map} where the keys are the known issuers: | ||||
| 	 * <pre> | ||||
| @ -93,7 +93,7 @@ public final class JwtIssuerAuthenticationManagerResolver implements Authenticat | ||||
| 	 *     	(authenticationManagers::get); | ||||
| 	 * </pre> | ||||
| 	 * | ||||
| 	 * The keys in the {@link Map} are the whitelist. | ||||
| 	 * The keys in the {@link Map} are the allowed issuers. | ||||
| 	 * | ||||
| 	 * @param issuerAuthenticationManagerResolver a strategy for resolving the {@link AuthenticationManager} by the issuer | ||||
| 	 */ | ||||
|  | ||||
| @ -48,7 +48,7 @@ import org.springframework.web.server.ServerWebExchange; | ||||
|  * | ||||
|  * To use, this class must be able to determine whether or not the `iss` claim is trusted. Recall that | ||||
|  * anyone can stand up an authorization server and issue valid tokens to a resource server. The simplest way | ||||
|  * to achieve this is to supply a whitelist of trusted issuers in the constructor. | ||||
|  * to achieve this is to supply a list of trusted issuers in the constructor. | ||||
|  * | ||||
|  * This class derives the Issuer from the `iss` claim found in the {@link ServerWebExchange}'s | ||||
|  * <a href="https://tools.ietf.org/html/rfc6750#section-1.2" target="_blank">Bearer Token</a>. | ||||
| @ -66,7 +66,7 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver | ||||
| 	/** | ||||
| 	 * Construct a {@link JwtIssuerReactiveAuthenticationManagerResolver} using the provided parameters | ||||
| 	 * | ||||
| 	 * @param trustedIssuers a whitelist of trusted issuers | ||||
| 	 * @param trustedIssuers a list of trusted issuers | ||||
| 	 */ | ||||
| 	public JwtIssuerReactiveAuthenticationManagerResolver(String... trustedIssuers) { | ||||
| 		this(Arrays.asList(trustedIssuers)); | ||||
| @ -75,7 +75,7 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver | ||||
| 	/** | ||||
| 	 * Construct a {@link JwtIssuerReactiveAuthenticationManagerResolver} using the provided parameters | ||||
| 	 * | ||||
| 	 * @param trustedIssuers a whitelist of trusted issuers | ||||
| 	 * @param trustedIssuers a collection of trusted issuers | ||||
| 	 */ | ||||
| 	public JwtIssuerReactiveAuthenticationManagerResolver(Collection<String> trustedIssuers) { | ||||
| 		Assert.notEmpty(trustedIssuers, "trustedIssuers cannot be empty"); | ||||
| @ -87,7 +87,7 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver | ||||
| 	 * Construct a {@link JwtIssuerReactiveAuthenticationManagerResolver} using the provided parameters | ||||
| 	 * | ||||
| 	 * Note that the {@link ReactiveAuthenticationManagerResolver} provided in this constructor will need to | ||||
| 	 * verify that the issuer is trusted. This should be done via a whitelist. | ||||
| 	 * verify that the issuer is trusted. This should be done via an allowed list of issuers. | ||||
| 	 * | ||||
| 	 * One way to achieve this is with a {@link Map} where the keys are the known issuers: | ||||
| 	 * <pre> | ||||
| @ -98,7 +98,7 @@ public final class JwtIssuerReactiveAuthenticationManagerResolver | ||||
| 	 *     	(issuer -> Mono.justOrEmpty(authenticationManagers.get(issuer)); | ||||
| 	 * </pre> | ||||
| 	 * | ||||
| 	 * The keys in the {@link Map} are the whitelist. | ||||
| 	 * The keys in the {@link Map} are the trusted issuers. | ||||
| 	 * | ||||
| 	 * @param issuerAuthenticationManagerResolver a strategy for resolving the {@link ReactiveAuthenticationManager} | ||||
| 	 * by the issuer | ||||
|  | ||||
| @ -358,7 +358,7 @@ public class StrictHttpFirewall implements HttpFirewall { | ||||
| 		if (!this.allowedHttpMethods.contains(request.getMethod())) { | ||||
| 			throw new RequestRejectedException("The request was rejected because the HTTP method \"" + | ||||
| 					request.getMethod() + | ||||
| 					"\" was not included within the whitelist " + | ||||
| 					"\" was not included within the list of allowed HTTP methods " + | ||||
| 					this.allowedHttpMethods); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user