can't get Spring Security to work - spring

I'm new to Spring Security so I probably miss out on something. I have a Spring Application that starts a Jetty with a WebApplication I want to secure using Spring Security. The webapp is running and reachable, but not restricted. I've tried a lot of stuff but nothing worked so I broke it down to a minimal setup, but still no chance.
the webapp is configured by the following java configuration:
#EnableWebMvc
#Configuration
#Import(SecurityConfiguration.class)
#ComponentScan(useDefaultFilters = false, basePackages = { "myapp.web" }, includeFilters = { #ComponentScan.Filter(Controller.class) })
public class SpringMvcConfiguration extends WebMvcConfigurerAdapter {
/**
* Allow the default servlet to serve static files from the webapp root.
*/
#Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
}
and Spring Security configured here:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user")
.password("password")
.roles("ADMIN")
.authorities("ADMIN");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.hasAuthority("ADMIN");
}
}
and some controller like this:
#Controller
public class SecuredController {
#RequestMapping(value = "/secure", method = RequestMethod.GET)
#ResponseBody
public String secured() {
return "you should not see this unless you provide authentication";
}
}
Everything starts up all right, the log tells me, that the controller is mapped...
[2014-10-01 20:21:29,538, INFO ] [main] mvc.method.annotation.RequestMappingHandlerMapping:197 - Mapped "{[/secure],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String myapp.web.SecuredController.secured()
...and that security is in place as well...
[2014-10-01 20:21:30,298, INFO ] [main] gframework.security.web.DefaultSecurityFilterChain:28 - Creating filter chain: org.springframework.security.web.util.matcher.AnyRequestMatcher#1, [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter#352c308, org.springframework.security.web.context.SecurityContextPersistenceFilter#2af616d3, org.springframework.security.web.header.HeaderWriterFilter#1a2e2935, org.springframework.security.web.csrf.CsrfFilter#64f857e7, org.springframework.security.web.authentication.logout.LogoutFilter#bc57b40, org.springframework.security.web.savedrequest.RequestCacheAwareFilter#3deb2326, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter#7889a1ac, org.springframework.security.web.authentication.AnonymousAuthenticationFilter#7d373bcf, org.springframework.security.web.session.SessionManagementFilter#5922ae77, org.springframework.security.web.access.ExceptionTranslationFilter#7e1a1da6, org.springframework.security.web.access.intercept.FilterSecurityInterceptor#1051817b]
... but the /secure url of my controller is unconditionally reachable. What am I doing wrong?
ps. I want to avoid xml config

In order to integrate Spring Security with Spring MVC you have to use #EnableWebMvcSecurity annotation instead of #EnableWebSecurity in SecurityConfiguration class.

I figured, I had to move the initialization of the Spring Security configuration to the root context, not the dispatcher-servlet context, and add the following line where i configure the context of my embedded Jetty:
context.addFilter(new FilterHolder(new DelegatingFilterProxy("springSecurityFilterChain")), "/*", EnumSet.allOf(DispatcherType.class));

Related

Evaluate Web Services Interceptor Before Spring Security Filter Chain

I have a SOAP-based web services application which is leveraging Spring Web Services (and Spring WS Security) as well as Spring Security. I am using a custom AbstractWsSecurityInterceptor to authenticate the incoming requests (using an injected AuthenticationManager) and to add the successful authentications to the SecurityContext. I then have a custom AcessDecisionManager which is using a custom WebSecurityExpressionHandler to validate a certain property from the principal added to the context by the interceptor.
Below is an idea of what my configuration files look like:
SecurityConfig.java:
#Getter
#Setter
#Configuration
#RequiredArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final AccessDecisionManager customAccessDecisionManager;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
cors()
.and().csrf().disable()
.authorizeRequests()
.accessDecisionManager(customAccessDecisionManager)
.antMatchers(GET, "/actuator/**").permitAll()
.anyRequest().access("customAccessMethod()")
.and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
WebServiceConfig.java:
#EnableWs
#Configuration
#RequiredArgsConstructor
public class WebServiceConfig extends WsConfigurerAdapter {
private final AuthenticationManager authenticationManager;
#Bean
public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean<>(servlet, "/ws/*");
}
...
...
#Bean
AbstractWsSecurityInterceptor customAuthenticationInterceptor() {
return new CustomAuthenticationInterceptor(authenticationManager);
}
#Override
public void addInterceptors(List<EndpointInterceptor> interceptors) {
interceptors.add(customAuthenticationInterceptor());
}
}
The issue with this setup is that the Spring Security filter chain is evaluated first and fails the authentication because the AccessDecisionManager is evaluated before the request has a chance to enter the custom AbstractWsSecurityInterceptor and place the authentication in the SecurityContext.
Is there any way to evaluate the interceptor and handling of the request on the Web Services and WS Security side of things before it then hits the Spring Security filter chain? Is this a possibility?
Thank you in advance for the help!

