Spring Boot security: Can't configure antMatchers after anyRequest - spring

I am trying to filter url through #EnableActiveDirectoryOAuth2ResourceServer. I have configured the bean of type ResourceServerConfigurer according to docs but for some reason I am getting the following error:
Caused by: java.lang.IllegalStateException: Can't configure antMatchers after anyRequest
Code:
#EnableActiveDirectoryOAuth2ResourceServer
#EnableWebSecurity
public class OAuthConfiguration {
#Bean
public ResourceServerConfigurer resourceServerConfigurer() {
return new ResourceServerConfigurerAdapter() {
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf()
.disable()
.requestMatcher(httpGetMethodForPath("/url1"))
.requestMatcher(httpGetMethodForPath("/url2"))
.requestMatcher(httpGetMethodForPath("/url3"))
.authorizeRequests()
.anyRequest().access("#oauth2.isClient() and #oauth2.hasScope('myscope')");
}
};
}
private RequestMatcher httpGetMethodForPath(String URI) {
return request -> request.getRequestURI().contains(URI) && HttpMethod.GET.name().equalsIgnoreCase(request.getMethod());
}
}

Related

An expected CSRF token cannot be found

I'm trying to disable Spring security into latest Spring Cloud using this configuration:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
#Order(SecurityProperties.DEFAULT_FILTER_ORDER)
public class WebSecurityConfigSec extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().cors().disable()
.authorizeRequests().anyRequest().permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/**");
}
}
application.yml
spring:
main:
allow-bean-definition-overriding: true
security:
ignored=/**:
enable-csrf: false
I also tried to add:
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
}
}
But it's not working.
I get error: An expected CSRF token cannot be found
18:16:24.537 [boundedElastic-2] DEBUG DefaultWebSessionManager[lambda$createWebSession$3:94] - Created new WebSession.
18:16:24.540 [boundedElastic-2] DEBUG HttpWebHandlerAdapter[traceDebug:91] - [1ffd0a30] Completed 403 FORBIDDEN
Do you know how I can solve this issue?
Exclude the MVC dependencies from pom.xml
And add:
spring:
main:
web-application-type: reactive
This worked for me; I was getting CSRF error as spring security used in Spring MVC was enabled.
I Fixed this by
#Bean
SecurityWebFilterChain springSecurityFilterChain(
ServerHttpSecurity http,
ReactiveClientRegistrationRepository clientRegistrationRepository
){
return http
...
.csrf(csrf -> csrf.csrfTokenRepository(
CookieServerCsrfTokenRepository.withHttpOnlyFalse()))
.build();
}
#Bean
WebFilter csrfWebFilter() {
//A filter with the only purpose of subscribing to the CsrfToken reactive stream and ensuring its value is extracted correctly
return (exchange, chain) -> {
exchange.getResponse().beforeCommit(() -> Mono.defer(() -> {
Mono<CsrfToken> csrfToken =
exchange.getAttribute(CsrfToken.class.getName());
return csrfToken != null ? csrfToken.then() : Mono.empty();
}));
return chain.filter(exchange);
};
}

EL1057E: No bean resolver registered in the context to resolve access to bean

I am using this resource server for authorizing request but whenever it tries to evaluate expression-"#ipWhitelistingProvider.isItValid(request)" it gives error stating- EL1057E: No bean resolver registered in the context to resolve access to bean 'ipWhitelistingProvider'.
#Profile("default")
#EnableResourceServer
#EnableWebSecurity
#Configuration
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Autowired
IpWhitelistingProvider ipWhitelistingProvider;
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/config/**").access("#ipWhitelistingProvider.isItValid(request) or #oauth2.hasScope('config')")
.anyRequest().authenticated()
.and().csrf().disable();
}
#Component("ipWhitelistingProvider")
public class IpWhitelistingProvider{
#Value("${ip.whitelist:1}")
List<String>whitelist;
String ipAcessWhitelistingString;
public boolean isItValid(HttpServletRequest request) {
String ip=request.getRemoteAddr();
if(whitelist.contains(ip)) {
return true;
}
else {
return false;
}
}
}
I managed to workaround this issue by doing the following:
My default OAuth2 Expression Handler's Bean Resolver was null, so I added a #Bean with OAuth2WebSecurityExpressionHandler that explicitly sets the application context.
#Bean
public OAuth2WebSecurityExpressionHandler oAuth2WebSecurityExpressionHandler(ApplicationContext applicationContext) {
OAuth2WebSecurityExpressionHandler expressionHandler = new OAuth2WebSecurityExpressionHandler();
expressionHandler.setApplicationContext(applicationContext);
return expressionHandler;
}
In my ResourceServerConfigurerAdapter, I configured resources and passed above bean
#Autowired
private OAuth2WebSecurityExpressionHandler expressionHandler;
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.expressionHandler(expressionHandler);
}

#RefreshScope together with #Order

I'm trying to use #RefreshScope with #Order. Bootrun fails with error
#Order on WebSecurityConfigurers must be unique. Order of 2147483636 was already used on com.company.rest.config.ActuatorSecurityConf$$EnhancerBySpringCGLIB$$1e7c9a55#6559faf1, so it cannot be used on com.company.rest.config.ActuatorSecurityConf$$EnhancerBySpringCGLIB$$1e7c9a55#6559faf1 too.
#RefreshScope makes the bean getting initialized more than once because it uses proxy. Is it possible to use #RefreshScope with #Order?
#Configuration
#Order(ManagementServerProperties.ACCESS_OVERRIDE_ORDER)
#RefreshScope
public class ActuatorSecurityConf extends WebSecurityConfigurerAdapter {
private ApplicationProperties properties;
public ActuatorSecurityConf(ApplicationProperties properties) {
this.properties = properties;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// #formatter:off
auth.inMemoryAuthentication()
.withUser(properties.getActuatorUsername())
.password(properties.getActuatorUserPassword())
.roles("ACTUATOR");
// #formatter:on
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.antMatcher("/manage/**")
.csrf().disable()
.cors()
.and()
.authorizeRequests()
.antMatchers("/manage/info").permitAll()
.anyRequest().hasRole("ACTUATOR")
.and()
.httpBasic();
// #formatter:on
}
}
Update:
Removed #RefreshScope from #Configuration as suggested but the error still occurs.
#Order(ManagementServerProperties.ACCESS_OVERRIDE_ORDER) is required to place it before another WebSecurityConfigurerAdapter in the app with
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER).
#Order(ManagementServerProperties.ACCESS_OVERRIDE_ORDER)
public class ActuatorSecurityConf extends WebSecurityConfigurerAdapter {
private ApplicationProperties properties;
#Autowired
public ActuatorSecurityConf(ApplicationProperties properties) {
this.properties = properties;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// same
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// same
}
}
#Configuration
class ApplicationConfig {
#Bean
#RefreshScope
public ApplicationProperties applicationProperties() {
return new ApplicationProperties();
}
#Bean
#RefreshScope
public ActuatorSecurityConf actuatorSecurityConf() {
return new ActuatorSecurityConf(applicationProperties());
}
}
Using Spring boot 1.5.4.RELEASE

Is it a Spring `Dalston` bug? [duplicate]

I am trying to upgrade a sample Spring Boot and Spring Cloud Security with OAuth from Spring Boot 1.4.1 + Brixton.RELEASE to Spring Boot 1.5.3+ Dalston.RELEASE. However, it has been a long hard try without any success.
It seems for some reason the resource server security filter chain is not getting fired. As a result the call to "/me" or "/user" is being handled by default security filter chain. I am thinking if this is a problem with order. But tried to explicitly set the order of the security filter chains as follows
Auth Server 6
Web Default 5
Resource server 3 (hard coded ??)
Since the default filter chain is handling the request, it is always going to the login page, which generates HTML and the SSO client (server side thymeleaf web UI) fails.
The source code is below
Authorization server
#SpringBootApplication
public class MyAuthServerApplication {
public static void main(String[] args) {
SpringApplication.run(MyAuthServerApplication.class, args);
}
}
Then the authorization server configuration
#Configuration
#EnableAuthorizationServer
#Order(6)
public class AuthorizationServerConfigurer extends A
uthorizationServerConfigurerAdapter {
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws
Exception {
clients.inMemory()
.withClient("myauthserver")
.secret("verysecretpassword")
.redirectUris("http://localhost:8080/")
.authorizedGrantTypes("authorization_code", "refresh_token")
.scopes("myscope")
.autoApprove(true);
}
}
Then the resource server class
#Configuration
#EnableResourceServer
public class ResourceServerConfigurer extends
ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.antMatcher("/user")
.authorizeRequests()
.anyRequest()
.authenticated();
}
}
The web MVC configuration
#Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("login").setViewName("login");
}
}
The default spring security configuration
#Configuration
#EnableWebSecurity
#Order(9)
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and().csrf()
.and().formLogin().loginPage("/login");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("admin").roles("USER", "ADMIN");
}
}
The resource controller
#RestController
public class ResourceController {
#RequestMapping(value = { "/user" }, produces = "application/json")
public Map<String, Object> user(OAuth2Authentication user) {
Map<String, Object> userDetails = new HashMap<>();
userDetails.put("user", user.getUserAuthentication().getPrincipal());
userDetails.put("authorities",
AuthorityUtils.
authorityListToSet(user.getUserAuthentication().getAuthorities()));
return userDetails;
}
}
Finally the configuration - application.yml for the auth server
server:
port: 9090
contextPath: /auth
logging:
level:
org.springframework: INFO
org.springframework.security: DEBUG
The login.html Thymeleaf template is not shown here.
OAUTH 2 SSO Client Web App
#SpringBootApplication
public class MyWebsiteApplication {
public static void main(String[] args) {
SpringApplication.run(MyWebsiteApplication.class, args);
}
}
The web security configuration
#Configuration
#EnableOAuth2Sso
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/").permitAll() // Allow navigating to index
page,
.anyRequest().authenticated(); // but secure all the other URLs
}
}
The web controller
#Controller
public class MyWebsiteController {
/**
* Default index page to verify that our application works.
*/
#RequestMapping("/")
#ResponseBody
public String helloWorld() {
return "Hello world!";
}
/**
* Return a ModelAndView which will cause the
'src/main/resources/templates/time.html' template to be rendered,
* with the current time.
*/
#RequestMapping("/time")
public ModelAndView time() {
ModelAndView mav = new ModelAndView("time");
mav.addObject("currentTime", getCurrentTime());
return mav;
}
private String getCurrentTime() {
return LocalTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME);
}
}
The application configuration - application.yml for the client web app
server:
port: 8080
contextPath: /
security:
oauth2:
client:
accessTokenUri: http://localhost:9090/auth/oauth/token
userAuthorizationUri: http://localhost:9090/auth/oauth/authorize
clientId: myauthserver
clientSecret: verysecretpassword
resource:
userInfoUri: http://localhost:9090/auth/user
The Thymeleaf template for the time.html page is not shown here.
There must be some subtle little configuration thats wrong or some bug I do not know. Any help or ideas highly appreciated.
Solution
Guess was right the ordering of the security filter chain got was changed. Here is the link to the
Spring 1.5.x release note
Modified code is here and will upload it to Github later. All changes on the auth server configuration.
The Spring security configuration - remove the #Order annotation.
#Configuration
#EnableWebSecurity
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated()
.and().csrf()
.and().formLogin().loginPage("/login");
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER")
.and()
.withUser("admin").password("admin").roles("USER", "ADMIN");
}
}
Then change the application.yml as follows
server:
port: 9090
contextPath: /auth
logging:
level:
org.springframework: INFO
org.springframework.security: DEBUG
security:
oauth2:
resource:
filter-order : 3
That's it then the time is displayed on the client application /time url after authentication on the auth server.

