How to disable csrf in spring security for only localhost? - spring-boot

I have working spring boot application in which csrf is enabled but now I want to disable it only for localhost. any request from other domain must underpass csrf security but for localhost, I want to disable it. how can I achieve that?
I know how to disable it by changing
#Configuration
#EnableWebMvcSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf.disable();
}
}
the above code disabled csrf but I want to disable csrf for the only localhost.
Can you please help me?
EDIT: I know how to do it by two profile. Thanks #daren for your detailed answer.

You could use Spring Profiles to achieve what you are looking to do.
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-profiles.html
At it's simplest you could have two configurations
#Configuration
#EnableWebMvcSecurity
#Profile("!deployed") //Not(!) deployed profile
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf.disable();
}
}
And in deployed regions active the deployed profile.
#Configuration
#EnableWebMvcSecurity
#Profile("deployed")
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf.enable();
}
}
Depending on what security configuration you are doing you could do the inverse of this and active a local profile by default which would do the disabling.

You can use the CsrfConfigurer#requireCsrfProtectionMatcher method and use a RequestMatcher which checks the request local vs remote address e.g.
private RequestMatcher csrfProtectionMatcher() {
final Set<String> allowedMethods = ImmutableSet.of("GET", "HEAD", "TRACE", "OPTIONS");
return request -> !allowedMethods.contains(request.getMethod()) && !(request.getLocalAddr().equals(request.getRemoteAddr()));
}

Related

disable spring formlogin and basic auth