Disable Spring Cloud security

I tried to disable Spring security in Spring Could using this configuration:
#SpringBootApplication(scanBasePackages = { ...... },
exclude = SecurityAutoConfiguration.class)
public class Application {
public static void main(final String[] args)
{
SpringApplication.run(Application.class, args);
}
}
When I make a request I get: An expected CSRF token cannot be found
and into prompt I get:
01:14:35.799 [boundedElastic-1] DEBUG DefaultWebSessionManager[lambda$createWebSession$3:94] - Created new WebSession. 01:14:35.862 [boundedElastic-1] DEBUG HttpWebHandlerAdapter[traceDebug:91] - [375ab2a1] Completed 403 FORBIDDEN
Do you know into the latest Spring Cloud how to disable Spring Security?
You can disable it using properties file:
security.enable.csrf=false
Or Alternatively:
You can disable csrf by extending WebSecurityConfigurerAdapter class and overriding configure method. Refer to this spring document.
#EnableWebSecurity
#Configuration
public class WebSecurityConfig extends
WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable();
}
}

spring security permit static assets not working

I understand #EnableWebSecurity disables all spring security defaults, therefore I have overridden the required methods in WebSecurityConfigurerAdapter. However, no matter what I do css and all other static assets get a 403 or 405.
Using spring boot 2.0.0.M7 with spring security created from https://start.spring.io/
Folder structure is the normal
- resources
- static
- css
styles.css
web.ignoring() doesn't do anything for some reason, yet when I enable debugging it does mention that the below paths have been bypassed but I still get a 405.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/css/**", "/webjars/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.
authorizeRequests()
.antMatchers("/register").permitAll()
.anyRequest().authenticated();
}
}
For further debugging I have even tried to permit everything by doing the below, but every url is still denied which is extremely confusing and makes me think there is some key concept I am not grasping.
http.authorizeRequests().antMatchers("/**").permitAll()
Finally, I have also tried to implement WebMvcConfigurer with various combinations of locations which don't work either.
#Configuration
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/css/**").addResourceLocations("/css/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("/webjars/");
}
Can anyone help me?
All the above security configuration is actually correct. You don't have to implement WebMvcConfigurer, only extend WebSecurityConfigurerAdapter.
Turns out to be a very hard bug to track down. I had a controller that served up a registration form like this.
#Controller
public class RegistrationController {
#GetMapping("/register")
public String getRegisterView(Model model) {
model.addAttribute("registerDto", new RegisterDto());
return "register";
}
#PostMapping
public String register(#Valid #ModelAttribute("registerDto") RegisterDto registerDto, BindingResult result) {
// business logic...
return "register";
}
}
The bug is the in the #PostMapping where I forgot to include the path!! which causes spring all sorts of issues when mapping paths. It would be nice if these annotations threw exceptions if no path was provided.
To fix this I updated it to #PostMapping("/register") and now all paths inside
web.ignoring().antMatchers("/css/**", "/js/**", "/webjars/**"); are allowed through.
So ensure all your contoller route annotations have paths in them!

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{
...
}

#preauthrize or #Secured is not working in Spring Oauth

#Preauthrize and #Secured annotations are not working in Spring Oauth (All examples I've referred to are for Spring basic security and not for Oauth protocol):
What I've done is:
I enabled global security in spring_security.xml
I used Preauthrize tag in service but it is not working.
Just add
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
To one of your configurations. I have added to my Resource Server Config
#Configuration
#EnableResourceServer
#Order(2)
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("Sample");
}
#Override
public void configure(HttpSecurity http) throws Exception {
//restrict access using #Secured or #PreAuthorize annotation
http.authorizeRequests().anyRequest().permitAll();
}
}
Worked flawlessly

Resources