Spring Security PreAuthorize Custom Method Bean resolver is not registered?

Im just learning Spring, going through tutorials and testing possibilities. One of my goals is to secure a Service Method using a Custom Method and the PreAuthorize annotation. Unfortunaly the Bean holding the custom Method cannot be resolved and I dont know why. Maybe someone can see the error at first sight.
Bean holding the custom Method:
#Component("mySecurityService")
public class MySecurityService {
public boolean hasPermission() {
return true; //simple implementation just to look if has permission is called
}
}
Service to be Secured:
public interface OrderService {
#PreAuthorize("#mySecurityService.hasPermission()")
public AllOrdersEvent requestAllOrders(RequestAllOrdersEvent requestAllCurrentOrdersEvent);
public OrderDetailsEvent requestOrderDetails(RequestOrderDetailsEvent requestOrderDetailsEvent);
public OrderStatusEvent requestOrderStatus(RequestOrderStatusEvent requestOrderStatusEvent);
public OrderCreatedEvent createOrder(CreateOrderEvent event);
public OrderUpdatedEvent setOrderPayment(SetOrderPaymentEvent setOrderPaymentEvent);
public OrderDeletedEvent deleteOrder(DeleteOrderEvent deleteOrderEvent);
}
Java Security Config:
#EnableWebSecurity
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("letsnosh").password("noshing").roles("USER");
}
#Override
#Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
#Bean(name = "mySecurityService")
MySecurityService createSecurityService(){return new MySecurityService();}
#Override
protected void configure(HttpSecurity http) throws Exception {
/*
http.authorizeUrls()
.antMatchers("/aggregators*//**//**").hasRole("USER")
.anyRequest().anonymous()
.and()
.httpBasic();
*/
}
}
Error:
No bean resolver registered in the context to resolve access to bean 'mySecurityService'
Hello I solved the problem. It was connected to the Version of Spring Security.
I got the Version from the official Spring Rest Tutotrial : 3.2.0.M2
In this version I had to declare the Security Context as follows:
#EnableWebSecurity
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("letsnosh").password("noshing").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeUrls()
.antMatchers("/aggregators/**").hasRole("USER")
.anyRequest().anonymous()
.and()
.httpBasic();
}
}
Here the error was thrown.
But using a newer Version of Spring Security: 3.2.5.RELEASE
I could declare the Config this way:
#EnableWebSecurity
#Configuration
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeUrls()
.antMatchers("/aggregators*//**//**").hasRole("USER")
.anyRequest().anonymous()
.and()
.httpBasic();
}
And the bean could be resolved, using either #Component Annotaions directly on the MySecurityService class or #Bean annotations on a config class method which returns a MySecurityService instance.

Resources