WebSecurity.ignoring() in ResourceServerConfigurerAdapter - spring-boot

I'm currently implementing oauth2 through Cognito for my Spring Boot API. As a part of configuring Spring Security, I set up my ResourceServerConfigurerAdapter with an override of configure(HttpSecurity http). However I also needed to use the configure(WebSecurity webSecurity) override in order to use WebSecurity.ignoring. Several of my endpoints need to be publicly accessible.
So this led to me having a WebSecurityConfigurerAdapter as well as my ResourceServerConfigurerAdapter. The problem arose with csrf though. The ResourceServerConfig is disabling csrf, but the WebSecurityConfig was apparently taking precedence and now all my endpoints require csrf. Overriding the configure(HttpSecurity) in the WebSecurityConfig to disable csrf fixes the issue but seems wrong to me. I'd like to not have to override and mess with HttpSecurity twice, and ResourceServerConfig doesn't have a webSecurity.ignoring option to my knowledge.
Here's my code for the two below
WebSecurityConfiguration
#Configuration
#EnableWebSecurity(debug = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
//Disabling this fixes the csrf issue.
http.csrf().disable();
}
#Override
public void configure(WebSecurity webSecurity) throws Exception {
webSecurity.ignoring().antMatchers("/api/auctions/**");
webSecurity.ignoring().antMatchers("/api/lots/**");
}
}
ResourceServerConfiguration
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends ResourceServerConfigurerAdapter {
private final ResourceServerProperties resource;
public SecurityConfiguration(ResourceServerProperties resource) {
this.resource = resource;
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.cors();
http.csrf().disable();
http.authorizeRequests().antMatchers("/**").permitAll().anyRequest().permitAll();
}
// Enabling Cognito Converter
#Bean
public TokenStore jwkTokenStore() {
return new JwkTokenStore(
Collections.singletonList(resource.getJwk().getKeySetUri()),
new CognitoAccessTokenConverter(),
null);
}
}
I mostly just want some guidance on what the best path on this is. I've done some digging online and there's conflicting and outdated answers, and everyone seems to be doing very different things with these configurations.

Related

Authentication provider per url pattern - Spring Boot

