diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java index 12cf10c07d..56b3ffbc81 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/builders/HttpSecurity.java @@ -53,7 +53,6 @@ import org.springframework.security.config.annotation.web.configurers.ChannelSec import org.springframework.security.config.annotation.web.configurers.CorsConfigurer; import org.springframework.security.config.annotation.web.configurers.CsrfConfigurer; import org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer; -import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; import org.springframework.security.config.annotation.web.configurers.FormLoginConfigurer; import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer; import org.springframework.security.config.annotation.web.configurers.HttpBasicConfigurer; @@ -613,125 +612,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilderExample Configurations - * - * The most basic example is to configure all URLs to require the role "ROLE_USER". - * The configuration below requires authentication to every URL and will grant access - * to both the user "admin" and "user". - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class AuthorizeUrlsSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.authorizeRequests((authorizeRequests) ->
-	 * 				authorizeRequests
-	 * 					.requestMatchers("/**").hasRole("USER")
-	 * 			)
-	 * 			.formLogin(withDefaults());
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		UserDetails admin = User.withDefaultPasswordEncoder()
-	 * 			.username("admin")
-	 * 			.password("password")
-	 * 			.roles("ADMIN", "USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user, admin);
-	 * 	}
-	 * }
-	 * 
- * - * We can also configure multiple URLs. The configuration below requires - * authentication to every URL and will grant access to URLs starting with /admin/ to - * only the "admin" user. All other URLs either user can access. - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class AuthorizeUrlsSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		http
-	 * 			.authorizeRequests((authorizeRequests) ->
-	 * 				authorizeRequests
-	 * 					.requestMatchers("/admin/**").hasRole("ADMIN")
-	 * 					.requestMatchers("/**").hasRole("USER")
-	 * 			)
-	 * 			.formLogin(withDefaults());
-	 * 		return http.build();
-	 * 	}
-	 *
-	 * 	@Bean
-	 * 	public UserDetailsService userDetailsService() {
-	 * 		UserDetails user = User.withDefaultPasswordEncoder()
-	 * 			.username("user")
-	 * 			.password("password")
-	 * 			.roles("USER")
-	 * 			.build();
-	 * 		UserDetails admin = User.withDefaultPasswordEncoder()
-	 * 			.username("admin")
-	 * 			.password("password")
-	 * 			.roles("ADMIN", "USER")
-	 * 			.build();
-	 * 		return new InMemoryUserDetailsManager(user, admin);
-	 * 	}
-	 * }
-	 * 
- * - * Note that the matchers are considered in order. Therefore, the following is invalid - * because the first matcher matches every request and will never get to the second - * mapping: - * - *
-	 * @Configuration
-	 * @EnableWebSecurity
-	 * public class AuthorizeUrlsSecurityConfig {
-	 *
-	 * 	@Bean
-	 * 	public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
-	 * 		 http
-	 * 		 	.authorizeRequests((authorizeRequests) ->
-	 * 		 		authorizeRequests
-	 * 			 		.requestMatchers("/**").hasRole("USER")
-	 * 			 		.requestMatchers("/admin/**").hasRole("ADMIN")
-	 * 		 	);
-	 * 		return http.build();
-	 * 	}
-	 * }
-	 * 
- * @param authorizeRequestsCustomizer the {@link Customizer} to provide more options - * for the {@link ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry} - * @return the {@link HttpSecurity} for further customizations - * @throws Exception - * @deprecated For removal in 7.0. Use {@link #authorizeHttpRequests(Customizer)} - * instead - */ - @Deprecated(since = "6.1", forRemoval = true) - public HttpSecurity authorizeRequests( - Customizer.ExpressionInterceptUrlRegistry> authorizeRequestsCustomizer) - throws Exception { - ApplicationContext context = getContext(); - authorizeRequestsCustomizer - .customize(getOrApply(new ExpressionUrlAuthorizationConfigurer<>(context)).getRegistry()); - return HttpSecurity.this; - } - /** * Allows restricting access based upon the {@link HttpServletRequest} using * {@link RequestMatcher} implementations (i.e. via URL patterns). @@ -1936,12 +1816,6 @@ public final class HttpSecurity extends AbstractConfiguredSecurityBuilder expressionConfigurer = getConfigurer( - ExpressionUrlAuthorizationConfigurer.class); - AuthorizeHttpRequestsConfigurer httpConfigurer = getConfigurer(AuthorizeHttpRequestsConfigurer.class); - boolean oneConfigurerPresent = expressionConfigurer == null ^ httpConfigurer == null; - Assert.state((expressionConfigurer == null && httpConfigurer == null) || oneConfigurerPresent, - "authorizeHttpRequests cannot be used in conjunction with authorizeRequests. Please select just one."); this.filters.sort(OrderComparator.INSTANCE); List sortedFilters = new ArrayList<>(this.filters.size()); for (Filter filter : this.filters) { diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java index dd3a6513fb..afd60cb114 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractConfigAttributeRequestMatcherRegistry.java @@ -36,8 +36,6 @@ import org.springframework.util.Assert; * @author Rob Winch * @since 3.2 * @see ChannelSecurityConfigurer - * @see UrlAuthorizationConfigurer - * @see ExpressionUrlAuthorizationConfigurer * @deprecated In modern Spring Security APIs, each API manages its own configuration * context. As such there is no direct replacement for this interface. In the case of * method security, please see {@link SecurityAnnotationScanner} and diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java deleted file mode 100644 index ad0454dfb3..0000000000 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/AbstractInterceptUrlConfigurer.java +++ /dev/null @@ -1,196 +0,0 @@ -/* - * Copyright 2002-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.web.configurers; - -import java.util.List; - -import org.springframework.security.access.AccessDecisionManager; -import org.springframework.security.access.AccessDecisionVoter; -import org.springframework.security.access.vote.AffirmativeBased; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.config.annotation.SecurityConfigurer; -import org.springframework.security.config.annotation.web.HttpSecurityBuilder; -import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; -import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; - -/** - * A base class for configuring the {@link FilterSecurityInterceptor}. - * - *

Security Filters

- * - * The following Filters are populated - * - *
    - *
  • {@link FilterSecurityInterceptor}
  • - *
- * - *

Shared Objects Created

- * - * The following shared objects are populated to allow other {@link SecurityConfigurer}'s - * to customize: - *
    - *
  • {@link FilterSecurityInterceptor}
  • - *
- * - *

Shared Objects Used

- * - * The following shared objects are used: - * - *
    - *
  • {@link AuthenticationManager}
  • - *
- * - * @param the AbstractInterceptUrlConfigurer - * @param the type of {@link HttpSecurityBuilder} that is being configured - * @author Rob Winch - * @since 3.2 - * @see ExpressionUrlAuthorizationConfigurer - * @see UrlAuthorizationConfigurer - * @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead - */ -@Deprecated -public abstract class AbstractInterceptUrlConfigurer, H extends HttpSecurityBuilder> - extends AbstractHttpConfigurer { - - private Boolean filterSecurityInterceptorOncePerRequest; - - private AccessDecisionManager accessDecisionManager; - - AbstractInterceptUrlConfigurer() { - } - - @Override - public void configure(H http) throws Exception { - FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http); - if (metadataSource == null) { - return; - } - FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(http, metadataSource, - http.getSharedObject(AuthenticationManager.class)); - if (this.filterSecurityInterceptorOncePerRequest != null) { - securityInterceptor.setObserveOncePerRequest(this.filterSecurityInterceptorOncePerRequest); - } - securityInterceptor = postProcess(securityInterceptor); - http.addFilter(securityInterceptor); - http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor); - } - - /** - * Subclasses should implement this method to provide a - * {@link FilterInvocationSecurityMetadataSource} for the - * {@link FilterSecurityInterceptor}. - * @param http the builder to use - * @return the {@link FilterInvocationSecurityMetadataSource} to set on the - * {@link FilterSecurityInterceptor}. Cannot be null. - */ - abstract FilterInvocationSecurityMetadataSource createMetadataSource(H http); - - /** - * Subclasses should implement this method to provide the {@link AccessDecisionVoter} - * instances used to create the default {@link AccessDecisionManager} - * @param http the builder to use - * @return the {@link AccessDecisionVoter} instances used to create the default - * {@link AccessDecisionManager} - */ - abstract List> getDecisionVoters(H http); - - /** - * Creates the default {@code AccessDecisionManager} - * @return the default {@code AccessDecisionManager} - */ - private AccessDecisionManager createDefaultAccessDecisionManager(H http) { - AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http)); - return postProcess(result); - } - - /** - * If currently null, creates a default {@link AccessDecisionManager} using - * {@link #createDefaultAccessDecisionManager(HttpSecurityBuilder)}. Otherwise returns - * the {@link AccessDecisionManager}. - * @param http the builder to use - * @return the {@link AccessDecisionManager} to use - */ - private AccessDecisionManager getAccessDecisionManager(H http) { - if (this.accessDecisionManager == null) { - this.accessDecisionManager = createDefaultAccessDecisionManager(http); - } - return this.accessDecisionManager; - } - - /** - * Creates the {@link FilterSecurityInterceptor} - * @param http the builder to use - * @param metadataSource the {@link FilterInvocationSecurityMetadataSource} to use - * @param authenticationManager the {@link AuthenticationManager} to use - * @return the {@link FilterSecurityInterceptor} - * @throws Exception - */ - private FilterSecurityInterceptor createFilterSecurityInterceptor(H http, - FilterInvocationSecurityMetadataSource metadataSource, AuthenticationManager authenticationManager) - throws Exception { - FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor(); - securityInterceptor.setSecurityMetadataSource(metadataSource); - securityInterceptor.setAccessDecisionManager(getAccessDecisionManager(http)); - securityInterceptor.setAuthenticationManager(authenticationManager); - securityInterceptor.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy()); - securityInterceptor.afterPropertiesSet(); - return securityInterceptor; - } - - @Deprecated - public abstract class AbstractInterceptUrlRegistry, T> - extends AbstractConfigAttributeRequestMatcherRegistry { - - AbstractInterceptUrlRegistry() { - } - - /** - * Allows setting the {@link AccessDecisionManager}. If none is provided, a - * default {@link AccessDecisionManager} is created. - * @param accessDecisionManager the {@link AccessDecisionManager} to use - * @return the {@link AbstractInterceptUrlConfigurer} for further customization - */ - public R accessDecisionManager(AccessDecisionManager accessDecisionManager) { - AbstractInterceptUrlConfigurer.this.accessDecisionManager = accessDecisionManager; - return getSelf(); - } - - /** - * Allows setting if the {@link FilterSecurityInterceptor} should be only applied - * once per request (i.e. if the filter intercepts on a forward, should it be - * applied again). - * @param filterSecurityInterceptorOncePerRequest if the - * {@link FilterSecurityInterceptor} should be only applied once per request - * @return the {@link AbstractInterceptUrlConfigurer} for further customization - */ - public R filterSecurityInterceptorOncePerRequest(boolean filterSecurityInterceptorOncePerRequest) { - AbstractInterceptUrlConfigurer.this.filterSecurityInterceptorOncePerRequest = filterSecurityInterceptorOncePerRequest; - return getSelf(); - } - - /** - * Returns a reference to the current object with a single suppression of the type - * @return a reference to the current object - */ - @SuppressWarnings("unchecked") - private R getSelf() { - return (R) this; - } - - } - -} diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java deleted file mode 100644 index 91b0838011..0000000000 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurer.java +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Copyright 2002-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.web.configurers; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; - -import org.springframework.context.ApplicationContext; -import org.springframework.security.access.AccessDecisionVoter; -import org.springframework.security.access.ConfigAttribute; -import org.springframework.security.access.PermissionEvaluator; -import org.springframework.security.access.SecurityConfig; -import org.springframework.security.access.expression.SecurityExpressionHandler; -import org.springframework.security.access.hierarchicalroles.RoleHierarchy; -import org.springframework.security.authentication.AuthenticationTrustResolver; -import org.springframework.security.config.Customizer; -import org.springframework.security.config.ObjectPostProcessor; -import org.springframework.security.config.annotation.web.HttpSecurityBuilder; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.core.GrantedAuthorityDefaults; -import org.springframework.security.web.FilterInvocation; -import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; -import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource; -import org.springframework.security.web.access.expression.WebExpressionVoter; -import org.springframework.security.web.util.matcher.RequestMatcher; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - -/** - * Adds URL based authorization based upon SpEL expressions to an application. At least - * one {@link org.springframework.web.bind.annotation.RequestMapping} needs to be mapped - * to {@link ConfigAttribute}'s for this {@link SecurityContextConfigurer} to have - * meaning. - *

Security Filters

- * - * The following Filters are populated - * - *
    - *
  • {@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor} - *
  • - *
- * - *

Shared Objects Created

- * - * The following shared objects are populated to allow other - * {@link org.springframework.security.config.annotation.SecurityConfigurer}'s to - * customize: - *
    - *
  • {@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor} - *
  • - *
- * - *

Shared Objects Used

- * - *
    - *
  • {@link AuthenticationTrustResolver} is optionally used to populate the - * {@link DefaultWebSecurityExpressionHandler}
  • - *
- * - * @param the type of {@link HttpSecurityBuilder} that is being configured - * @author Rob Winch - * @author Yanming Zhou - * @author Ngoc Nhan - * @since 3.2 - * @see org.springframework.security.config.annotation.web.builders.HttpSecurity#authorizeRequests(Customizer) - * @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead - */ -@Deprecated -public final class ExpressionUrlAuthorizationConfigurer> - extends AbstractInterceptUrlConfigurer, H> { - - static final String permitAll = "permitAll"; - - private static final String denyAll = "denyAll"; - - private static final String anonymous = "anonymous"; - - private static final String authenticated = "authenticated"; - - private static final String fullyAuthenticated = "fullyAuthenticated"; - - private static final String rememberMe = "rememberMe"; - - private final String rolePrefix; - - private final ExpressionInterceptUrlRegistry REGISTRY; - - private SecurityExpressionHandler expressionHandler; - - /** - * Creates a new instance - * @see HttpSecurity#authorizeRequests(Customizer) - */ - public ExpressionUrlAuthorizationConfigurer(ApplicationContext context) { - GrantedAuthorityDefaults grantedAuthorityDefaults = context.getBeanProvider(GrantedAuthorityDefaults.class) - .getIfUnique(); - if (grantedAuthorityDefaults != null) { - this.rolePrefix = grantedAuthorityDefaults.getRolePrefix(); - } - else { - this.rolePrefix = "ROLE_"; - } - this.REGISTRY = new ExpressionInterceptUrlRegistry(context); - } - - public ExpressionInterceptUrlRegistry getRegistry() { - return this.REGISTRY; - } - - /** - * Allows registering multiple {@link RequestMatcher} instances to a collection of - * {@link ConfigAttribute} instances - * @param requestMatchers the {@link RequestMatcher} instances to register to the - * {@link ConfigAttribute} instances - * @param configAttributes the {@link ConfigAttribute} to be mapped by the - * {@link RequestMatcher} instances - */ - private void interceptUrl(Iterable requestMatchers, - Collection configAttributes) { - for (RequestMatcher requestMatcher : requestMatchers) { - this.REGISTRY.addMapping( - new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(requestMatcher, configAttributes)); - } - } - - @Override - @SuppressWarnings("rawtypes") - List> getDecisionVoters(H http) { - List> decisionVoters = new ArrayList<>(); - WebExpressionVoter expressionVoter = new WebExpressionVoter(); - expressionVoter.setExpressionHandler(getExpressionHandler(http)); - decisionVoters.add(expressionVoter); - return decisionVoters; - } - - @Override - ExpressionBasedFilterInvocationSecurityMetadataSource createMetadataSource(H http) { - LinkedHashMap> requestMap = this.REGISTRY.createRequestMap(); - Assert.state(!requestMap.isEmpty(), - "At least one mapping is required (i.e. authorizeRequests().anyRequest().authenticated())"); - return new ExpressionBasedFilterInvocationSecurityMetadataSource(requestMap, getExpressionHandler(http)); - } - - private SecurityExpressionHandler getExpressionHandler(H http) { - if (this.expressionHandler != null) { - return this.expressionHandler; - } - DefaultWebSecurityExpressionHandler defaultHandler = new DefaultWebSecurityExpressionHandler(); - AuthenticationTrustResolver trustResolver = http.getSharedObject(AuthenticationTrustResolver.class); - if (trustResolver != null) { - defaultHandler.setTrustResolver(trustResolver); - } - ApplicationContext context = http.getSharedObject(ApplicationContext.class); - if (context != null) { - context.getBeanProvider(RoleHierarchy.class).ifUnique(defaultHandler::setRoleHierarchy); - context.getBeanProvider(GrantedAuthorityDefaults.class) - .ifUnique((grantedAuthorityDefaults) -> defaultHandler - .setDefaultRolePrefix(grantedAuthorityDefaults.getRolePrefix())); - context.getBeanProvider(PermissionEvaluator.class).ifUnique(defaultHandler::setPermissionEvaluator); - } - this.expressionHandler = postProcess(defaultHandler); - return this.expressionHandler; - } - - private static String hasAnyRole(String rolePrefix, String... authorities) { - String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','" + rolePrefix); - return "hasAnyRole('" + rolePrefix + anyAuthorities + "')"; - } - - private static String hasRole(String rolePrefix, String role) { - Assert.notNull(role, "role cannot be null"); - Assert.isTrue(rolePrefix.isEmpty() || !role.startsWith(rolePrefix), () -> "role should not start with '" - + rolePrefix + "' since it is automatically inserted. Got '" + role + "'"); - return "hasRole('" + rolePrefix + role + "')"; - } - - private static String hasAuthority(String authority) { - return "hasAuthority('" + authority + "')"; - } - - private static String hasAnyAuthority(String... authorities) { - String anyAuthorities = StringUtils.arrayToDelimitedString(authorities, "','"); - return "hasAnyAuthority('" + anyAuthorities + "')"; - } - - private static String hasIpAddress(String ipAddressExpression) { - return "hasIpAddress('" + ipAddressExpression + "')"; - } - - @Deprecated - public final class ExpressionInterceptUrlRegistry extends - ExpressionUrlAuthorizationConfigurer.AbstractInterceptUrlRegistry { - - private ExpressionInterceptUrlRegistry(ApplicationContext context) { - setApplicationContext(context); - } - - @Override - protected AuthorizedUrl chainRequestMatchersInternal(List requestMatchers) { - return new AuthorizedUrl(requestMatchers); - } - - /** - * Allows customization of the {@link SecurityExpressionHandler} to be used. The - * default is {@link DefaultWebSecurityExpressionHandler} - * @param expressionHandler the {@link SecurityExpressionHandler} to be used - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization. - */ - public ExpressionInterceptUrlRegistry expressionHandler( - SecurityExpressionHandler expressionHandler) { - ExpressionUrlAuthorizationConfigurer.this.expressionHandler = expressionHandler; - return this; - } - - /** - * Adds an {@link ObjectPostProcessor} for this class. - * @param objectPostProcessor - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customizations - */ - public ExpressionInterceptUrlRegistry withObjectPostProcessor(ObjectPostProcessor objectPostProcessor) { - addObjectPostProcessor(objectPostProcessor); - return this; - } - - public H and() { - return ExpressionUrlAuthorizationConfigurer.this.getBuilder(); - } - - } - - public class AuthorizedUrl { - - private List requestMatchers; - - private boolean not; - - /** - * Creates a new instance - * @param requestMatchers the {@link RequestMatcher} instances to map - */ - AuthorizedUrl(List requestMatchers) { - this.requestMatchers = requestMatchers; - } - - protected List getMatchers() { - return this.requestMatchers; - } - - /** - * Negates the following expression. - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization - */ - public AuthorizedUrl not() { - this.not = true; - return this; - } - - /** - * Shortcut for specifying URLs require a particular role. If you do not want to - * have role prefix (default "ROLE_") automatically inserted see - * {@link #hasAuthority(String)}. - * @param role the role to require (i.e. USER, ADMIN, etc). Note, it should not - * start with role prefix as this is automatically inserted. - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization - */ - public ExpressionInterceptUrlRegistry hasRole(String role) { - return access(ExpressionUrlAuthorizationConfigurer - .hasRole(ExpressionUrlAuthorizationConfigurer.this.rolePrefix, role)); - } - - /** - * Shortcut for specifying URLs require any of a number of roles. If you do not - * want to have role prefix (default "ROLE_") automatically inserted see - * {@link #hasAnyAuthority(String...)} - * @param roles the roles to require (i.e. USER, ADMIN, etc). Note, it should not - * start with role prefix as this is automatically inserted. - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization - */ - public ExpressionInterceptUrlRegistry hasAnyRole(String... roles) { - return access(ExpressionUrlAuthorizationConfigurer - .hasAnyRole(ExpressionUrlAuthorizationConfigurer.this.rolePrefix, roles)); - } - - /** - * Specify that URLs require a particular authority. - * @param authority the authority to require (i.e. ROLE_USER, ROLE_ADMIN, etc). - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization - */ - public ExpressionInterceptUrlRegistry hasAuthority(String authority) { - return access(ExpressionUrlAuthorizationConfigurer.hasAuthority(authority)); - } - - /** - * Specify that URLs requires any of a number authorities. - * @param authorities the requests require at least one of the authorities (i.e. - * "ROLE_USER","ROLE_ADMIN" would mean either "ROLE_USER" or "ROLE_ADMIN" is - * required). - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization - */ - public ExpressionInterceptUrlRegistry hasAnyAuthority(String... authorities) { - return access(ExpressionUrlAuthorizationConfigurer.hasAnyAuthority(authorities)); - } - - /** - * Specify that URLs requires a specific IP Address or subnet. - * @param ipaddressExpression the ipaddress (i.e. 192.168.1.79) or local subnet - * (i.e. 192.168.0/24) - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization - */ - public ExpressionInterceptUrlRegistry hasIpAddress(String ipaddressExpression) { - return access(ExpressionUrlAuthorizationConfigurer.hasIpAddress(ipaddressExpression)); - } - - /** - * Specify that URLs are allowed by anyone. - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization - */ - public ExpressionInterceptUrlRegistry permitAll() { - return access(permitAll); - } - - /** - * Specify that URLs are allowed by anonymous users. - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization - */ - public ExpressionInterceptUrlRegistry anonymous() { - return access(anonymous); - } - - /** - * Specify that URLs are allowed by users that have been remembered. - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization - * @see RememberMeConfigurer - */ - public ExpressionInterceptUrlRegistry rememberMe() { - return access(rememberMe); - } - - /** - * Specify that URLs are not allowed by anyone. - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization - */ - public ExpressionInterceptUrlRegistry denyAll() { - return access(denyAll); - } - - /** - * Specify that URLs are allowed by any authenticated user. - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization - */ - public ExpressionInterceptUrlRegistry authenticated() { - return access(authenticated); - } - - /** - * Specify that URLs are allowed by users who have authenticated and were not - * "remembered". - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization - * @see RememberMeConfigurer - */ - public ExpressionInterceptUrlRegistry fullyAuthenticated() { - return access(fullyAuthenticated); - } - - /** - * Allows specifying that URLs are secured by an arbitrary expression - * @param attribute the expression to secure the URLs (i.e. "hasRole('ROLE_USER') - * and hasRole('ROLE_SUPER')") - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customization - */ - public ExpressionInterceptUrlRegistry access(String attribute) { - if (this.not) { - attribute = "!" + attribute; - } - interceptUrl(this.requestMatchers, SecurityConfig.createList(attribute)); - return ExpressionUrlAuthorizationConfigurer.this.REGISTRY; - } - - } - -} diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupport.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupport.java index a9f283a42e..b25ec8bd04 100644 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupport.java +++ b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupport.java @@ -18,10 +18,8 @@ package org.springframework.security.config.annotation.web.configurers; import jakarta.servlet.http.HttpServletRequest; -import org.springframework.security.access.SecurityConfig; import org.springframework.security.authorization.SingleResultAuthorizationManager; import org.springframework.security.config.annotation.web.HttpSecurityBuilder; -import org.springframework.security.config.annotation.web.configurers.AbstractConfigAttributeRequestMatcherRegistry.UrlMapping; import org.springframework.security.web.util.matcher.RequestMatcher; import org.springframework.util.Assert; @@ -47,25 +45,14 @@ final class PermitAllSupport { @SuppressWarnings("unchecked") static void permitAll(HttpSecurityBuilder> http, RequestMatcher... requestMatchers) { - ExpressionUrlAuthorizationConfigurer configurer = http - .getConfigurer(ExpressionUrlAuthorizationConfigurer.class); AuthorizeHttpRequestsConfigurer httpConfigurer = http.getConfigurer(AuthorizeHttpRequestsConfigurer.class); - boolean oneConfigurerPresent = configurer == null ^ httpConfigurer == null; - Assert.state(oneConfigurerPresent, - "permitAll only works with either HttpSecurity.authorizeRequests() or HttpSecurity.authorizeHttpRequests(). " - + "Please define one or the other but not both."); + Assert.state(httpConfigurer != null, + "permitAll only works with HttpSecurity.authorizeHttpRequests(). Please define one."); for (RequestMatcher matcher : requestMatchers) { if (matcher != null) { - if (configurer != null) { - configurer.getRegistry() - .addMapping(0, new UrlMapping(matcher, - SecurityConfig.createList(ExpressionUrlAuthorizationConfigurer.permitAll))); - } - else { - httpConfigurer.addFirst(matcher, SingleResultAuthorizationManager.permitAll()); - } + httpConfigurer.addFirst(matcher, SingleResultAuthorizationManager.permitAll()); } } } diff --git a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurer.java b/config/src/main/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurer.java deleted file mode 100644 index cf7cf4d823..0000000000 --- a/config/src/main/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurer.java +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright 2002-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.web.configurers; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import org.springframework.context.ApplicationContext; -import org.springframework.http.HttpMethod; -import org.springframework.security.access.AccessDecisionManager; -import org.springframework.security.access.AccessDecisionVoter; -import org.springframework.security.access.ConfigAttribute; -import org.springframework.security.access.SecurityConfig; -import org.springframework.security.access.vote.AuthenticatedVoter; -import org.springframework.security.access.vote.RoleVoter; -import org.springframework.security.config.ObjectPostProcessor; -import org.springframework.security.config.annotation.web.HttpSecurityBuilder; -import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource; -import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; -import org.springframework.security.web.util.matcher.RequestMatcher; -import org.springframework.util.Assert; - -/** - * Adds URL based authorization using - * {@link DefaultFilterInvocationSecurityMetadataSource}. At least one - * {@link org.springframework.web.bind.annotation.RequestMapping} needs to be mapped to - * {@link ConfigAttribute}'s for this {@link SecurityContextConfigurer} to have meaning. - *

Security Filters

- * - *

- * Usage includes applying the {@link UrlAuthorizationConfigurer} and then modifying the - * StandardInterceptUrlRegistry. For example: - *

- * - *
- * @Bean
- * public SecurityFilterChain filterChain(HttpSecurity http, ApplicationContext context) throws Exception {
- * 	http.apply(new UrlAuthorizationConfigurer<HttpSecurity>(context)).getRegistry()
- * 			.requestMatchers("/users**", "/sessions/**").hasRole("USER")
- * 			.requestMatchers("/signup").hasRole("ANONYMOUS").anyRequest().hasRole("USER");
- * }
- * 
- * - * The following Filters are populated - * - *
    - *
  • - * {@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}
  • - *
- * - *

Shared Objects Created

- * - * The following shared objects are populated to allow other - * {@link org.springframework.security.config.annotation.SecurityConfigurer}'s to - * customize: - *
    - *
  • - * {@link org.springframework.security.web.access.intercept.FilterSecurityInterceptor}
  • - *
- * - *

Shared Objects Used

- * - * The following shared objects are used: - * - *
    - *
  • AuthenticationManager
  • - *
- * - * @param the type of {@link HttpSecurityBuilder} that is being configured - * @author Rob Winch - * @since 3.2 - * @see ExpressionUrlAuthorizationConfigurer - * @deprecated Use {@link AuthorizeHttpRequestsConfigurer} instead - */ -@Deprecated -public final class UrlAuthorizationConfigurer> - extends AbstractInterceptUrlConfigurer, H> { - - private final StandardInterceptUrlRegistry registry; - - public UrlAuthorizationConfigurer(ApplicationContext context) { - this.registry = new StandardInterceptUrlRegistry(context); - } - - /** - * The StandardInterceptUrlRegistry is what users will interact with after applying - * the {@link UrlAuthorizationConfigurer}. - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further customizations - */ - public StandardInterceptUrlRegistry getRegistry() { - return this.registry; - } - - /** - * Adds an {@link ObjectPostProcessor} for this class. - * @param objectPostProcessor - * @return the {@link UrlAuthorizationConfigurer} for further customizations - */ - @Override - public UrlAuthorizationConfigurer withObjectPostProcessor(ObjectPostProcessor objectPostProcessor) { - addObjectPostProcessor(objectPostProcessor); - return this; - } - - /** - * Creates the default {@link AccessDecisionVoter} instances used if an - * {@link AccessDecisionManager} was not specified. - * @param http the builder to use - */ - @Override - @SuppressWarnings("rawtypes") - List> getDecisionVoters(H http) { - List> decisionVoters = new ArrayList<>(); - decisionVoters.add(new RoleVoter()); - decisionVoters.add(new AuthenticatedVoter()); - return decisionVoters; - } - - /** - * Creates the {@link FilterInvocationSecurityMetadataSource} to use. The - * implementation is a {@link DefaultFilterInvocationSecurityMetadataSource}. - * @param http the builder to use - */ - @Override - FilterInvocationSecurityMetadataSource createMetadataSource(H http) { - return new DefaultFilterInvocationSecurityMetadataSource(this.registry.createRequestMap()); - } - - /** - * Adds a mapping of the {@link RequestMatcher} instances to the - * {@link ConfigAttribute} instances. - * @param requestMatchers the {@link RequestMatcher} instances that should map to the - * provided {@link ConfigAttribute} instances - * @param configAttributes the {@link ConfigAttribute} instances that should be mapped - * by the {@link RequestMatcher} instances - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further customizations - */ - private StandardInterceptUrlRegistry addMapping(Iterable requestMatchers, - Collection configAttributes) { - for (RequestMatcher requestMatcher : requestMatchers) { - this.registry.addMapping( - new AbstractConfigAttributeRequestMatcherRegistry.UrlMapping(requestMatcher, configAttributes)); - } - return this.registry; - } - - /** - * Creates a String for specifying a user requires a role. - * @param role the role that should be required which is prepended with ROLE_ - * automatically (i.e. USER, ADMIN, etc). It should not start with ROLE_ - * @return the {@link ConfigAttribute} expressed as a String - */ - private static String hasRole(String role) { - Assert.isTrue(!role.startsWith("ROLE_"), () -> role - + " should not start with ROLE_ since ROLE_ is automatically prepended when using hasRole. Consider using hasAuthority or access instead."); - return "ROLE_" + role; - } - - /** - * Creates a String for specifying that a user requires one of many roles. - * @param roles the roles that the user should have at least one of (i.e. ADMIN, USER, - * etc). Each role should not start with ROLE_ since it is automatically prepended - * already. - * @return the {@link ConfigAttribute} expressed as a String - */ - private static String[] hasAnyRole(String... roles) { - for (int i = 0; i < roles.length; i++) { - roles[i] = "ROLE_" + roles[i]; - } - return roles; - } - - /** - * Creates a String for specifying that a user requires one of many authorities - * @param authorities the authorities that the user should have at least one of (i.e. - * ROLE_USER, ROLE_ADMIN, etc). - * @return the {@link ConfigAttribute} expressed as a String. - */ - private static String[] hasAnyAuthority(String... authorities) { - return authorities; - } - - @Deprecated - public final class StandardInterceptUrlRegistry extends - UrlAuthorizationConfigurer.AbstractInterceptUrlRegistry { - - private StandardInterceptUrlRegistry(ApplicationContext context) { - setApplicationContext(context); - } - - @Override - public AuthorizedUrl requestMatchers(String... patterns) { - return super.requestMatchers(patterns); - } - - @Override - public AuthorizedUrl requestMatchers(HttpMethod method, String... patterns) { - return super.requestMatchers(method, patterns); - } - - @Override - public AuthorizedUrl requestMatchers(HttpMethod method) { - return super.requestMatchers(method); - } - - @Override - public AuthorizedUrl requestMatchers(RequestMatcher... requestMatchers) { - return super.requestMatchers(requestMatchers); - } - - @Override - protected AuthorizedUrl chainRequestMatchersInternal(List requestMatchers) { - return new AuthorizedUrl(requestMatchers); - } - - /** - * Adds an {@link ObjectPostProcessor} for this class. - * @param objectPostProcessor - * @return the {@link ExpressionUrlAuthorizationConfigurer} for further - * customizations - */ - public StandardInterceptUrlRegistry withObjectPostProcessor(ObjectPostProcessor objectPostProcessor) { - addObjectPostProcessor(objectPostProcessor); - return this; - } - - public H and() { - return UrlAuthorizationConfigurer.this.getBuilder(); - } - - } - - /** - * Maps the specified {@link RequestMatcher} instances to {@link ConfigAttribute} - * instances. - * - * @author Rob Winch - * @since 3.2 - */ - public class AuthorizedUrl { - - private final List requestMatchers; - - /** - * Creates a new instance - * @param requestMatchers the {@link RequestMatcher} instances to map to some - * {@link ConfigAttribute} instances. - */ - AuthorizedUrl(List requestMatchers) { - Assert.notEmpty(requestMatchers, "requestMatchers must contain at least one value"); - this.requestMatchers = requestMatchers; - } - - /** - * Specifies a user requires a role. - * @param role the role that should be required which is prepended with ROLE_ - * automatically (i.e. USER, ADMIN, etc). It should not start with ROLE_ the - * {@link UrlAuthorizationConfigurer} for further customization - */ - public StandardInterceptUrlRegistry hasRole(String role) { - return access(UrlAuthorizationConfigurer.hasRole(role)); - } - - /** - * Specifies that a user requires one of many roles. - * @param roles the roles that the user should have at least one of (i.e. ADMIN, - * USER, etc). Each role should not start with ROLE_ since it is automatically - * prepended already. - * @return the {@link UrlAuthorizationConfigurer} for further customization - */ - public StandardInterceptUrlRegistry hasAnyRole(String... roles) { - return access(UrlAuthorizationConfigurer.hasAnyRole(roles)); - } - - /** - * Specifies a user requires an authority. - * @param authority the authority that should be required - * @return the {@link UrlAuthorizationConfigurer} for further customization - */ - public StandardInterceptUrlRegistry hasAuthority(String authority) { - return access(authority); - } - - /** - * Specifies that a user requires one of many authorities - * @param authorities the authorities that the user should have at least one of - * (i.e. ROLE_USER, ROLE_ADMIN, etc). - * @return the {@link UrlAuthorizationConfigurer} for further customization - */ - public StandardInterceptUrlRegistry hasAnyAuthority(String... authorities) { - return access(UrlAuthorizationConfigurer.hasAnyAuthority(authorities)); - } - - /** - * Specifies that an anonymous user is allowed access - * @return the {@link UrlAuthorizationConfigurer} for further customization - */ - public StandardInterceptUrlRegistry anonymous() { - return hasRole("ANONYMOUS"); - } - - /** - * Specifies that the user must have the specified {@link ConfigAttribute}'s - * @param attributes the {@link ConfigAttribute}'s that restrict access to a URL - * @return the {@link UrlAuthorizationConfigurer} for further customization - */ - public StandardInterceptUrlRegistry access(String... attributes) { - addMapping(this.requestMatchers, SecurityConfig.createList(attributes)); - return UrlAuthorizationConfigurer.this.registry; - } - - protected List getMatchers() { - return this.requestMatchers; - } - - } - -} diff --git a/config/src/main/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDsl.kt b/config/src/main/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDsl.kt deleted file mode 100644 index 2620ccbe82..0000000000 --- a/config/src/main/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDsl.kt +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.web - -import org.springframework.http.HttpMethod -import org.springframework.security.config.annotation.web.builders.HttpSecurity -import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer -import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher -import org.springframework.security.web.util.matcher.AnyRequestMatcher -import org.springframework.security.web.util.matcher.RequestMatcher - -/** - * A Kotlin DSL to configure [HttpSecurity] request authorization using idiomatic Kotlin code. - * - * @author Eleftheria Stein - * @since 5.3 - */ -class AuthorizeRequestsDsl : AbstractRequestMatcherDsl() { - private val authorizationRules = mutableListOf() - private val PATTERN_TYPE = PatternType.PATH; - - /** - * Adds a request authorization rule. - * - * @param matches the [RequestMatcher] to match incoming requests against - * @param access the SpEL expression to secure the matching request - * (i.e. "hasAuthority('ROLE_USER') and hasAuthority('ROLE_SUPER')") - */ - fun authorize(matches: RequestMatcher = AnyRequestMatcher.INSTANCE, - access: String) { - authorizationRules.add(MatcherAuthorizationRule(matches, access)) - } - - /** - * Adds a request authorization rule for an endpoint matching the provided - * pattern. - * If Spring MVC is on the classpath, it will use an MVC matcher. - * If Spring MVC is not on the classpath, it will use an ant matcher. - * The MVC will use the same rules that Spring MVC uses for matching. - * For example, often times a mapping of the path "/path" will match on - * "/path", "/path/", "/path.html", etc. - * If the current request will not be processed by Spring MVC, a reasonable default - * using the pattern as an ant pattern will be used. - * - * @param pattern the pattern to match incoming requests against. - * @param access the SpEL expression to secure the matching request - * (i.e. "hasAuthority('ROLE_USER') and hasAuthority('ROLE_SUPER')") - */ - fun authorize(pattern: String, access: String) { - authorizationRules.add(PatternAuthorizationRule(pattern = pattern, - patternType = PATTERN_TYPE, - rule = access)) - } - - /** - * Adds a request authorization rule for an endpoint matching the provided - * pattern. - * If Spring MVC is on the classpath, it will use an MVC matcher. - * If Spring MVC is not on the classpath, it will use an ant matcher. - * The MVC will use the same rules that Spring MVC uses for matching. - * For example, often times a mapping of the path "/path" will match on - * "/path", "/path/", "/path.html", etc. - * If the current request will not be processed by Spring MVC, a reasonable default - * using the pattern as an ant pattern will be used. - * - * @param method the HTTP method to match the income requests against. - * @param pattern the pattern to match incoming requests against. - * @param access the SpEL expression to secure the matching request - * (i.e. "hasAuthority('ROLE_USER') and hasAuthority('ROLE_SUPER')") - */ - fun authorize(method: HttpMethod, pattern: String, access: String) { - authorizationRules.add(PatternAuthorizationRule(pattern = pattern, - patternType = PATTERN_TYPE, - httpMethod = method, - rule = access)) - } - - /** - * Adds a request authorization rule for an endpoint matching the provided - * pattern. - * If Spring MVC is on the classpath, it will use an MVC matcher. - * If Spring MVC is not on the classpath, it will use an ant matcher. - * The MVC will use the same rules that Spring MVC uses for matching. - * For example, often times a mapping of the path "/path" will match on - * "/path", "/path/", "/path.html", etc. - * If the current request will not be processed by Spring MVC, a reasonable default - * using the pattern as an ant pattern will be used. - * - * @param pattern the pattern to match incoming requests against. - * @param servletPath the servlet path to match incoming requests against. This - * only applies when using an MVC pattern matcher. - * @param access the SpEL expression to secure the matching request - * (i.e. "hasAuthority('ROLE_USER') and hasAuthority('ROLE_SUPER')") - */ - fun authorize(pattern: String, servletPath: String, access: String) { - authorizationRules.add(PatternAuthorizationRule(pattern = pattern, - patternType = PATTERN_TYPE, - servletPath = servletPath, - rule = access)) - } - - /** - * Adds a request authorization rule for an endpoint matching the provided - * pattern. - * If Spring MVC is on the classpath, it will use an MVC matcher. - * If Spring MVC is not on the classpath, it will use an ant matcher. - * The MVC will use the same rules that Spring MVC uses for matching. - * For example, often times a mapping of the path "/path" will match on - * "/path", "/path/", "/path.html", etc. - * If the current request will not be processed by Spring MVC, a reasonable default - * using the pattern as an ant pattern will be used. - * - * @param method the HTTP method to match the income requests against. - * @param pattern the pattern to match incoming requests against. - * @param servletPath the servlet path to match incoming requests against. This - * only applies when using an MVC pattern matcher. - * @param access the SpEL expression to secure the matching request - * (i.e. "hasAuthority('ROLE_USER') and hasAuthority('ROLE_SUPER')") - */ - fun authorize(method: HttpMethod, pattern: String, servletPath: String, access: String) { - authorizationRules.add(PatternAuthorizationRule(pattern = pattern, - patternType = PATTERN_TYPE, - servletPath = servletPath, - httpMethod = method, - rule = access)) - } - - /** - * Specify that URLs require a particular authority. - * - * @param authority the authority to require (i.e. ROLE_USER, ROLE_ADMIN, etc). - * @return the SpEL expression "hasAuthority" with the given authority as a - * parameter - */ - fun hasAuthority(authority: String) = "hasAuthority('$authority')" - - /** - * Specify that URLs require any number of authorities. - * - * @param authorities the authorities to require (i.e. ROLE_USER, ROLE_ADMIN, etc). - * @return the SpEL expression "hasAnyAuthority" with the given authorities as a - * parameter - */ - fun hasAnyAuthority(vararg authorities: String): String { - val anyAuthorities = authorities.joinToString("','") - return "hasAnyAuthority('$anyAuthorities')" - } - - /** - * Specify that URLs require a particular role. - * - * @param role the role to require (i.e. USER, ADMIN, etc). - * @return the SpEL expression "hasRole" with the given role as a - * parameter - */ - fun hasRole(role: String) = "hasRole('$role')" - - /** - * Specify that URLs require any number of roles. - * - * @param roles the roles to require (i.e. USER, ADMIN, etc). - * @return the SpEL expression "hasAnyRole" with the given roles as a - * parameter - */ - fun hasAnyRole(vararg roles: String): String { - val anyRoles = roles.joinToString("','") - return "hasAnyRole('$anyRoles')" - } - - /** - * Specify that URLs are allowed by anyone. - */ - val permitAll = "permitAll" - - /** - * Specify that URLs are allowed by anonymous users. - */ - val anonymous = "anonymous" - - /** - * Specify that URLs are allowed by users that have been remembered. - */ - val rememberMe = "rememberMe" - - /** - * Specify that URLs are not allowed by anyone. - */ - val denyAll = "denyAll" - - /** - * Specify that URLs are allowed by any authenticated user. - */ - val authenticated = "authenticated" - - /** - * Specify that URLs are allowed by users who have authenticated and were not - * "remembered". - */ - val fullyAuthenticated = "fullyAuthenticated" - - internal fun get(): (ExpressionUrlAuthorizationConfigurer.ExpressionInterceptUrlRegistry) -> Unit { - return { requests -> - authorizationRules.forEach { rule -> - when (rule) { - is MatcherAuthorizationRule -> requests.requestMatchers(rule.matcher).access(rule.rule) - is PatternAuthorizationRule -> { - var builder = requests.applicationContext.getBeanProvider( - PathPatternRequestMatcher.Builder::class.java) - .getIfUnique(PathPatternRequestMatcher::withDefaults); - if (rule.servletPath != null) { - builder = builder.basePath(rule.servletPath) - } - requests.requestMatchers(builder.matcher(rule.httpMethod, rule.pattern)).access(rule.rule) - } - } - } - } - } -} - diff --git a/config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt b/config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt index 8b9ccb4caa..8c35f1aeb2 100644 --- a/config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt +++ b/config/src/main/kotlin/org/springframework/security/config/annotation/web/HttpSecurityDsl.kt @@ -241,39 +241,6 @@ class HttpSecurityDsl(private val http: HttpSecurity, private val init: HttpSecu this.http.formLogin(loginCustomizer) } - /** - * Allows restricting access based upon the [HttpServletRequest] - * - * Example: - * - * ``` - * @Configuration - * @EnableWebSecurity - * class SecurityConfig { - * - * @Bean - * fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { - * http { - * authorizeRequests { - * authorize("/public", permitAll) - * authorize(anyRequest, authenticated) - * } - * } - * return http.build() - * } - * } - * ``` - * - * @param authorizeRequestsConfiguration custom configuration that specifies - * access for requests - * @see [AuthorizeRequestsDsl] - */ - @Deprecated(message = "Since 6.4. Use authorizeHttpRequests instead") - fun authorizeRequests(authorizeRequestsConfiguration: AuthorizeRequestsDsl.() -> Unit) { - val authorizeRequestsCustomizer = AuthorizeRequestsDsl().apply(authorizeRequestsConfiguration).get() - this.http.authorizeRequests(authorizeRequestsCustomizer) - } - /** * Allows restricting access based upon the [HttpServletRequest] * diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java deleted file mode 100644 index 1314cb4404..0000000000 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/AuthorizeRequestsTests.java +++ /dev/null @@ -1,561 +0,0 @@ -/* - * Copyright 2002-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.web.configurers; - -import jakarta.servlet.http.HttpServletResponse; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.http.HttpMethod; -import org.springframework.mock.web.MockFilterChain; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.security.access.hierarchicalroles.RoleHierarchy; -import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl; -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.context.SecurityContext; -import org.springframework.security.core.context.SecurityContextImpl; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; -import org.springframework.security.web.FilterChainProxy; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager; -import org.springframework.security.web.context.HttpSessionSecurityContextRepository; -import org.springframework.security.web.servlet.MockServletContext; -import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.util.pattern.PathPatternParser; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.spy; -import static org.springframework.security.config.Customizer.withDefaults; -import static org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher.pathPattern; - -/** - * @author Rob Winch - * - */ -public class AuthorizeRequestsTests { - - AnnotationConfigWebApplicationContext context; - - MockHttpServletRequest request; - - MockHttpServletResponse response; - - MockFilterChain chain; - - MockServletContext servletContext; - - @Autowired - FilterChainProxy springSecurityFilterChain; - - @BeforeEach - public void setup() { - this.servletContext = spy(MockServletContext.mvc()); - this.request = new MockHttpServletRequest(this.servletContext, "GET", ""); - this.response = new MockHttpServletResponse(); - this.chain = new MockFilterChain(); - } - - @AfterEach - public void cleanup() { - if (this.context != null) { - this.context.close(); - } - } - - // SEC-3135 - @Test - public void antMatchersMethodAndNoPatterns() throws Exception { - loadConfig(AntMatchersNoPatternsConfig.class); - this.request.setMethod("POST"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN); - } - - @Test - public void postWhenPostDenyAllInLambdaThenRespondsWithForbidden() throws Exception { - loadConfig(AntMatchersNoPatternsInLambdaConfig.class); - this.request.setMethod("POST"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN); - } - - // SEC-2256 - @Test - public void antMatchersPathVariables() throws Exception { - loadConfig(AntPatchersPathVariables.class); - this.request.setServletPath("/user/user"); - this.request.setRequestURI("/user/user"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - this.setup(); - this.request.setServletPath("/user/deny"); - this.request.setRequestURI("/user/deny"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN); - } - - // SEC-2256 - @Test - public void antMatchersPathVariablesCaseInsensitive() throws Exception { - loadConfig(AntPatchersPathVariables.class); - this.request.setRequestURI("/USER/user"); - this.request.setServletPath("/USER/user"); - this.request.setRequestURI("/USER/user"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - this.setup(); - this.request.setRequestURI("/USER/deny"); - this.request.setServletPath("/USER/deny"); - this.request.setRequestURI("/USER/deny"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN); - } - - // gh-3786 - @Test - public void antMatchersPathVariablesCaseInsensitiveCamelCaseVariables() throws Exception { - loadConfig(AntMatchersPathVariablesCamelCaseVariables.class); - this.request.setServletPath("/USER/user"); - this.request.setRequestURI("/USER/user"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - this.setup(); - this.request.setServletPath("/USER/deny"); - this.request.setRequestURI("/USER/deny"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN); - } - - // gh-3394 - @Test - public void roleHiearchy() throws Exception { - loadConfig(RoleHiearchyConfig.class); - SecurityContext securityContext = new SecurityContextImpl(); - securityContext.setAuthentication(UsernamePasswordAuthenticationToken.authenticated("test", "notused", - AuthorityUtils.createAuthorityList("ROLE_USER"))); - this.request.getSession() - .setAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, securityContext); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - } - - @Test - public void mvcMatcherPathVariables() throws Exception { - loadConfig(MvcMatcherPathVariablesConfig.class); - this.request.setRequestURI("/user/user"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - this.setup(); - this.request.setRequestURI("/user/deny"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - } - - @Test - public void requestWhenMvcMatcherPathVariablesThenMatchesOnPathVariables() throws Exception { - loadConfig(MvcMatcherPathVariablesInLambdaConfig.class); - this.request.setRequestURI("/user/user"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - this.setup(); - this.request.setRequestURI("/user/deny"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_UNAUTHORIZED); - } - - public void loadConfig(Class... configs) { - this.context = new AnnotationConfigWebApplicationContext(); - this.context.register(configs); - this.context.setServletContext(this.servletContext); - this.context.refresh(); - this.context.getAutowireCapableBeanFactory().autowireBean(this); - } - - @EnableWebSecurity - @Configuration - static class AntMatchersNoPatternsConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .requestMatchers(pathPattern(HttpMethod.POST, "/**")).denyAll()); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(); - } - - } - - @EnableWebSecurity - @Configuration - static class AntMatchersNoPatternsInLambdaConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((authorize) -> authorize - .requestMatchers(pathPattern(HttpMethod.POST, "/**")).denyAll() - ); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(); - } - - } - - @EnableWebSecurity - @Configuration - static class AntPatchersPathVariables { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - PathPatternParser parser = new PathPatternParser(); - parser.setCaseSensitive(false); - PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withPathPatternParser(parser); - WebExpressionAuthorizationManager authz = new WebExpressionAuthorizationManager("#user == 'user'"); - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .requestMatchers(builder.matcher("/user/{user}")).access(authz) - .anyRequest().denyAll()); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(); - } - - } - - @EnableWebSecurity - @Configuration - static class AntMatchersPathVariablesCamelCaseVariables { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - PathPatternParser parser = new PathPatternParser(); - parser.setCaseSensitive(false); - PathPatternRequestMatcher.Builder builder = PathPatternRequestMatcher.withPathPatternParser(parser); - WebExpressionAuthorizationManager authz = new WebExpressionAuthorizationManager("#userName == 'user'"); - - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .requestMatchers(builder.matcher("/user/{userName}")).access(authz) - .anyRequest().denyAll()); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(); - } - - } - - @EnableWebSecurity - @Configuration - static class RoleHiearchyConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .anyRequest().hasRole("ADMIN")); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(); - } - - @Bean - RoleHierarchy roleHiearchy() { - return RoleHierarchyImpl.fromHierarchy("ROLE_USER > ROLE_ADMIN"); - } - - } - - @EnableWebSecurity - @Configuration - @EnableWebMvc - static class MvcMatcherConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .requestMatchers("/path").denyAll()); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(); - } - - @RestController - static class PathController { - - @RequestMapping("/path") - String path() { - return "path"; - } - - } - - } - - @EnableWebSecurity - @Configuration - @EnableWebMvc - static class MvcMatcherInLambdaConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((authorize) -> authorize - .requestMatchers("/path").denyAll() - ); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(); - } - - @RestController - static class PathController { - - @RequestMapping("/path") - String path() { - return "path"; - } - - } - - } - - @EnableWebSecurity - @Configuration - @EnableWebMvc - static class MvcMatcherServletPathConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { - PathPatternRequestMatcher.Builder spring = builder.basePath("/spring"); - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .requestMatchers(spring.matcher("/path")).denyAll()); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(); - } - - @RestController - static class PathController { - - @RequestMapping("/path") - String path() { - return "path"; - } - - } - - } - - @EnableWebSecurity - @Configuration - @EnableWebMvc - static class MvcMatcherServletPathInLambdaConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http, PathPatternRequestMatcher.Builder builder) throws Exception { - PathPatternRequestMatcher.Builder spring = builder.basePath("/spring"); - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((authorize) -> authorize - .requestMatchers(spring.matcher("/path")).denyAll() - ); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(); - } - - @RestController - static class PathController { - - @RequestMapping("/path") - String path() { - return "path"; - } - - } - - } - - @EnableWebSecurity - @Configuration - @EnableWebMvc - static class MvcMatcherPathVariablesConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - WebExpressionAuthorizationManager authz = new WebExpressionAuthorizationManager("#userName == 'user'"); - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .requestMatchers("/user/{userName}").access(authz)); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(); - } - - @RestController - static class PathController { - - @RequestMapping("/path") - String path() { - return "path"; - } - - } - - } - - @EnableWebSecurity - @Configuration - @EnableWebMvc - static class MvcMatcherPathVariablesInLambdaConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - WebExpressionAuthorizationManager authz = new WebExpressionAuthorizationManager("#userName == 'user'"); - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((authorize) -> authorize - .requestMatchers("/user/{userName}").access(authz) - ); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(); - } - - @RestController - static class PathController { - - @RequestMapping("/path") - String path() { - return "path"; - } - - } - - } - - @EnableWebSecurity - @Configuration - @EnableWebMvc - static class MvcMatcherPathServletPathRequiredConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .requestMatchers("/user").denyAll()); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(); - } - - @RestController - static class PathController { - - @RequestMapping("/path") - String path() { - return "path"; - } - - } - - } - -} diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurerTests.java deleted file mode 100644 index 05b7043292..0000000000 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/ExpressionUrlAuthorizationConfigurerTests.java +++ /dev/null @@ -1,1197 +0,0 @@ -/* - * Copyright 2002-2025 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.web.configurers; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.function.Supplier; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; - -import org.springframework.beans.factory.BeanCreationException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationEventPublisher; -import org.springframework.context.ApplicationListener; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.expression.EvaluationContext; -import org.springframework.expression.spel.support.StandardEvaluationContext; -import org.springframework.security.access.PermissionEvaluator; -import org.springframework.security.access.hierarchicalroles.RoleHierarchy; -import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl; -import org.springframework.security.authentication.RememberMeAuthenticationToken; -import org.springframework.security.authorization.AuthorizationDecision; -import org.springframework.security.authorization.AuthorizationEventPublisher; -import org.springframework.security.authorization.AuthorizationManager; -import org.springframework.security.authorization.SpringAuthorizationEventPublisher; -import org.springframework.security.authorization.event.AuthorizationEvent; -import org.springframework.security.config.ObjectPostProcessor; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.config.core.GrantedAuthorityDefaults; -import org.springframework.security.config.test.SpringTestContext; -import org.springframework.security.config.test.SpringTestContextExtension; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.authority.AuthorityUtils; -import org.springframework.security.core.authority.SimpleGrantedAuthority; -import org.springframework.security.core.userdetails.PasswordEncodedUser; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.access.IpAddressAuthorizationManager; -import org.springframework.security.web.access.expression.DefaultHttpSecurityExpressionHandler; -import org.springframework.security.web.access.expression.WebExpressionAuthorizationManager; -import org.springframework.security.web.access.expression.WebSecurityExpressionRoot; -import org.springframework.security.web.access.intercept.RequestAuthorizationContext; -import org.springframework.stereotype.Component; -import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; -import static org.springframework.security.config.Customizer.withDefaults; -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.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.user; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; - -/** - * Tests for {@link AuthorizeHttpRequestsConfigurer} - * - * @author Rob Winch - * @author Eleftheria Stein - * @author Yanming Zhou - */ -@ExtendWith(SpringTestContextExtension.class) -public class ExpressionUrlAuthorizationConfigurerTests { - - public final SpringTestContext spring = new SpringTestContext(this); - - @Autowired - MockMvc mvc; - - @Test - public void configureWhenHasRoleStartingWithStringRoleThenException() { - assertThatExceptionOfType(BeanCreationException.class) - .isThrownBy(() -> this.spring.register(HasRoleStartingWithRoleConfig.class).autowire()) - .withRootCauseInstanceOf(IllegalArgumentException.class) - .withMessageContaining("ROLE_USER should not start with ROLE_"); - } - - @Test - public void configureWhenAuthorizedRequestsAndNoRequestsThenException() { - assertThatExceptionOfType(BeanCreationException.class) - .isThrownBy(() -> this.spring.register(NoRequestsConfig.class).autowire()) - .withMessageContaining( - "At least one mapping is required (for example, authorizeHttpRequests().anyRequest().authenticated())"); - } - - @Test - public void configureWhenAnyRequestIncompleteMappingThenException() { - assertThatExceptionOfType(BeanCreationException.class) - .isThrownBy(() -> this.spring.register(IncompleteMappingConfig.class).autowire()) - .withMessageContaining("An incomplete mapping was found for "); - } - - @Test - public void getWhenHasAnyAuthorityRoleUserConfiguredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception { - this.spring.register(RoleUserAnyAuthorityConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithUser = get("/") - .with(user("user") - .authorities(new SimpleGrantedAuthority("ROLE_USER"))); - // @formatter:on - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenHasAnyAuthorityRoleUserConfiguredAndAuthorityIsRoleAdminThenRespondsWithForbidden() - throws Exception { - this.spring.register(RoleUserAnyAuthorityConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithAdmin = get("/") - .with(user("user") - .authorities(new SimpleGrantedAuthority("ROLE_ADMIN"))); - // @formatter:on - this.mvc.perform(requestWithAdmin).andExpect(status().isForbidden()); - } - - @Test - public void getWhenHasAnyAuthorityRoleUserConfiguredAndNoAuthorityThenRespondsWithUnauthorized() throws Exception { - this.spring.register(RoleUserAnyAuthorityConfig.class, BasicController.class).autowire(); - this.mvc.perform(get("/")).andExpect(status().isUnauthorized()); - } - - @Test - public void getWhenHasAuthorityRoleUserConfiguredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception { - this.spring.register(RoleUserAuthorityConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithUser = get("/") - .with(user("user") - .authorities(new SimpleGrantedAuthority("ROLE_USER"))); - // @formatter:on - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenHasAuthorityRoleUserConfiguredAndAuthorityIsRoleAdminThenRespondsWithForbidden() - throws Exception { - this.spring.register(RoleUserAuthorityConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithAdmin = get("/") - .with(user("user") - .authorities(new SimpleGrantedAuthority("ROLE_ADMIN"))); - // @formatter:on - this.mvc.perform(requestWithAdmin).andExpect(status().isForbidden()); - } - - @Test - public void getWhenHasAuthorityRoleUserConfiguredAndNoAuthorityThenRespondsWithUnauthorized() throws Exception { - this.spring.register(RoleUserAuthorityConfig.class, BasicController.class).autowire(); - this.mvc.perform(get("/")).andExpect(status().isUnauthorized()); - } - - @Test - public void getWhenAuthorityRoleUserOrAdminRequiredAndAuthorityIsRoleUserThenRespondsWithOk() throws Exception { - this.spring.register(RoleUserOrRoleAdminAuthorityConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithUser = get("/") - .with(user("user") - .authorities(new SimpleGrantedAuthority("ROLE_USER"))); - // @formatter:on - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenAuthorityRoleUserOrAdminRequiredAndAuthorityIsRoleAdminThenRespondsWithOk() throws Exception { - this.spring.register(RoleUserOrRoleAdminAuthorityConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithUser = get("/") - .with(user("user") - .authorities(new SimpleGrantedAuthority("ROLE_ADMIN"))); - // @formatter:on - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenAuthorityRoleUserOrAdminRequiredAndAuthorityIsRoleOtherThenRespondsWithForbidden() - throws Exception { - this.spring.register(RoleUserOrRoleAdminAuthorityConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithUser = get("/") - .with(user("user") - .authorities(new SimpleGrantedAuthority("ROLE_OTHER"))); - // @formatter:on - this.mvc.perform(requestWithUser).andExpect(status().isForbidden()); - } - - @Test - public void getWhenAuthorityRoleUserOrAdminAuthRequiredAndNoUserThenRespondsWithUnauthorized() throws Exception { - this.spring.register(RoleUserOrRoleAdminAuthorityConfig.class, BasicController.class).autowire(); - this.mvc.perform(get("/")).andExpect(status().isUnauthorized()); - } - - @Test - public void getWhenHasAnyRoleUserConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception { - this.spring.register(RoleUserConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithUser = get("/") - .with(user("user") - .roles("USER")); - // @formatter:on - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenHasAnyRoleUserConfiguredAndRoleIsAdminThenRespondsWithForbidden() throws Exception { - this.spring.register(RoleUserConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithAdmin = get("/") - .with(user("user") - .roles("ADMIN")); - // @formatter:on - this.mvc.perform(requestWithAdmin).andExpect(status().isForbidden()); - } - - @Test - public void getWhenHasAnyRoleUserWithTestRolePrefixConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception { - this.spring.register(RoleUserWithTestRolePrefixConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithUser = get("/") - .with(user("user") - .authorities(new SimpleGrantedAuthority("TEST_USER"))); - // @formatter:on - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenHasAnyRoleUserWithEmptyRolePrefixConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception { - this.spring.register(RoleUserWithEmptyRolePrefixConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithUser = get("/") - .with(user("user") - .authorities(new SimpleGrantedAuthority("USER"))); - // @formatter:on - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenRoleUserOrAdminConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception { - this.spring.register(RoleUserOrAdminConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithUser = get("/") - .with(user("user") - .roles("USER")); - // @formatter:on - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenRoleUserOrAdminConfiguredAndRoleIsAdminThenRespondsWithOk() throws Exception { - this.spring.register(RoleUserOrAdminConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithAdmin = get("/") - .with(user("user") - .roles("ADMIN")); - // @formatter:on - this.mvc.perform(requestWithAdmin).andExpect(status().isOk()); - } - - @Test - public void getWhenRoleUserOrAdminConfiguredAndRoleIsOtherThenRespondsWithForbidden() throws Exception { - this.spring.register(RoleUserOrAdminConfig.class, BasicController.class).autowire(); - // - MockHttpServletRequestBuilder requestWithRoleOther = get("/").with(user("user").roles("OTHER")); - // - this.mvc.perform(requestWithRoleOther).andExpect(status().isForbidden()); - } - - @Test - public void getWhenRoleUserOrAdminWithTestRolePrefixConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception { - this.spring.register(RoleUserOrAdminWithTestRolePrefixConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithUser = get("/") - .with(user("user") - .authorities(new SimpleGrantedAuthority("TEST_USER"))); - // @formatter:on - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenRoleUserOrAdminWithEmptyRolePrefixConfiguredAndRoleIsUserThenRespondsWithOk() throws Exception { - this.spring.register(RoleUserOrAdminWithEmptyRolePrefixConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithUser = get("/") - .with(user("user") - .authorities(new SimpleGrantedAuthority("USER"))); - // @formatter:on - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenHasIpAddressConfiguredAndIpAddressMatchesThenRespondsWithOk() throws Exception { - this.spring.register(HasIpAddressConfig.class, BasicController.class).autowire(); - this.mvc.perform(get("/").with((request) -> { - request.setRemoteAddr("192.168.1.0"); - return request; - })).andExpect(status().isOk()); - } - - @Test - public void getWhenHasIpAddressConfiguredAndIpAddressDoesNotMatchThenRespondsWithUnauthorized() throws Exception { - this.spring.register(HasIpAddressConfig.class, BasicController.class).autowire(); - this.mvc.perform(get("/").with((request) -> { - request.setRemoteAddr("192.168.1.1"); - return request; - })).andExpect(status().isUnauthorized()); - } - - @Test - public void getWhenAnonymousConfiguredAndAnonymousUserThenRespondsWithOk() throws Exception { - this.spring.register(AnonymousConfig.class, BasicController.class).autowire(); - this.mvc.perform(get("/")).andExpect(status().isOk()); - } - - @Test - public void getWhenAnonymousConfiguredAndLoggedInUserThenRespondsWithForbidden() throws Exception { - this.spring.register(AnonymousConfig.class, BasicController.class).autowire(); - MockHttpServletRequestBuilder requestWithUser = get("/").with(user("user")); - this.mvc.perform(requestWithUser).andExpect(status().isForbidden()); - } - - @Test - public void getWhenRememberMeConfiguredAndNoUserThenRespondsWithUnauthorized() throws Exception { - this.spring.register(RememberMeConfig.class, BasicController.class).autowire(); - this.mvc.perform(get("/")).andExpect(status().isUnauthorized()); - } - - @Test - public void getWhenRememberMeConfiguredAndRememberMeTokenThenRespondsWithOk() throws Exception { - this.spring.register(RememberMeConfig.class, BasicController.class).autowire(); - RememberMeAuthenticationToken rememberme = new RememberMeAuthenticationToken("key", "user", - AuthorityUtils.createAuthorityList("ROLE_USER")); - MockHttpServletRequestBuilder requestWithRememberme = get("/").with(authentication(rememberme)); - this.mvc.perform(requestWithRememberme).andExpect(status().isOk()); - } - - @Test - public void getWhenDenyAllConfiguredAndNoUserThenRespondsWithUnauthorized() throws Exception { - this.spring.register(DenyAllConfig.class, BasicController.class).autowire(); - this.mvc.perform(get("/")).andExpect(status().isUnauthorized()); - } - - @Test - public void getWheDenyAllConfiguredAndUserLoggedInThenRespondsWithForbidden() throws Exception { - this.spring.register(DenyAllConfig.class, BasicController.class).autowire(); - MockHttpServletRequestBuilder requestWithUser = get("/").with(user("user").roles("USER")); - this.mvc.perform(requestWithUser).andExpect(status().isForbidden()); - } - - @Test - public void getWhenNotDenyAllConfiguredAndNoUserThenRespondsWithOk() throws Exception { - this.spring.register(NotDenyAllConfig.class, BasicController.class).autowire(); - this.mvc.perform(get("/")).andExpect(status().isOk()); - } - - @Test - public void getWhenNotDenyAllConfiguredAndRememberMeTokenThenRespondsWithOk() throws Exception { - this.spring.register(NotDenyAllConfig.class, BasicController.class).autowire(); - RememberMeAuthenticationToken rememberme = new RememberMeAuthenticationToken("key", "user", - AuthorityUtils.createAuthorityList("ROLE_USER")); - MockHttpServletRequestBuilder requestWithRememberme = get("/").with(authentication(rememberme)); - this.mvc.perform(requestWithRememberme).andExpect(status().isOk()); - } - - @Test - public void getWhenFullyAuthenticatedConfiguredAndRememberMeTokenThenRespondsWithUnauthorized() throws Exception { - this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire(); - RememberMeAuthenticationToken rememberme = new RememberMeAuthenticationToken("key", "user", - AuthorityUtils.createAuthorityList("ROLE_USER")); - MockHttpServletRequestBuilder requestWithRememberme = get("/").with(authentication(rememberme)); - this.mvc.perform(requestWithRememberme).andExpect(status().isUnauthorized()); - } - - @Test - public void getWhenFullyAuthenticatedConfiguredAndUserThenRespondsWithOk() throws Exception { - this.spring.register(FullyAuthenticatedConfig.class, BasicController.class).autowire(); - MockHttpServletRequestBuilder requestWithUser = get("/").with(user("user").roles("USER")); - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenAccessRoleUserOrGetRequestConfiguredThenRespondsWithOk() throws Exception { - this.spring.register(AccessConfig.class, BasicController.class).autowire(); - this.mvc.perform(get("/")).andExpect(status().isOk()); - } - - @Test - public void postWhenAccessRoleUserOrGetRequestConfiguredAndRoleUserThenRespondsWithOk() throws Exception { - this.spring.register(AccessConfig.class, BasicController.class).autowire(); - // @formatter:off - MockHttpServletRequestBuilder requestWithUser = post("/") - .with(csrf()) - .with(user("user").roles("USER")); - // @formatter:on - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void postWhenAccessRoleUserOrGetRequestConfiguredThenRespondsWithUnauthorized() throws Exception { - this.spring.register(AccessConfig.class, BasicController.class).autowire(); - MockHttpServletRequestBuilder requestWithCsrf = post("/").with(csrf()); - this.mvc.perform(requestWithCsrf).andExpect(status().isUnauthorized()); - } - - @Test - public void authorizeRequestsWhenInvokedTwiceThenUsesOriginalConfiguration() throws Exception { - this.spring.register(InvokeTwiceDoesNotResetConfig.class, BasicController.class).autowire(); - MockHttpServletRequestBuilder requestWithCsrf = post("/").with(csrf()); - this.mvc.perform(requestWithCsrf).andExpect(status().isUnauthorized()); - } - - @Test - public void configureWhenUsingAllAuthorizeRequestPropertiesThenCompiles() { - this.spring.register(AllPropertiesWorkConfig.class).autowire(); - } - - @Test - public void configureWhenRegisteringObjectPostProcessorThenApplicationListenerInvokedOnAuthorizedEvent() - throws Exception { - AuthorizedEventApplicationListener.clearEvents(); - this.spring.register(AuthorizedRequestsWithPostProcessorConfig.class).autowire(); - this.mvc.perform(get("/")); - assertThat(AuthorizedEventApplicationListener.EVENTS).isNotEmpty(); - } - - @Test - public void getWhenPermissionCheckAndRoleDoesNotMatchThenRespondsWithForbidden() throws Exception { - this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire(); - MockHttpServletRequestBuilder requestWithUser = get("/admin").with(user("user").roles("USER")); - this.mvc.perform(requestWithUser).andExpect(status().isForbidden()); - } - - @Test - public void getWhenPermissionCheckAndRoleMatchesThenRespondsWithOk() throws Exception { - this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire(); - MockHttpServletRequestBuilder requestWithUser = get("/user").with(user("user").roles("USER")); - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenPermissionCheckAndAuthenticationNameMatchesThenRespondsWithOk() throws Exception { - this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire(); - MockHttpServletRequestBuilder requestWithUser = get("/allow").with(user("user").roles("USER")); - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenPermissionCheckAndAuthenticationNameDoesNotMatchThenRespondsWithForbidden() throws Exception { - this.spring.register(UseBeansInExpressions.class, WildcardController.class).autowire(); - MockHttpServletRequestBuilder requestWithUser = get("/deny").with(user("user").roles("USER")); - this.mvc.perform(requestWithUser).andExpect(status().isForbidden()); - } - - @Test - public void getWhenCustomExpressionHandlerAndRoleDoesNotMatchThenRespondsWithForbidden() throws Exception { - this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire(); - MockHttpServletRequestBuilder requestWithUser = get("/admin").with(user("user").roles("USER")); - this.mvc.perform(requestWithUser).andExpect(status().isForbidden()); - } - - @Test - public void getWhenCustomExpressionHandlerAndRoleMatchesThenRespondsWithOk() throws Exception { - this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire(); - MockHttpServletRequestBuilder requestWithUser = get("/user").with(user("user").roles("USER")); - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenCustomExpressionHandlerAndAuthenticationNameMatchesThenRespondsWithOk() throws Exception { - this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire(); - MockHttpServletRequestBuilder requestWithUser = get("/allow").with(user("user").roles("USER")); - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenCustomExpressionHandlerAndAuthenticationNameDoesNotMatchThenRespondsWithForbidden() - throws Exception { - this.spring.register(CustomExpressionRootConfig.class, WildcardController.class).autowire(); - MockHttpServletRequestBuilder requestWithUser = get("/deny").with(user("user").roles("USER")); - this.mvc.perform(requestWithUser).andExpect(status().isForbidden()); - } - - @Test - public void getWhenRegisteringPermissionEvaluatorAndPermissionWithIdAndTypeMatchesThenRespondsWithOk() - throws Exception { - this.spring.register(PermissionEvaluatorConfig.class, WildcardController.class).autowire(); - this.mvc.perform(get("/allow")).andExpect(status().isOk()); - } - - @Test - public void getWhenRegisteringPermissionEvaluatorAndPermissionWithIdAndTypeDoesNotMatchThenRespondsWithForbidden() - throws Exception { - this.spring.register(PermissionEvaluatorConfig.class, WildcardController.class).autowire(); - this.mvc.perform(get("/deny")).andExpect(status().isForbidden()); - } - - @Test - public void getWhenRegisteringPermissionEvaluatorAndPermissionWithObjectMatchesThenRespondsWithOk() - throws Exception { - this.spring.register(PermissionEvaluatorConfig.class, WildcardController.class).autowire(); - this.mvc.perform(get("/allowObject")).andExpect(status().isOk()); - } - - @Test - public void getWhenRegisteringPermissionEvaluatorAndPermissionWithObjectDoesNotMatchThenRespondsWithForbidden() - throws Exception { - this.spring.register(PermissionEvaluatorConfig.class, WildcardController.class).autowire(); - this.mvc.perform(get("/denyObject")).andExpect(status().isForbidden()); - } - - @Test - public void getWhenRegisteringRoleHierarchyAndRelatedRoleAllowedThenRespondsWithOk() throws Exception { - this.spring.register(RoleHierarchyConfig.class, WildcardController.class).autowire(); - MockHttpServletRequestBuilder requestWithUser = get("/allow").with(user("user").roles("USER")); - this.mvc.perform(requestWithUser).andExpect(status().isOk()); - } - - @Test - public void getWhenRegisteringRoleHierarchyAndNoRelatedRolesAllowedThenRespondsWithForbidden() throws Exception { - this.spring.register(RoleHierarchyConfig.class, WildcardController.class).autowire(); - MockHttpServletRequestBuilder requestWithUser = get("/deny").with(user("user").roles("USER")); - this.mvc.perform(requestWithUser).andExpect(status().isForbidden()); - } - - @Configuration - @EnableWebSecurity - static class HasRoleStartingWithRoleConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .anyRequest().hasRole("ROLE_USER")); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - static class NoRequestsConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests(withDefaults()); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - static class IncompleteMappingConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .requestMatchers("/a").authenticated() - .anyRequest()); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - static class RoleUserAnyAuthorityConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .anyRequest().hasAnyAuthority("ROLE_USER")); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - static class RoleUserAuthorityConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .anyRequest().hasAuthority("ROLE_USER")); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - static class RoleUserOrRoleAdminAuthorityConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .anyRequest().hasAnyAuthority("ROLE_USER", "ROLE_ADMIN")); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - static class RoleUserConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .anyRequest().hasAnyRole("USER")); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - static class RoleUserWithTestRolePrefixConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .anyRequest().hasAnyRole("USER")); - return http.build(); - // @formatter:on - } - - @Bean - GrantedAuthorityDefaults grantedAuthorityDefaults() { - return new GrantedAuthorityDefaults("TEST_"); - } - - } - - @Configuration - @EnableWebSecurity - static class RoleUserWithEmptyRolePrefixConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .anyRequest().hasAnyRole("USER")); - return http.build(); - // @formatter:on - } - - @Bean - GrantedAuthorityDefaults grantedAuthorityDefaults() { - return new GrantedAuthorityDefaults(""); - } - - } - - @Configuration - @EnableWebSecurity - static class RoleUserOrAdminConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .anyRequest().hasAnyRole("USER", "ADMIN")); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - static class RoleUserOrAdminWithTestRolePrefixConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .anyRequest().hasAnyRole("USER", "ADMIN")); - return http.build(); - // @formatter:on - } - - @Bean - GrantedAuthorityDefaults grantedAuthorityDefaults() { - return new GrantedAuthorityDefaults("TEST_"); - } - - } - - @Configuration - @EnableWebSecurity - static class RoleUserOrAdminWithEmptyRolePrefixConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .anyRequest().hasAnyRole("USER", "ADMIN")); - return http.build(); - // @formatter:on - } - - @Bean - GrantedAuthorityDefaults grantedAuthorityDefaults() { - return new GrantedAuthorityDefaults(""); - } - - } - - @Configuration - @EnableWebSecurity - static class HasIpAddressConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .anyRequest().access(IpAddressAuthorizationManager.hasIpAddress("192.168.1.0")) - ); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - static class AnonymousConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .anyRequest().anonymous()); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - static class RememberMeConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .rememberMe(withDefaults()) - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .anyRequest().rememberMe()); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(PasswordEncodedUser.user()); - } - - } - - @Configuration - @EnableWebSecurity - static class DenyAllConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .anyRequest().denyAll()); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - static class NotDenyAllConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .anyRequest().not().denyAll()); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - static class FullyAuthenticatedConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .rememberMe(withDefaults()) - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .anyRequest().fullyAuthenticated()); - return http.build(); - // @formatter:on - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(PasswordEncodedUser.user()); - } - - } - - @Configuration - @EnableWebSecurity - static class AccessConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - WebExpressionAuthorizationManager authz = new WebExpressionAuthorizationManager( - "hasRole('ROLE_USER') or request.method == 'GET'"); - // @formatter:off - http - .rememberMe(withDefaults()) - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests.anyRequest().access(authz)); - return http.build(); - // @formatter:on - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(PasswordEncodedUser.user()); - } - - } - - @Configuration - @EnableWebSecurity - static class InvokeTwiceDoesNotResetConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .httpBasic(withDefaults()) - .authorizeHttpRequests((requests) -> requests - .anyRequest().authenticated()) - .authorizeHttpRequests(withDefaults()); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - static class AllPropertiesWorkConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .shouldFilterAllDispatcherTypes(false) - .requestMatchers("/a", "/b").hasRole("ADMIN") - .anyRequest().permitAll()) - .formLogin(withDefaults()); - return http.build(); - // @formatter:on - } - - } - - @Configuration - @EnableWebSecurity - static class AuthorizedRequestsWithPostProcessorConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests.anyRequest().permitAll()); - return http.build(); - // @formatter:on - } - - @Bean - AuthorizationEventPublisher publisher(ApplicationEventPublisher publisher) { - SpringAuthorizationEventPublisher authzEvents = new SpringAuthorizationEventPublisher(publisher); - authzEvents.setShouldPublishResult((result) -> true); - return authzEvents; - } - - @Bean - ApplicationListener applicationListener() { - return new AuthorizedEventApplicationListener(); - } - - } - - static class AuthorizedEventApplicationListener implements ApplicationListener { - - static final List EVENTS = new ArrayList<>(); - - @Override - public void onApplicationEvent(AuthorizationEvent event) { - EVENTS.add(event); - } - - static void clearEvents() { - EVENTS.clear(); - } - - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - static class UseBeansInExpressions { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http, ApplicationContext context) throws Exception { - WebExpressionAuthorizationManager user = new WebExpressionAuthorizationManager( - "@permission.check(authentication,'user')"); - DefaultHttpSecurityExpressionHandler expressionHandler = new DefaultHttpSecurityExpressionHandler(); - expressionHandler.setApplicationContext(context); - user.setExpressionHandler(expressionHandler); - WebExpressionAuthorizationManager admin = new WebExpressionAuthorizationManager( - "@permission.check(authentication,'admin')"); - admin.setExpressionHandler(expressionHandler); - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .requestMatchers("/admin").hasRole("ADMIN") - .requestMatchers("/user").hasRole("USER") - .requestMatchers("/allow").access(user) - .anyRequest().access(admin)); - return http.build(); - // @formatter:on - } - - @Bean - Checker permission() { - return new Checker(); - } - - static class Checker { - - public boolean check(Authentication authentication, String customArg) { - return authentication.getName().contains(customArg); - } - - } - - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - static class CustomExpressionRootConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - WebExpressionAuthorizationManager user = new WebExpressionAuthorizationManager("check('user')"); - user.setExpressionHandler(expressionHandler()); - WebExpressionAuthorizationManager admin = new WebExpressionAuthorizationManager("check('admin')"); - admin.setExpressionHandler(expressionHandler()); - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .requestMatchers("/admin").hasRole("ADMIN") - .requestMatchers("/user").hasRole("USER") - .requestMatchers("/allow").access(user) - .anyRequest().access(admin)); - return http.build(); - // @formatter:on - } - - @Bean - CustomExpressionHandler expressionHandler() { - return new CustomExpressionHandler(); - } - - static class CustomExpressionHandler extends DefaultHttpSecurityExpressionHandler { - - @Override - public EvaluationContext createEvaluationContext(Supplier authentication, - RequestAuthorizationContext context) { - StandardEvaluationContext ctx = (StandardEvaluationContext) super.createEvaluationContext( - authentication, context); - WebSecurityExpressionRoot delegate = (WebSecurityExpressionRoot) ctx.getRootObject().getValue(); - ctx.setRootObject(new CustomExpressionRoot(delegate)); - return ctx; - } - - } - - static class CustomExpressionRoot extends WebSecurityExpressionRoot { - - CustomExpressionRoot(WebSecurityExpressionRoot root) { - super(root::getAuthentication, root.request); - } - - public boolean check(String customArg) { - Authentication auth = this.getAuthentication(); - return auth.getName().contains(customArg); - } - - } - - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - static class PermissionEvaluatorConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http, PermissionEvaluatorAuthorizations authz) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .requestMatchers("/allow").access(authz.hasPermission("TESTOBJ", "PERMISSION")) - .requestMatchers("/allowObject").access(authz.hasPermission("TESTOBJ", "PERMISSION")) - .requestMatchers("/deny").access(authz.hasPermission("ID", "TYPE", "NO PERMISSION")) - .requestMatchers("/denyObject").access(authz.hasPermission("TESTOBJ", "NO PERMISSION")) - .anyRequest().permitAll()); - return http.build(); - // @formatter:on - } - - @Bean - PermissionEvaluator permissionEvaluator() { - return new PermissionEvaluator() { - @Override - public boolean hasPermission(Authentication authentication, Object targetDomainObject, - Object permission) { - return "TESTOBJ".equals(targetDomainObject) && "PERMISSION".equals(permission); - } - - @Override - public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, - Object permission) { - return "ID".equals(targetId) && "TYPE".equals(targetType) && "PERMISSION".equals(permission); - } - }; - } - - @Component - static class PermissionEvaluatorAuthorizations { - - private final PermissionEvaluator permissions; - - PermissionEvaluatorAuthorizations(PermissionEvaluator permissions) { - this.permissions = permissions; - } - - AuthorizationManager hasPermission(Object targetDomainObject, - Object permission) { - return (auth, request) -> new AuthorizationDecision( - this.permissions.hasPermission(auth.get(), targetDomainObject, permission)); - } - - AuthorizationManager hasPermission(Serializable targetId, String targetType, - Object permission) { - return (auth, request) -> new AuthorizationDecision( - this.permissions.hasPermission(auth.get(), targetId, targetType, permission)); - } - - } - - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - static class RoleHierarchyConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .authorizeHttpRequests((requests) -> requests - .requestMatchers("/allow").hasRole("MEMBER") - .requestMatchers("/deny").hasRole("ADMIN") - .anyRequest().permitAll()); - return http.build(); - // @formatter:on - } - - @Bean - RoleHierarchy roleHierarchy() { - return RoleHierarchyImpl.fromHierarchy("ROLE_USER > ROLE_MEMBER"); - } - - } - - @RestController - static class BasicController { - - @GetMapping("/") - void rootGet() { - } - - @PostMapping("/") - void rootPost() { - } - - } - - @RestController - static class WildcardController { - - @GetMapping("/{path}") - void wildcard(@PathVariable String path) { - } - - } - - static class ReflectingObjectPostProcessor implements ObjectPostProcessor { - - @Override - public O postProcess(O object) { - return object; - } - - } - -} diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java index ffa6fcd155..30007797a5 100644 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java +++ b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/PermitAllSupportTests.java @@ -81,7 +81,7 @@ public class PermitAllSupportTests { assertThatExceptionOfType(BeanCreationException.class) .isThrownBy(() -> this.spring.register(NoAuthorizedUrlsConfig.class).autowire()) .withMessageContaining( - "permitAll only works with either HttpSecurity.authorizeRequests() or HttpSecurity.authorizeHttpRequests()"); + "permitAll only works with HttpSecurity.authorizeHttpRequests(). Please define one."); } @Configuration diff --git a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java b/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java deleted file mode 100644 index b43ffd8831..0000000000 --- a/config/src/test/java/org/springframework/security/config/annotation/web/configurers/UrlAuthorizationConfigurerTests.java +++ /dev/null @@ -1,254 +0,0 @@ -/* - * Copyright 2002-2024 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.web.configurers; - -import java.util.Base64; - -import jakarta.servlet.http.HttpServletResponse; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.mock.web.MockFilterChain; -import org.springframework.mock.web.MockHttpServletRequest; -import org.springframework.mock.web.MockHttpServletResponse; -import org.springframework.security.config.Customizer; -import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; -import org.springframework.security.core.userdetails.PasswordEncodedUser; -import org.springframework.security.core.userdetails.User; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; -import org.springframework.security.web.FilterChainProxy; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.servlet.MockServletContext; -import org.springframework.security.web.servlet.util.matcher.PathPatternRequestMatcher; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; -import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.springframework.security.config.Customizer.withDefaults; - -/** - * @author Rob Winch - * @author M.S. Dousti - * - */ -public class UrlAuthorizationConfigurerTests { - - AnnotationConfigWebApplicationContext context; - - MockHttpServletRequest request; - - MockHttpServletResponse response; - - MockFilterChain chain; - - @Autowired - FilterChainProxy springSecurityFilterChain; - - @BeforeEach - public void setup() { - this.request = new MockHttpServletRequest(MockServletContext.mvc(), "GET", ""); - this.request.setMethod("GET"); - this.response = new MockHttpServletResponse(); - this.chain = new MockFilterChain(); - } - - @AfterEach - public void cleanup() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - public void anonymousUrlAuthorization() { - loadConfig(AnonymousUrlAuthorizationConfig.class); - } - - // gh-10956 - @Test - public void multiMvcMatchersConfig() throws Exception { - loadConfig(MultiMvcMatcherConfig.class); - this.request.addHeader("Authorization", - "Basic " + new String(Base64.getEncoder().encode("user:password".getBytes()))); - this.request.setRequestURI("/test-1"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN); - setup(); - this.request.addHeader("Authorization", - "Basic " + new String(Base64.getEncoder().encode("user:password".getBytes()))); - this.request.setRequestURI("/test-2"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN); - setup(); - this.request.addHeader("Authorization", - "Basic " + new String(Base64.getEncoder().encode("user:password".getBytes()))); - this.request.setRequestURI("/test-3"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_FORBIDDEN); - setup(); - this.request.addHeader("Authorization", - "Basic " + new String(Base64.getEncoder().encode("user:password".getBytes()))); - this.request.setRequestURI("/test-x"); - this.springSecurityFilterChain.doFilter(this.request, this.response, this.chain); - assertThat(this.response.getStatus()).isEqualTo(HttpServletResponse.SC_OK); - } - - public void loadConfig(Class... configs) { - this.context = new AnnotationConfigWebApplicationContext(); - this.context.register(configs); - this.context.setServletContext(MockServletContext.mvc()); - this.context.refresh(); - this.context.getAutowireCapableBeanFactory().autowireBean(this); - } - - @EnableWebSecurity - @Configuration - @EnableWebMvc - static class MvcMatcherConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http, ApplicationContext context, - PathPatternRequestMatcher.Builder builder) throws Exception { - // @formatter:off - http - .httpBasic(withDefaults()) - .apply(new UrlAuthorizationConfigurer(context)).getRegistry() - .requestMatchers(builder.matcher("/path")).hasRole("ADMIN"); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(PasswordEncodedUser.user()); - } - - @RestController - static class PathController { - - @RequestMapping("/path") - String path() { - return "path"; - } - - } - - } - - @EnableWebSecurity - @Configuration - @EnableWebMvc - static class MvcMatcherServletPathConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http, ApplicationContext context, - PathPatternRequestMatcher.Builder builder) throws Exception { - PathPatternRequestMatcher.Builder spring = builder.basePath("/spring"); - // @formatter:off - http - .httpBasic(withDefaults()) - .apply(new UrlAuthorizationConfigurer(context)).getRegistry() - .requestMatchers(builder.matcher("/path")).hasRole("ADMIN"); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - return new InMemoryUserDetailsManager(PasswordEncodedUser.user()); - } - - @RestController - static class PathController { - - @RequestMapping("/path") - String path() { - return "path"; - } - - } - - } - - @EnableWebSecurity - @Configuration - static class AnonymousUrlAuthorizationConfig { - - @Bean - SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - // @formatter:off - http - .apply(new UrlAuthorizationConfigurer<>(null)).getRegistry() - .anyRequest().anonymous(); - return http.build(); - // @formatter:on - } - - } - - @EnableWebSecurity - @Configuration - @EnableWebMvc - static class MultiMvcMatcherConfig { - - @Bean - SecurityFilterChain security(HttpSecurity http, ApplicationContext context) throws Exception { - // @formatter:off - http - .httpBasic(Customizer.withDefaults()) - .apply(new UrlAuthorizationConfigurer<>(context)).getRegistry() - .requestMatchers("/test-1").hasRole("ADMIN") - .requestMatchers("/test-2").hasRole("ADMIN") - .requestMatchers("/test-3").hasRole("ADMIN") - .anyRequest().hasRole("USER"); - // @formatter:on - return http.build(); - } - - @Bean - UserDetailsService userDetailsService() { - UserDetails user = User.withDefaultPasswordEncoder() - .username("user") - .password("password") - .roles("USER") - .build(); - return new InMemoryUserDetailsManager(user); - } - - @RestController - static class PathController { - - @RequestMapping({ "/test-1", "/test-2", "/test-3", "/test-x" }) - String path() { - return "path"; - } - - } - - } - -} diff --git a/config/src/test/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDslTests.kt b/config/src/test/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDslTests.kt deleted file mode 100644 index ed70c24915..0000000000 --- a/config/src/test/kotlin/org/springframework/security/config/annotation/web/AuthorizeRequestsDslTests.kt +++ /dev/null @@ -1,520 +0,0 @@ -/* - * Copyright 2002-2022 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.security.config.annotation.web - -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.extension.ExtendWith -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.http.HttpMethod -import org.springframework.security.config.annotation.web.builders.HttpSecurity -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity -import org.springframework.security.config.test.SpringTestContext -import org.springframework.security.config.test.SpringTestContextExtension -import org.springframework.security.core.userdetails.User -import org.springframework.security.core.userdetails.UserDetailsService -import org.springframework.security.provisioning.InMemoryUserDetailsManager -import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf -import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.httpBasic -import org.springframework.security.web.SecurityFilterChain -import org.springframework.security.web.util.matcher.RegexRequestMatcher -import org.springframework.test.web.servlet.MockMvc -import org.springframework.test.web.servlet.get -import org.springframework.test.web.servlet.post -import org.springframework.test.web.servlet.put -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders -import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -import org.springframework.web.bind.annotation.GetMapping -import org.springframework.web.bind.annotation.PathVariable -import org.springframework.web.bind.annotation.RequestMapping -import org.springframework.web.bind.annotation.RestController -import org.springframework.web.servlet.config.annotation.EnableWebMvc - -/** - * Tests for [AuthorizeRequestsDsl] - * - * @author Eleftheria Stein - */ -@ExtendWith(SpringTestContextExtension::class) -class AuthorizeRequestsDslTests { - @JvmField - val spring = SpringTestContext(this) - - @Autowired - lateinit var mockMvc: MockMvc - - @Test - fun `request when secured by regex matcher then responds with forbidden`() { - this.spring.register(AuthorizeRequestsByRegexConfig::class.java).autowire() - - this.mockMvc.get("/private") - .andExpect { - status { isForbidden() } - } - } - - @Test - fun `request when allowed by regex matcher then responds with ok`() { - this.spring.register(AuthorizeRequestsByRegexConfig::class.java).autowire() - - this.mockMvc.get("/path") - .andExpect { - status { isOk() } - } - } - - @Test - fun `request when allowed by regex matcher with http method then responds based on method`() { - this.spring.register(AuthorizeRequestsByRegexConfig::class.java).autowire() - - this.mockMvc.post("/onlyPostPermitted") { with(csrf()) } - .andExpect { - status { isOk() } - } - - this.mockMvc.get("/onlyPostPermitted") - .andExpect { - status { isForbidden() } - } - } - - @Configuration - @EnableWebSecurity - open class AuthorizeRequestsByRegexConfig { - @Bean - open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { - http { - authorizeRequests { - authorize(RegexRequestMatcher("/path", null), permitAll) - authorize(RegexRequestMatcher("/onlyPostPermitted", "POST"), permitAll) - authorize(RegexRequestMatcher("/onlyPostPermitted", "GET"), denyAll) - authorize(RegexRequestMatcher(".*", null), authenticated) - } - } - return http.build() - } - - @RestController - internal class PathController { - @RequestMapping("/path") - fun path(): String { - return "ok" - } - - @RequestMapping("/onlyPostPermitted") - fun onlyPostPermitted(): String { - return "ok" - } - } - } - - @Test - fun `request when secured by mvc then responds with forbidden`() { - this.spring.register(AuthorizeRequestsByMvcConfig::class.java).autowire() - - this.mockMvc.get("/private") - .andExpect { - status { isForbidden() } - } - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - open class AuthorizeRequestsByMvcConfig { - @Bean - open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { - http { - authorizeRequests { - authorize("/path", permitAll) - authorize("/**", authenticated) - } - } - return http.build() - } - - @RestController - internal class PathController { - @RequestMapping("/path") - fun path(): String { - return "ok" - } - } - } - - @Test - fun `request when secured by mvc path variables then responds based on path variable value`() { - this.spring.register(MvcMatcherPathVariablesConfig::class.java).autowire() - - this.mockMvc.get("/user/user") - .andExpect { - status { isOk() } - } - - this.mockMvc.get("/user/deny") - .andExpect { - status { isForbidden() } - } - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - open class MvcMatcherPathVariablesConfig { - @Bean - open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { - http { - authorizeRequests { - authorize("/user/{userName}", "#userName == 'user'") - } - } - return http.build() - } - - @RestController - internal class PathController { - @RequestMapping("/user/{user}") - fun path(@PathVariable user: String) { - } - } - } - - @Test - fun `request when user has allowed role then responds with OK`() { - this.spring.register(HasRoleConfig::class.java).autowire() - - this.mockMvc.get("/") { - with(httpBasic("admin", "password")) - }.andExpect { - status { isOk() } - } - } - - @Test - fun `request when user does not have allowed role then responds with forbidden`() { - this.spring.register(HasRoleConfig::class.java).autowire() - - this.mockMvc.get("/") { - with(httpBasic("user", "password")) - }.andExpect { - status { isForbidden() } - } - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - open class HasRoleConfig { - @Bean - open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { - http { - authorizeRequests { - authorize("/**", hasRole("ADMIN")) - } - httpBasic { } - } - return http.build() - } - - @RestController - internal class PathController { - @GetMapping("/") - fun index() { - } - } - - @Bean - open fun userDetailsService(): UserDetailsService { - val userDetails = User.withDefaultPasswordEncoder() - .username("user") - .password("password") - .roles("USER") - .build() - val adminDetails = User.withDefaultPasswordEncoder() - .username("admin") - .password("password") - .roles("ADMIN") - .build() - return InMemoryUserDetailsManager(userDetails, adminDetails) - } - } - - @Test - fun `request when user has some allowed roles then responds with OK`() { - this.spring.register(HasAnyRoleConfig::class.java).autowire() - - this.mockMvc.get("/") { - with(httpBasic("user", "password")) - }.andExpect { - status { isOk() } - } - - this.mockMvc.get("/") { - with(httpBasic("admin", "password")) - }.andExpect { - status { isOk() } - } - } - - @Test - fun `request when user does not have any allowed roles then responds with forbidden`() { - this.spring.register(HasAnyRoleConfig::class.java).autowire() - - this.mockMvc.get("/") { - with(httpBasic("other", "password")) - }.andExpect { - status { isForbidden() } - } - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - open class HasAnyRoleConfig { - @Bean - open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { - http { - authorizeRequests { - authorize("/**", hasAnyRole("ADMIN", "USER")) - } - httpBasic { } - } - return http.build() - } - - @RestController - internal class PathController { - @GetMapping("/") - fun index():String { - return "ok" - } - } - - @Bean - open fun userDetailsService(): UserDetailsService { - val userDetails = User.withDefaultPasswordEncoder() - .username("user") - .password("password") - .roles("USER") - .build() - val admin1Details = User.withDefaultPasswordEncoder() - .username("admin") - .password("password") - .roles("ADMIN") - .build() - val admin2Details = User.withDefaultPasswordEncoder() - .username("other") - .password("password") - .roles("OTHER") - .build() - return InMemoryUserDetailsManager(userDetails, admin1Details, admin2Details) - } - } - - @Test - fun `request when user has some allowed authorities then responds with OK`() { - this.spring.register(HasAnyAuthorityConfig::class.java).autowire() - - this.mockMvc.get("/") { - with(httpBasic("user", "password")) - }.andExpect { - status { isOk() } - } - - this.mockMvc.get("/") { - with(httpBasic("admin", "password")) - }.andExpect { - status { isOk() } - } - } - - @Test - fun `request when user does not have any allowed authorities then responds with forbidden`() { - this.spring.register(HasAnyAuthorityConfig::class.java).autowire() - - this.mockMvc.get("/") { - with(httpBasic("other", "password")) - }.andExpect { - status { isForbidden() } - } - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - open class HasAnyAuthorityConfig { - @Bean - open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { - http { - authorizeRequests { - authorize("/**", hasAnyAuthority("ROLE_ADMIN", "ROLE_USER")) - } - httpBasic { } - } - return http.build() - } - - @RestController - internal class PathController { - @GetMapping("/") - fun index():String { - return "ok" - } - } - - @Bean - open fun userDetailsService(): UserDetailsService { - val userDetails = User.withDefaultPasswordEncoder() - .username("user") - .password("password") - .authorities("ROLE_USER") - .build() - val admin1Details = User.withDefaultPasswordEncoder() - .username("admin") - .password("password") - .authorities("ROLE_ADMIN") - .build() - val admin2Details = User.withDefaultPasswordEncoder() - .username("other") - .password("password") - .authorities("ROLE_OTHER") - .build() - return InMemoryUserDetailsManager(userDetails, admin1Details, admin2Details) - } - } - - @Test - fun `request when secured by mvc with servlet path then responds based on servlet path`() { - this.spring.register(MvcMatcherServletPathConfig::class.java).autowire() - - this.mockMvc.perform(MockMvcRequestBuilders.get("/spring/path") - .servletPath("/spring")) - .andExpect(status().isForbidden) - - this.mockMvc.perform(MockMvcRequestBuilders.get("/other/path") - .servletPath("/other")) - .andExpect(status().isOk) - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - open class MvcMatcherServletPathConfig { - @Bean - open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { - http { - authorizeRequests { - authorize("/path", - "/spring", - denyAll) - } - } - return http.build() - } - - @RestController - internal class PathController { - @RequestMapping("/path") - fun path():String { - return "ok" - } - } - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - open class AuthorizeRequestsByMvcConfigWithHttpMethod{ - @Bean - open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { - http { - authorizeRequests { - authorize(HttpMethod.GET, "/path", permitAll) - authorize(HttpMethod.PUT, "/path", denyAll) - } - } - return http.build() - } - - @RestController - internal class PathController { - @RequestMapping("/path") - fun path(): String { - return "ok" - } - } - } - - @Test - fun `request when secured by mvc with http method then responds based on http method`() { - this.spring.register(AuthorizeRequestsByMvcConfigWithHttpMethod::class.java).autowire() - - this.mockMvc.get("/path") - .andExpect { - status { isOk() } - } - - this.mockMvc.put("/path") { with(csrf()) } - .andExpect { - status { isForbidden() } - } - } - - @Configuration - @EnableWebSecurity - @EnableWebMvc - open class MvcMatcherServletPathHttpMethodConfig { - @Bean - open fun securityFilterChain(http: HttpSecurity): SecurityFilterChain { - http { - authorizeRequests { - authorize(HttpMethod.GET, "/path", "/spring", denyAll) - authorize(HttpMethod.PUT, "/path", "/spring", denyAll) - } - } - return http.build() - } - - @RestController - internal class PathController { - @RequestMapping("/path") - fun path(): String { - return "ok" - } - } - } - - - - @Test - fun `request when secured by mvc with servlet path and http method then responds based on path and method`() { - this.spring.register(MvcMatcherServletPathConfig::class.java).autowire() - - this.mockMvc.perform(MockMvcRequestBuilders.get("/spring/path") - .servletPath("/spring")) - .andExpect(status().isForbidden) - - this.mockMvc.perform(MockMvcRequestBuilders.put("/spring/path") - .servletPath("/spring")) - .andExpect(status().isForbidden) - - this.mockMvc.perform(MockMvcRequestBuilders.get("/other/path") - .servletPath("/other")) - .andExpect(status().isOk) - } -} diff --git a/etc/checkstyle/checkstyle-suppressions.xml b/etc/checkstyle/checkstyle-suppressions.xml index 4c9e12f670..f7c3a56e38 100644 --- a/etc/checkstyle/checkstyle-suppressions.xml +++ b/etc/checkstyle/checkstyle-suppressions.xml @@ -23,7 +23,6 @@ -