I have the following spring boot 2.0 config but I am still getting the basic auth login screen. I DO NOT want to disable all spring security like almost every post on the internet suggests. I only want to stop the form login page and basic auth so I can use my own.
I have seen all the suggestions with permitAll and exclude = {SecurityAutoConfiguration.class} and a few others that I can't remember anymore. Those are not what I want. I want to use spring security but I wan my config not Spring Boots. Yes I know many people are going to say this is a duplicate but I disagree because all the other answers are to disable spring security completely and not just stop the stupid login page.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class CustomSecurity extends WebSecurityConfigurerAdapter {
private final RememberMeServices rememberMeService;
private final AuthenticationProvider customAuthProvider;
#Value("${server.session.cookie.secure:true}")
private boolean useSecureCookie;
#Inject
public CustomSecurity(RememberMeServices rememberMeService, AuthenticationProvider customAuthProvider) {
super(true);
this.rememberMeService = rememberMeService;
this.bouncerAuthProvider = bouncerAuthProvider;
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/v2/**").antMatchers("/webjars/**").antMatchers("/swagger-resources/**")
.antMatchers("/swagger-ui.html");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().disable().formLogin().disable();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).headers().frameOptions().disable();
http.authenticationProvider(customAuthProvider).authorizeRequests().antMatchers("/health").permitAll()
.anyRequest().authenticated();
http.rememberMe().rememberMeServices(rememberMeService).useSecureCookie(useSecureCookie);
http.exceptionHandling().authenticationEntryPoint(new ForbiddenEntryPoint());
}
}
If you want to redirect to your own login page, i can show your sample code and configuration
remove the http.httpBasic().disable().formLogin().disable();, you should set your own login page to redirect instead of disable form login
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/my_login").permitAll().and().authorizeRequests().anyRequest().authenticated();
http.formLogin().loginPage("/my_login");
}
then create your own LoginController
#Controller
public class LoginController {
#RequestMapping("/my_login")
public ModelAndView myLogin() {
return new ModelAndView("login");
}
}
you can specified the login with thymeleaf view resolver

Spring Boot 2.0 disable default security

I want to use Spring Security for JWT authentication. But it comes with default authentication. I am trying to disable it, but the old approach of doing this - disabling it through application.properties - is deprecated in 2.0.
This is what I tried:
#Configuration
public class StackWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.httpBasic().disable();
// http.authorizeRequests().anyRequest().permitAll(); // Also doesn't work.
}
}
How can I simply disable basic security?
UPDATE
It might be nice to know that I am not using web mvc but web flux.
Screenshot:
According to the new updates in Spring 2.0, if Spring Security is on the classpath, Spring Boot will add #EnableWebSecurity.So adding entries to the application.properties ain't gonna work (i.e it is no longer customizable that way). For more information visit the official website Security changes in Spring Boot 2.0
Albeit not sure about your requirement exactly, I could think of one workaround like the following:-
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception{
http.authorizeRequests().antMatchers("/").permitAll();
}
}
Hope this helps.
From Spring Boot 2.1 on, if you include spring-boot-actuator, it does not suffice anymore to only exclude SecurityAutoconfiguration, you also need to exclude ManagementWebSecurityAutoConfiguration, like so:
#SpringBootApplication(exclude = { SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class })
According to the reference documentation, the Security configuration for allowing all requests with WebFlux should look like this:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
#Configuration
public class SecurityConfig {
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.authorizeExchange().anyExchange().permitAll();
return http.build();
}
}
This worked for me:
#Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable().authorizeRequests().anyRequest().permitAll();
}
}
You can add/modify the following to your Application class:
#SpringBootApplication(exclude = { SecurityAutoConfiguration.class })
public class MyApplication {
}
Adding some fresh answer, I assume all use actuator, if not I'd bet one class exclusion should be sufficient, I managed to disable through properties:
spring:
autoconfigure:
exclude: ${spring.autoconfigure.sac}, ${spring.autoconfigure.mwsas}
sac: org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
mwsas: org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration
I've referenced two auto-config classes through property to keep the length intact (note that IntelliJ Ultimate will cry if you reference it like that as it has no clue what are these placeholder values and if they are actually legit classes, so inline if that annoys you).
Application however does not fail to start as claimed by:
https://www.baeldung.com/spring-boot-security-autoconfiguration
if you just disable SecurityAutoConfiguration
If it did work, you will stop seeing auto generated password and it is a little bit less confusing than the accepted answer, as dev reading the log won't get confused by generated password for basic auth while security allows all.
Why just disabling main auto config class isn't enough is because of this fella:
#Configuration
class ManagementWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.requestMatchers(
EndpointRequest.to(HealthEndpoint.class, InfoEndpoint.class))
.permitAll().anyRequest().authenticated().and().formLogin().and()
.httpBasic();
}
}
There was tons of work made to split actuator and security config which confused us all, now its more straightforward but artifacts like these still exist. Spring devs will correct me if I am wrong :-).
I have leveraged #ConditionalOnProperty to load the following SecurityConfig.java class if I set spring.security.enabled property to false in my application.yml to disable spring security and it works like a charm.
#ConditionalOnProperty(name = "spring.security.enabled", havingValue = "false")
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests().antMatchers("/").permitAll();
}
}
If anyone is struggling with this in a WebFlux based application, or a Spring Cloud Gateway application, the below worked for me:
#EnableWebFluxSecurity
public class InsecurityConfiguration {
// #formatter:off
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange()
.anyExchange().permitAll();
return http.build();
}
}
To disable default security for Spring Boot Reactive Web applications, use the following excludes when you have actuator also in the classpath.
#SpringBootApplication(exclude = {ReactiveSecurityAutoConfiguration.class, ReactiveManagementWebSecurityAutoConfiguration.class })
I think what you are looking for is to override the default authentication entry point which is set to BasicAuthenticationEntryPoint.
This entrypoint adds the
"WWW-Authenticate": "Basic realm=..."
header that tells your browser to use Basic Auth.
If you're extending WebSecurityConfigurerAdapter, you can pass in true to the super constructor to disable the defaults.
You may need to provide other beans if you do this.
/**
* Creates an instance which allows specifying if the default configuration should be
* enabled. Disabling the default configuration should be considered more advanced
* usage as it requires more understanding of how the framework is implemented.
*
* #param disableDefaults true if the default configuration should be disabled, else
* false
*/
protected WebSecurityConfigurerAdapter(boolean disableDefaults) {
this.disableDefaults = disableDefaults;
}
If you want to disable it just for testing purposes -
Rather than completely disabling the auto-configuration, I create an "InsecurityConfiguration" in addition to "SecurityConfiguration", and activate it with either a Spring Profile or Property value.
Technically security is still configured, but wide open.
#Configuration
#ConditionalOnProperty(prefix = "security", value = "disabled", havingValue = "true")
public class InsecurityConfiguration extends WebSecurityConfigurerAdapter {
private final static Logger log = LoggerFactory.getLogger(InsecurityConfiguration.class);
#Override
protected void configure(HttpSecurity http) throws Exception {
log.warn("configuring insecure HttpSecurity");
http.authorizeRequests().anyRequest().permitAll();
}
#Override
public void configure(WebSecurity web) throws Exception {
log.warn("configuring insecure WebSecurity");
web.ignoring().antMatchers("/**");
}
}
Note This is for mvc, not webflux. For Webflux you should create a SecurityWebFilterChain like Bryan mentioned.
This is how I generally disable basic auth in webflux, when using JWT -
#Bean
public SecurityWebFilterChain configure(ServerHttpSecurity http) {
http
.authorizeExchange().anyExchange().authenticated().and()
.httpBasic().disable()
.formLogin().disable()
.logout().disable()
.oauth2ResourceServer()
.jwt()
.and()
.and().exceptionHandling().accessDeniedHandler(problemSupport);
return http.build();
}
Only properties - works for me (sb2 - 2022):
spring:
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
- org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration
Simple solution for Spring Boot 2.6
#SpringBootApplication(exclude = {SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class})
In Spring boot 2, there is no way to disable basic authentication by application.properties file. But the only thing is use annotation
#EnableAutoConfiguration(exclude = {SecurityAutoConfiguration.class})
in the main class.
It works
The problem is with org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter
it has private ServerAuthenticationEntryPoint authenticationEntryPoint = new HttpBasicServerAuthenticationEntryPoint();
so to fix it during ServerHttpSecurity initialization add:
http.exceptionHandling().authenticationEntryPoint(HttpStatusServerEntryPoint(HttpStatus.FORBIDDEN))
Looks like vanilla (servlet) spring uses org.springframework.security.config.annotation.web.configurers.ExceptionHandlingConfigurer#createDefaultEntryPoint
private AuthenticationEntryPoint createDefaultEntryPoint(H http) {
if (this.defaultEntryPointMappings.isEmpty()) {
return new Http403ForbiddenEntryPoint();
}
if (this.defaultEntryPointMappings.size() == 1) {
return this.defaultEntryPointMappings.values().iterator().next();
}
DelegatingAuthenticationEntryPoint entryPoint = new DelegatingAuthenticationEntryPoint(
this.defaultEntryPointMappings);
entryPoint.setDefaultEntryPoint(this.defaultEntryPointMappings.values().iterator()
.next());
return entryPoint;
}
Side note: mutable fields in builder style beans (like ExceptionTranslationWebFilter) make spring code hard to debug (too magic configuration as well)
You should add #EnableWebSecurity to enable a custom security configuration.
After that simply disable the form login
#Configuration
#EnableWebSecurity
public class StackWebSecurityConfigurerAdapter extends
WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().disable();
}
}
This worked for me
#SpringBootApplication(exclude = {UserDetailsServiceAutoConfiguration.class})
class SpringApplication{
...
}