I faced problem when configuring different auth providers per url pattern using Spring Boot security. I am trying to configure security in Spring Boot app and want to have swagger behind basic auth and all API is secured only by token. I have it almost working, but noticed that API except the fact that it is secured by token which is verified by IDAuthProvider class it also is secured by basic auth. I do not want that and also noticed that if I removed line:
sessionCreationPolicy(SessionCreationPolicy.STATELESS).
it seems to be working correctly, but still header Basic {token} is being added in request which is something I do not want...
Do you know how can I configure it to make all swagger stuff secured by basic auth and API stuff secured by token?
My configuration looks like below:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Configuration
#Order(1)
public class SwaggerSecurityConfig extends WebSecurityConfigurerAdapter {
private final AuthenticationProvider userPassAuthProvider;
#Autowired
SwaggerSecurityConfig(UserPassAuthProvider userPassAuthProvider) {
this.userPassAuthProvider = userPassAuthProvider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/swagger**").
authorizeRequests().
antMatchers("/swagger**").authenticated().
and().httpBasic().and().csrf().disable();
}
#Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(userPassAuthProvider);
}
}
#Configuration
#Order(2)
public class APISecurityConfig extends WebSecurityConfigurerAdapter {
private final AuthenticationProvider idAuthProvider;
#Autowired
APISecurityConfig(IDAuthProvider idAuthProvider) {
this.idAuthProvider = idAuthProvider;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/api/v1/**").
authorizeRequests().anyRequest().authenticated().
and().
addFilterBefore(idpAuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class).sessionManagement().
and().
csrf().disable();
}
#Override
public void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.authenticationProvider(idAuthProvider);
}
IDPAuthenticationFilter idpAuthenticationFilter(AuthenticationManager auth) {
return new IDPAuthenticationFilter(auth, new OrRequestMatcher(new AntPathRequestMatcher(ApiRouter.API_PATH + "/**", HttpMethod.GET.toString()), new AntPathRequestMatcher(ApiRouter.API_PATH + "/**", HttpMethod.POST.toString()), new AntPathRequestMatcher(ApiRouter.API_PATH + "/**", HttpMethod.DELETE.toString()), new AntPathRequestMatcher("/swagger**", HttpMethod.GET.toString())));
}
}
}

How to tune authenticationEntryPoint behaviour Spring Security

I have Spring Boot 2 based Security Gateway performing OAuth2 authentication sitting before GUI app and back-end.
It is configured like
#Configuration
#EnableOAuth2Client
#EnableWebSecurity
public class SecurityGatewayConfig extends WebSecurityConfigurerAdapter{
#Bean
public SecurityGatewayAuthenticationFilter filter() {
return new SecurityGatewayAuthenticationFilter("/login");
}
#Override
public void configure(HttpSecurity http) {
http
.addFilterAfter(new OAuth2ClientContextFilter(), AbstractPreAuthenticatedProcessingFilter.class)
.addFilterAfter(filter(), OAuth2ClientContextFilter.class)
.httpBasic().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))
.and()
...
It redirect requests to /login and SecurityGatewayAuthenticationFilter performs authentication against external OAuth2 provider.
It is good for GIU app. However, when accessing back-end services(they have /api/ in the path) I need different behaviour: If request is not authenticated, do not redirect, but immediately return 401 error.
Any idea, how to configure Spring Security for that?
If i got you questions right, what you can do is work with different ConfigurationAdapters. The basic idea looks like:
#Order(1)
#Configuration
#EnableOAuth2Sso
public static class SecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("defaultMatcher")
private RequestMatcher defaultMatcher;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(defaultMatcher)...
}
}
#Order(2)
#Configuration
public static class OtherConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(yourRequestMatcher())...
}
}
Spring will evalutate each request in the order you add with Order() if you use #EnableResourceServer, this will always have Order(3)
You can then build your request matchers as example like this (in this example it matches all, but excludes explicitly some other):
#Bean
public RequestMatcher defaultMatcher(#Qualifier("apiMatcher") RequestMatcher api, #Qualifier("anyother") RequestMatcher anyother) {
final RequestMatcher all = new AntPathRequestMatcher("/**");
final RequestMatcher nonApi = new NegatedRequestMatcher(new OrRequestMatcher(api, anyother));
return new AndRequestMatcher(all, nonApi);
}
Hope that helps.
best regards,
WiPu
you need add entry point filter
#Component
public final class CustomAuthenticationEntryPoint implements
AuthenticationEntryPoint {
#Override
public void commence(final HttpServletRequest request, final
HttpServletResponse response, final AuthenticationException
authException) throws IOException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
When a client accesses resources without authentication...

Spring Security does not intercept requests

I have a legacy application in which I have added Spring Web MVC libraries in order to expose a new Rest API.
I am struggling integrating spring-security in order to intercept the incoming requests. I have set up a security configuration class
#EnableWebSecurity
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.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}
and a security application initializer
public class SecurityWebApplicationInitializer extends
AbstractSecurityWebApplicationInitializer {
}
following relevant guides.
Using debugger I verified that during initializing my configuration class is loaded. My problem is that my requests are not intercepted as expected.
Since you're already using Spring MVC, go to your class that initializes your application. If you're using Java Config, it most likely extends AbstractAnnotationConfigDispatcherServletInitializer.
Add your SecurityConfig to its "root config classes":
public class MySpringMmvcInitializer extends
AbstractAnnotationConfigDispatcherServletInitializer {
...
#Override
protected abstract Class<?>[] getRootConfigClasses() {
return new Class[] { ..., SecurityConfig.class};
}
}
I think you forgot the #configuration annotation, try this
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}

#Value annotation return empty value in an AbstractAuthenticationProcessingFilter filter

I'm developing a springboot application with spring security.
I'm trying to make my custom authentication filter reading some properties from the application.properties file without success.
I've read this other question which is similar but within a different context (not related to spring security filters). The reason for the failure makes sense to me but I've tried the way suggested with the DelegatingFilterProxy but without success (to be fair, I didn't really get the meaning of the part added to the Application class). The other solution does not fit my case as I don't have any onStartup method to override.
Here is the code I'm using:
public class JWTAuthenticationFilter extends
AbstractAuthenticationProcessingFilter {
#Value("${app.jwtSecret}")
public String SECRET2;
Almost the same code, in a controller class, works fine:
#RestController
#RequestMapping("/api")
#CrossOrigin
#EnableAutoConfiguration
public class UsersController {
#Value("${app.jwtSecret}")
public String SECRET2;
But I can't make it work in the filter. I'm using springboot 2.0.3.
Any suggestion? Is the DelegatingFilterProxy the right approach in this situation? In that case, any example/article I could follow?
Thanks,
Michele.
UPDATE:
to fully answer to the first comment, the filter is called by the following class:
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Autowired
private LdapAuthenticationProvider ldapAuthenticationProvider;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/secureLogin").permitAll()
.antMatchers(HttpMethod.GET, "/api").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.addFilterBefore(new JWTAuthenticationFilter(authenticationManager()), UsernamePasswordAuthenticationFilter.class)
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(ldapAuthenticationProvider);
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
No need to use #Value in filter class:
public class JWTAuthenticationFilter extends
AbstractAuthenticationProcessingFilter {
private String secret;
//... setter for secret
But inject the secret in the config class:
#EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
#Value("${app.jwtSecret}")
public String secret;
//...
#Override
protected void configure(HttpSecurity http) throws Exception {
JWTAuthorizationFilter jwtFilter = new JWTAuthorizationFilter(authenticationManager());
//set secret
//...
}

EnableResourceServer breaks oAuth2 authorization server

I implemented oAuth2 authorization server using Spring Boot version 1.5.2.RELEASE. The authorization server supports implicit flow. With the WebSecurityConfig below the login form (http://localhost:8200/login) works well.
#Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JpaUserDetailsService userDetailsService;
#Bean
#Override
public UserDetailsService userDetailsServiceBean() throws Exception {
return userDetailsService;
}
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
#Bean
public AuthenticationProvider authenticationProvider() throws Exception {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setUserDetailsService(userDetailsServiceBean());
provider.setPasswordEncoder(passwordEncoder());
return provider;
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return new ProviderManager(singletonList(authenticationProvider()));
}
#Override
public void configure(WebSecurity web) {
web.ignoring()
.antMatchers("/")
.antMatchers("/docs/**")
.antMatchers("/swagger/**")
.antMatchers("/token/**")
.antMatchers("/v2/*")
.antMatchers(HttpMethod.OPTIONS, "/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().antMatchers("/login**").permitAll().anyRequest().authenticated().and()
.formLogin().loginPage("/login").permitAll().and()
.logout().permitAll();
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
}
I want resource server be a part of the same application. The purpose is I need a /me endpoint that will provide me details of logged in user and endpoints for managing users. But as soon as I add ResourceServerConfig annotated with EnableResourceServer below I start getting an error "Full authentication is required to access this resource" when I request http://localhost:8200/login.
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
public static final String RESOURCE_ID = "proclaim-auth";
#Autowired
private ResourceServerTokenServices tokenServices;
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources
.resourceId(RESOURCE_ID)
.tokenServices(tokenServices);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/api/ **").authenticated();
}
}
I suspect that resource server security chain precedes authorization server security chain. I tried to annotate WebSecurityConfig with annotation Order but it did not fix my problem:
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
...
}
What am I doing wrong? Please advise.
Thanks in advance!
EDIT 1
I added method configure(HttpSecurity http) into ResourceServerConfig and changed value of Order annotation to -1 on WebSecurityConfig. Now the security filted defined in WebSecurityConfig is applied and the one defined in ResourceServerConfig is ignored. So when I call /me endpoint with valid token I'm redirected to login page.
The cause of the problem was wrong configuration of http security in the ResourceServerConfig class. The correct configuration is as follows:
#Override
public void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/api/**").and()
.authorizeRequests().anyRequest().authenticated();
}
The requestMatchers will ensure that only requests on paths starting with "/api/" will be processed by this security chain. All other requests will be passed to the security chain defined in the WebSecurityConfig class. I was missing this in my config so all requests were processed by the ResourceServerConfig security chain and none request reached the WebSecurityConfig security chain.

Resources