security.xml to java config, how to implement a custom securityMetataSource - spring-security

So, in my migration towards a javaconfig style spring security, I'm running into an issue with regards to a custom securityMetadataSource. It doesn't seem to get picked up automatically, and I'm not sure how to include it in the http security wizard. Because we have multiple site configurations that can have various security configurations, we keep the security in a separate site specific config class
#Bean
DefaultFilterInvocationSecurityMetadataSource securityMetadataSource(){
SecurityExpressionHandler<FilterInvocation> securityExpressionHandler = new DefaultWebSecurityExpressionHandler();
LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> map = new LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>>();
processSecurityPath(map,"/signin/**","permitAll");
processSecurityPath(map,"/redirect/**","permitAll");
processSecurityPath(map,"/*/*/account/g_product/add*/**" ,"hasAnyRole('ROLE_ADMIN','ROLE_EDITOR')");
processSecurityPath(map,"/**" ,"permitAll");
ExpressionBasedFilterInvocationSecurityMetadataSource ms = new ExpressionBasedFilterInvocationSecurityMetadataSource(map, securityExpressionHandler);
return ms;
}
private void processSecurityPath(LinkedHashMap<RequestMatcher, Collection<ConfigAttribute>> map, String path, String securityRule){
map.put(new AntPathRequestMatcher(path), Arrays.<ConfigAttribute>asList(new SecurityConfig(securityRule)));
}
And this is the main security config
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilter(myFilterSecurityInterceptor)
.addFilterBefore(authenticationFilter(), UsernamePasswordAuthenticationFilter.class)
.exceptionHandling().accessDeniedHandler(new MyAccessDeniedHandler())
.and()
.authorizeRequests()
// .anyRequest().authenticated() // this should be handled by the DefaultFilterInvocationSecurityMetadataSource that is part of the project specific config
[...]

Related

How to implement config in AbstractHttpConfigurer's *before* local HttpSecurity code

I'm updating an internal library and applications to Spring Boot 3 (which updated to Spring Security 6).
We have common security configuration which I've updated to implement AbstractHttpConfigurer e.g.
public class WebberWebSecurityConfigurerAdapter
extends AbstractHttpConfigurer<WebberWebSecurityConfigurerAdapter, HttpSecurity> {
public void configure(final HttpSecurity http) throws Exception {
http
.authorizeHttpRequests()
.requestMatchers(HEALTH_CHECK_PATH).permitAll()
}
}
The web application then has:
#Configuration
public class SecurityConfig {
#Bean
public SecurityFilterChain config(HttpSecurity http) throws Exception {
http.apply(new WebberWebSecurityConfigurerAdapter());
http
.authorizeHttpRequests()
.requestMatchers("/", "/request-info", "/test").permitAll()
.anyRequest().authenticated();
return http.build();
}
}
This throws the exception:
Caused by: java.lang.IllegalStateException: Can't configure requestMatchers after anyRequest
Presumably because Spring is trying to configure the .requestMatchers(HEALTH_CHECK_PATH).permitAll() line after the .anyRequest().authenticated(); line, despite it being specified first in the config.
How do I get Spring to configure all the upstream library config first, before applying the custom config from the web application itself?

Spring Security exclude URL on custom filter