Spring Boot setup with multiple authentication providers (API+Browser)

My application serves both API and browser. I've implemented API Token authentication with all custom providers and filter. The configuration now seems to interfere with the browser version.
I have two questions that I need advice on how to solve, as I'm not getting anywhere after digging through the documentation and other examples.
1) My StatelessAuthenticationFilter is being called despite a request
coming from the browser. I have e.g. specified the request matcher to "/api/**". Why is that?
2) The AuthenticationManager have not registered two AuthenticationProviders. This is my conclusion after debugging my StatelessAuthenticationFilter that's being called wrongly.
Here's the configuration classes that I have
#Configuration
#EnableWebSecurity
public class WebSecurityConfig {
#Order(1)
#Configuration
public static class A extends WebSecurityConfigurerAdapter {
#Autowired
TokenAuthenticationProvider tokenAuthenticationProvider;
#Autowired
ApiEntryPoint apiEntryPoint;
#Override
protected void configure(HttpSecurity http) throws Exception {
StatelessAuthenticationFilter filter = new StatelessAuthenticationFilter();
AntPathRequestMatcher requestMatcher = new AntPathRequestMatcher("/api/**");
filter.setRequiresAuthenticationRequestMatcher(requestMatcher);
filter.setAuthenticationManager(super.authenticationManager());
http.csrf().disable()
.exceptionHandling().authenticationEntryPoint(apiEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(tokenAuthenticationProvider);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/user/register");
}
}
#Configuration
public static class B extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new DaoAuthenticationProvider());
}
}
}
As you can see, B class doesn't specify anything, yet when I access localhost:8080 the StatelessAuthenticationFilter is called. What is going on here?
In class A you are configuring the StatelessAuthenticationFilter to use a requestMatcher. Whatever you do with that, spring does not know or care about that.
You must also restrict your security configuration using
http.antMatcher("/api/**")
otherwise its configured for every URI and the StatelessAuthenticationFilter will be invoked for every request, exactly as you described.
You should also annotate class A and B with #Order as shown in the example at multiple-httpsecurity