#SuppressWarnings("SpringJavaAutowiringInspection")
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
#Autowired
private UserDetailsService userDetailsService;
#Autowired
public void configureAuthentication(AuthenticationManagerBuilder
authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder.userDetailsService(userDetailsService);
}
#Bean
public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
return new JwtAuthenticationTokenFilter();
}
#Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/test").permitAll()
.antMatchers("/api/**").permitAll()
.anyRequest().authenticated();
httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
}
I have a custom filter that runs before Spring Security. I want to be able to exclude some URLs (like /test) from the filter and Spring Security and others to be intercepted (like /api/**).
When using postman to test localhost/test it still goes through the filter even though I have antMatchers("/test").permitAll().
How do I bypass the filter?
You can disable the Spring Security filter chain for some URLs, see WebSecurity#ignoring:
Allows adding RequestMatcher instances that should that Spring Security should ignore. Web Security provided by Spring Security (including the SecurityContext) will not be available on HttpServletRequest that match. Typically the requests that are registered should be that of only static resources. For requests that are dynamic, consider mapping the request to allow all users instead.
Example Usage:
webSecurityBuilder.ignoring()
// ignore all URLs that start with /resources/ or /static/
.antMatchers("/resources/**", "/static/**");
Therefore, you can override WebSecurityConfigurerAdapter#configure:
Override this method to configure WebSecurity. For example, if you wish to ignore certain requests.
To ignore path /test you have to add following method to your configuration:
public void configure​(WebSecurity web)
webSecurityBuilder
.ignoring()
.antMatchers("/test");
}

Enabling Spring Security makes Swagger output text/plain instead of HTML

Swagger works! I can interact with http://localhost:8090/sdoc.jsp and everything is fine.
I add the following to pom.xml...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
I also add the following two files:
#Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
if( !Authenticate.authenticate(name, password) )
return null;
List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
Authentication auth = new UsernamePasswordAuthenticationToken(name, password, grantedAuths);
return auth;
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
and
#Configuration
#EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests()
.anyRequest().permitAll()
.antMatchers("/**").authenticated().and()
.formLogin().loginPage("/login").permitAll().and()
.httpBasic()
;
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new CustomAuthenticationProvider());
}
}
At this point if I visit the same URL that was previously working I now instead get a response type of "text/plain" and instead of a pretty HTML looking browser I see source code.
If I revert the change and remove the two files from project and remove JAR file it works again.
How do I get Spring Security and Swagger to play nice? What am I doing wrong.
I suspect this is due to Spring-Security's effect on the content-type headers (http://docs.spring.io/spring-security/site/docs/3.2.0.CI-SNAPSHOT/reference/html/headers.html#headers-content-type-options).
From the docs -
Historically browsers, including Internet Explorer, would try to guess the content type of a request using content sniffing. This allowed browsers to improve the user experience by guessing the content type on resources that had not specified the content type. For example, if a browser encountered a JavaScript file that did not have the content type specified, it would be able to guess the content type and then execute it.
The problem with content sniffing is that this allowed malicious users to use polyglots (i.e. a file that is valid as multiple content types) to execute XSS attacks. For example, some sites may allow users to submit a valid postscript document to a website and view it. A malicious user might create a postscript document that is also a valid JavaScript file and execute a XSS attack with it.
Again, from the docs, in order to override the default -
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
// ...
.headers()
.contentTypeOptions();
}
}
Wow, I figured it was something along these lines. Thanks so much
When I tried this and it started working
.headers()
.disable()
I narrowed the default contentTypeOptions down to..
.headers()
//.contentTypeOptions() // If this is uncommented it fails.
.xssProtection()
.cacheControl()
.httpStrictTransportSecurity()
.frameOptions()
.and()

Disable Basic Authentication while using Spring Security Java configuration

I am trying to secure a web application using Spring Security java configuration.
This is how the configuration looks:-
#Configuration
#EnableWebMvcSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private String googleClientSecret;
#Autowired
private CustomUserService customUserService;
/*
* (non-Javadoc)
*
* #see org.springframework.security.config.annotation.web.configuration.
* WebSecurityConfigurerAdapter
* #configure(org.springframework.security.config
* .annotation.web.builders.HttpSecurity)
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/","/static/**", "/resources/**","/resources/public/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic().disable()
.requiresChannel().anyRequest().requiresSecure();
// #formatter:on
super.configure(http);
}
#Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
// #formatter:off
auth
.eraseCredentials(true)
.userDetailsService(customUserService);
// #formatter:on
super.configure(auth);
}
}
Notice that I have explicitly disabled HTTP Basic authentication using:-
.httpBasic().disable()
I am still getting HTTP Authenticaton prompt box while accessing a secured url. Why?
Please help me fix this.
I just want to render the default login form that comes bundled.
Spring Boot Starter Version : 1.1.5
Spring Security Version : 3.2.5
Thanks
First of all, calling super.configure(http); will override whole your configuration you have before that.
Try this instead:
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin()
.and()
.httpBasic().disable();
In case you use Spring Boot, the documentation states:
To switch off the Boot default configuration completely in a web
application you can add a bean with #EnableWebSecurity
So if you want to fully customize itself that might be an option.
Just to make it clear... You just need to put #EnableWebSecurity annotation on your main application class or application configuration class.
You can disable the formLogin through the HttpSecurity instance as follow:
http.authorizeRequests().antMatchers("/public/**").permitAll()
.antMatchers("/api/**").hasRole("USER")
.anyRequest().authenticated()
.and().formLogin().disable();
This will lead receiving 403 Http error when trying to access any secured resource
Anonymous option worked for me. My code like
http.csrf().disable().headers().frameOptions().sameOrigin().and().
authorizeRequests().anyRequest().anonymous().and().httpBasic().disable();
Suitable for Spring Boot or folks using OAuth
#Profile("test")
#EnableWebSecurity
static class BasicWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().anonymous().and().httpBasic().disable();
}
}
If you are using #EnableOAuth2Client or #EnableResourceServer, then in test profile switch to basic auth and then disable the same. In Spring Boot,to switch off the spring security default configuration completely in a web application you need to add a bean with #EnableWebSecurity
The following worked for me:
http
.authorizeRequests()
.anyRequest().permitAll();

Spring Security 3.2 setting authenticationEntryPoint in HttpSecurity has no effect (Java-Config)

I want to convert spring security configuration from xml to java config.
Is't nearly done, the last issue is the AuthenticationEntryPoint. The settings of it in HttpSecurity will be ignored.
I use Spring security 3.2.0.M2
Snipped of SecurityConfig.class
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterAfter(httpPayloadFilter(), ChannelProcessingFilter.class)
.addFilterAfter(httpRestLoginFilter(), SecurityContextPersistenceFilter.class)
.authorizeUrls()
.antMatchers("/**").hasRole("USER")
.antMatchers("/secure/clientident/**").hasRole("REQUESTVALID")
.and()
.httpBasic().authenticationEntryPoint(delegatingAuthenticationEntryPoint());
}
#Bean
public DelegatingAuthenticationEntryPoint delegatingAuthenticationEntryPoint() {
ELRequestMatcher matcher = new ELRequestMatcher("hasHeader('user-agent', 'Mozilla') or " +
"hasHeader('user-agent', 'Chromium') or " +
"hasHeader('user-agent', 'Chrome') or " +
"hasHeader('user-agent', 'Safari')");
LinkedHashMap<RequestMatcher, AuthenticationEntryPoint> map =
new LinkedHashMap<RequestMatcher, AuthenticationEntryPoint>();
map.put(matcher, new BasicAuthenticationEntryPoint());
DelegatingAuthenticationEntryPoint delegatingAuthenticationEntryPoint = new DelegatingAuthenticationEntryPoint(map);
delegatingAuthenticationEntryPoint.setDefaultEntryPoint(new Http403ForbiddenEntryPoint());
return delegatingAuthenticationEntryPoint;
}
I always get the "HTTP 403" (guess Http403ForbiddenEntryPoint) on client side.
I also have tried an easier config without delegatingAuthenticationEntryPoint like.
.httpBasic().authenticationEntryPoint(new BasicAuthenticationEntryPoint())
this will not work too.
Has anyone an idea what I'm doing wrong?
Add:
Should have locked better. Found another post about this issue.
need spring security java config example showing basic auth only
A Ticket SEC-2198 has also been placed.
current workaround.
.exceptionHandling()
.authenticationEntryPoint(delegatingAuthenticationEntryPoint())
.and()
.httpBasic();

Resources