Spring Boot 1.3.3 #EnableResourceServer and #EnableOAuth2Sso at the same time

I want my server be a ResourceServer, which can accept a Bearer Access token
However, If such token doesn't exist, I want to use the OAuth2Server to authenticate my user.
I try to do like:
#Configuration
#EnableOAuth2Sso
#EnableResourceServer
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
}
However, in this case, only the #EnableResourceServer annotation works. It returns
Full authentication is required to access this resource
And do not redirect me to the login page
I mentioned that the #Order is important, if I add the #Order(0) annotation,
I will be redirect to the login page, however, I cannot access my resource with the access_token in Http header:
Authorization : Bearer 142042b2-342f-4f19-8f53-bea0bae061fc
How can I achieve my goal? I want it use Access token and SSO at the same time.
Thanks~
Using both configuration on same request would be ambiguous. There could be some solution for that, but more clear to define separate request groups:
OAuth2Sso: for users coming from a browser, we want to redirect them to the authentication provider for the token
ResourceServer: usually for api requests, coming with a token they got from somewhere (most probably from same authentication provider)
For achieving this, separate the configurations with request matcher:
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Bean("resourceServerRequestMatcher")
public RequestMatcher resources() {
return new AntPathRequestMatcher("/resources/**");
}
#Override
public void configure(final HttpSecurity http) throws Exception {
http
.requestMatcher(resources()).authorizeRequests()
.anyRequest().authenticated();
}
}
And exclude these from the sso filter chain:
#Configuration
#EnableOAuth2Sso
public class SsoSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
#Qualifier("resourceServerRequestMatcher")
private RequestMatcher resources;
#Override
protected void configure(final HttpSecurity http) throws Exception {
RequestMatcher nonResoures = new NegatedRequestMatcher(resources);
http
.requestMatcher(nonResoures).authorizeRequests()
.anyRequest().authenticated();
}
}
And put all your resources under /resources/**
Of course in this case both will use the same oauth2 configuration (accessTokenUri, jwt.key-value, etc.)
UPDATE1:
Actually you can achieve your original goal by using this request matcher for the above configuration:
new RequestHeaderRequestMatcher("Authorization")
UPDATE2:
(Explanation of #sid-morad's comment)
Spring Security creates a filter chain for each configuration. The request matcher for each filter chain is evaluated in the order of the configurations.
WebSecurityConfigurerAdapter has default order 100, and ResourceServerConfiguration is ordered 3 by default. Which means ResourceServerConfiguration's request matcher evaluated first. This order can be overridden for these configurations like:
#Configuration
#EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
#Autowired
private org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration configuration;
#PostConstruct
public void setSecurityConfigurerOrder() {
configuration.setOrder(3);
}
...
}
#Configuration
#EnableOAuth2Sso
#Order(100)
public class SsoSecurityConfiguration extends WebSecurityConfigurerAdapter {
...
}
So yes, request matcher is not needed for SsoSecurityConfiguration in the above sample. But good to know the reasons behind :)

Add OAuth2 to existing Spring Security App

I have a web application which runs with following configuration.
public class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.authorizeRequests()
.antMatchers("/api/open/**").permitAll()
.antMatchers("/api/data/**").authenticated()
.antMatchers("/api/user/**").hasRole("USER")
.antMatchers("/api/mgr/**").hasRole("MGR")
.antMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
.and() .exceptionHandling().accessDeniedHandler(customBasicAuthenticationAccessDeniedHandler())
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.csrf().disable() //TODO
.httpBasic().authenticationEntryPoint(customBasicAuthenticationEntryPoint());
}
...
}
I then added,
#Configuration
#EnableAuthorizationServer
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
...
}
and
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
//Same as WebSecurityConfigurerAdapter configure()
...
}
Because of ResourceServerConfig class now everything has crewed up. Tried various ways to configure this. But it seems ResourceServerConfigurerAdapter behave completely different than WebSecurityConfigurerAdapter, but I don't have a single clue to get this to work.
Do I need to remove WebSecurityConfigurerAdapter and keep only ResourceServerConfigurerAdapter? Did that, but configure(HttpSecurity) behave differently than I thought.
Also some stackoverflow answers recommended to change the #Order of the WebSecurityConfigurerAdapter. But nothing works.
I need to know actually what is wrong and what is correct first, than writing a code.
Appreciate very very much if someone point me a right direction.
Thanks!
By sharing this, I am only intending to be helpful, not answer your query. I know documentation is not that good. Just sharing my 2 cents.
This is what worked for me. Using Spring-security-Oauth2 version 2.0.7
#EnableWebSecurity
public class SampleMultiHttpSecurityConfig {
#Configuration
#Order(1)
public static class ComplexOauth2SpringSecurityConfiguration extends
WebSecurityConfigurerAdapter {
#Autowired
private OAuth2AuthenticationProcessingFilter oAuth2AuthenticationProcessingFilter;
#Autowired
private OAuth2AuthenticationManager oAuth2AuthenticationManager;
#Override
protected void configure(HttpSecurity http) throws Exception {
...
}
}
#Configuration
public static class ComplexOauth2SpringSecurityConfiguration2 extends
WebSecurityConfigurerAdapter {
#Autowired
private OAuth2AuthenticationProcessingFilter oAuth2AuthenticationProcessingFilter;
#Autowired
private OAuth2AuthenticationManager oAuth2AuthenticationManager;
#Override
protected void configure(HttpSecurity http) throws Exception {
...
}
}
Thereafter, I simply added a component:scan on the package which is having this class.
This is primarily on the server side.
Also, note the injection of OAuth2AuthenticationProcessingFilter. This is based on RemoteTokenServices whose one of many jobs is to perform Token Validation with Authorization server.
<bean id="remoteTokenServices" class="org.springframework.security.oauth2.provider.token.RemoteTokenServices"
init-method="init" destroy-method="shutdown">
<property name="checkTokenEndpointUrl" value"..."/>
</bean>
I do agree that I did not implement resource server and Authorization server. They were already built for us. However, while testing we simply created couple of REST POST services to simulate the Token generation and Validation.

Resources