I know that there are topics with this problem, but the config which I made is correct and I compared it to a project where it works correctly.
I want to "unsecure" a /login endpoint for JWT security, but still the AuthenticationFilter runs before reaching the /login endpoint.
I'm confused why it is no working.
My Code Below :
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().authenticated();
http
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
http.headers().cacheControl();
}
Duplicate: How to add a filter only for one special path WebSecurityConfigurerAdapter
You can't do that with a single Configuration class. Take a look at this question: How to apply spring security filter only on secured endpoints?.
In this case, I think the better solution is to configure multiple HttpSecurity. From Spring IO documentation:
We can configure multiple HttpSecurity instances just as we can have
multiple blocks. The key is to extend the
WebSecurityConfigurationAdapter multiple times. For example, the
following is an example of having a different configuration for URL’s
that start with /api/.
The documentation has a full example with the necessary steps to accomplish this:
Configure Authentication as normal
Create an instance of WebSecurityConfigurerAdapter that contains
#Order to specify which WebSecurityConfigurerAdapter should be
considered first.
The http.antMatcher states that this HttpSecurity
will only be applicable to URLs that start with /api/
Create another instance of WebSecurityConfigurerAdapter. If the URL does not start with /api/ this configuration will be used. This
configuration is considered after ApiWebSecurityConfigurationAdapter
since it has an #Order value after 1 (no #Order defaults to last).
Good luck!
Related
I´ve got a running Spring Boot Application (Spring Boot v2.4.1) and I would like to monitor it using Spring Boot Admin.
I have already setup the server and I can monitor the instance of my application with the /actuator/ endpoint not secured. I have a permitAll() on it.
Now I´d like to secure it, but I do not know how to do it without messing with my current Security Configuration.
I have Spring Security configured to match username and password from a DB and with a CustomAuthenticationProvider. If possible I would like to add a Actuator Endpoints with a HTTP Basic authentication.
This is my current security config:
http.
authorizeRequests()
.antMatchers("/admin/**").hasAuthority(AUTHORITY_ADMIN)
.antMatchers("/user/**").hasAnyAuthority(AUTHORITY_ADMIN, AUTHORITY_USER)
.anyRequest().authenticated()
.and()
.csrf().disable()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error=true")
.successHandler(new CustomUrlAuthenticationSuccessHandler(translator))
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.and()
.exceptionHandling().accessDeniedPage("/403")
.and()
.headers().frameOptions().sameOrigin();
I would like to keep that configuration and also tell spring that whenever a user hits /actuator/ endpoint, it will requiere HTTP Basic Security credentials.
I was thinking on having two #Configuration classes, extending WebSecurityConfigurerAdapter. One would be the one I´ve already got and the other one for the actuator endpoints. But I had no luck with it.
Thank you
Thank you very much
You can create two SecurityFilterChain beans, one for your /actuator/** endpoint with higher priority, and other to every other endpoint with lower priority, like so:
#Bean
#Order(1)
public SecurityFilterChain actuatorWebSecurity(HttpSecurity http) throws Exception {
http.requestMatchers((matchers) -> matchers
.antMatchers("/actuator/**"));
http.authorizeRequests((authz) -> authz
.anyRequest().authenticated());
http.httpBasic();
http.userDetailsService(myUserDetailsService);
...
return http.build();
}
#Bean
#Order(2)
public SecurityFilterChain defaultWebSecurity(HttpSecurity http) throws Exception {
// your current configuration
}
In this configuration, the #Order annotation tells the order that the SecurityFilterChains are gonna be matched against the requests.
This is how I solve it: I create a new #Configuraiton class extending WebSecurityConfigurerAdapter,
I was unable to stop using WebSecurityConfigurerAdapter (as suggested by #Marcus-Hert-da-Coregio in the comments) because if I do not extend it I was not able to define my custom AuthenticationProvider.
This class has #Order(1) so it would take precedence over my other initial configuration (which I set to #Order(2)). And this is it's content:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/actuator/**")
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
Then my custom AuthenticationProvider will verify if the given credentials for accessing the actuator endpoints are valid.
Addittional information
The reason why this fails the first time I test it was because I was not setting the initial
.antMatcher("/actuator/**")
by adding it I was telling SpringSecurity that this configuration should only be applied to those endpoints. I get that notion from this article
I hope this helps someone in the future
Does anybody know if there any way to configure Spring Security in the way that it doesn't change session id if there is some parameter in the request.
For example:
somesite.com/home.jsp?password=encrypted- change session id after
authentication
somesite.com/home.jsp?password=encrypted& keepsessionid - don't
change session id after authentication
I was thinking about filter chain, maybe removing conditionally SessionManagementFilter, but not sure if this is a proper way, and even if this will be working
For someone with the same question. I found the answer. Different session management strategy can be achieved by using multiple http security configuration (inner classes of main security classes). The special case http security configurer should be adjusted to some special request
#Configuration
#Order(1)
public class SpecialCaseSessionHandlingConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(request -> Check1(request))
.authorizeRequests()
.anyRequest().authenticated();
}
}
I'm trying to get a Spring application to allow some requests to public (without login) and some requests to private (with login).
At this point I'd like to just get the public part to work properly.
I have tried most of the example configurations listed on the Spring Security documentation, including all sorts of combinations of anonymous(), and permitAll(). All end up redirecting to the login page.
protected void configure(HttpSecurity http) throws Exception{
http.authorizeRequests()
.antMatchers("/resources/**", "/signup", "/about","/api/home").permitAll()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.anyRequest().authenticated()
.and()
// ...
.formLogin();
}
Expected result: items under permitAll() are accessible without logging in
Actual result:
redirect to login page. This shows up in the log: 2019-06-06
17:29:43.593 INFO 56330 --- [ main]
o.s.s.web.DefaultSecurityFilterChain : Creating filter chain: any
request, [org.sprin...
This leads me to believe that it isn't even reading this configuration. Is there any way to fix this?
Thanks!
UPDATE: I tried adding the websecurity ignores, and it doesn't appear to be working still. It appears to still print the "defaultsecuritychain" error so I feel like this may have something to do with it.
UPDATE 2: Added application.properties file under src/main/resources with this line logging.level.org.springframework.security=DEBUG to make it log debug messages.
pastebin.com/2u9k7eHD
Have a look at http://blog.florian-hopf.de/2017/08/spring-security.html, it may explain your use-case in more detail.
My recommendation is to try and use WebSecurity for static and public resources
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**", "/signup", "/about","/api/home");
}
You can achieve your requirements with below configurations. It's a good way to use the URLs which does't require Authentication/Authorization to be placed in WebSecurity using ignoring instead of HttpSecurity as WebScurity will bypass the Spring Security Filter Chain and reduce the execution time
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**", "/signup", "/about","/api/home");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/db/**").access("hasRole('ADMIN') and hasRole('DBA')")
.anyRequest().authenticated()
.yourConfigurations
}
When you use HttpSecurity and try to permitAll() requests. Your requests will be allowed to be accessed from the Spring Security Filter Chain. This is costly as there will be requests other requests which would also come into this filter chain which needs to be allowed or disallowed based on Authentication/Authorization
But when you use WebSecurity, any requests to "/resources/**", "/signup", "/about","/api/home" will completely by pass the Spring Security Filter Chain all together. It is safe because you don't need any Authentication/Authorization to be in place to see an image or read a javascript file.
Turns out that I was missing the #SpringBootApplication annotation all along in one of my source files. Make sure that's in there and perhaps it will work.
Thank you to all who replied!
I'm building a web application which will contain an API and an admin interface in a single application. As a result, I need two types of authentication, token based auth for the API, and form based auth for the admin interface.
I've almost got it working by applying a filter to authenticate API tokens, however the filter is being executed for every request, and I only want it to be executes on paths matching '/api/**'.
Hopefully it's clear from my security configuration what I'm trying to do, but sadly it doesn't work as expected.
All API requests will start '/api/', while all admin interface requests will start '/admin/'. So I was hoping to apply different security rules to each.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/api/account/login").permitAll();
http.addFilterBefore(webServiceAuthenticationFilter, UsernamePasswordAuthenticationFilter.class).authorizeRequests().antMatchers("/api/**").hasAuthority("APIUSER");
http.authorizeRequests().antMatchers("/admin/**").authenticated().and()
.formLogin()
.loginPage("/admin/account/login").permitAll()
.passwordParameter("password")
.usernameParameter("username")
.failureUrl("/admin/account/login?error").permitAll()
.defaultSuccessUrl("/admin/dashboard")
.and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/admin/account/logout"))
.logoutSuccessUrl("/admin/account/login");
http.exceptionHandling().accessDeniedPage("/admin/account/forbidden");
}
There is a way to configure several HttpSecuritys depending on the url by using the antMatcher (or in more advanced cases requestMatchers) on the HttpSecurity directly (not on authorizeRequests!). See: https://docs.spring.io/spring-security/site/docs/current/apidocs/org/springframework/security/config/annotation/web/builders/HttpSecurity.html#antMatcher-java.lang.String-
This requires defining several WebSecurityConfigurerAdapters with defined #Orders such that Spring uses the first appropriate configuration depending on the given url and the order of the configurations. For more details please take a look at the docs at http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#multiple-httpsecurity
I don't know if this is the 'correct' way of doing it, but I've managed to only get the filters code to execute when a route is matched with '/api/**' by adding an if statement to the filter itself;
So within my filter I have the following;
AntPathMatcher urlMatch = new AntPathMatcher();
if (urlMatch.match("/api/**", httpRequest.getRequestURI().substring(httpRequest.getContextPath().length()))) {
// Token authentication in here
}
I an Trying to secure spring actuator services /manage context path when calling for example:
http://localhost:9091/manage/metrics
with this config in my yalm.properties
management:
port: 9091
address: 127.0.0.1
context-path: /manage
security:
enabled: true
role: ADMIN.
Git branch with security actuator service layer
but access to every service is still free.
Spring security config:
'#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/pizzas","/info","/addPizza").hasAnyRole("USER","ADMIN").and().authorizeRequests().antMatchers("/users","/addUser").hasRole("ADMIN").and().authorizeRequests().antMatchers("/static/**","/logout","/login").permitAll();
http.formLogin().loginPage("/login").failureUrl("/login?error").permitAll();
http.logout().logoutSuccessUrl("/?logout").deleteCookies("remember-me").permitAll();
http.sessionManagement().maximumSessions(1).
expiredUrl("/?expired").maxSessionsPreventsLogin(true).and()
.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
}
/**
* Configure global security with Bccyptenoncder and custom userDetailService with Spring Security
* #param auth
* #throws Exception
*/
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsServiceImpl).passwordEncoder(passwordEncoder());
}
/**
* Bcrypt password encoding configuration, more info at http://www.baeldung.com/spring-security-registration-password-encoding-bcrypt
* #return
*/
#Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
'
Spring boot team has resolved me this issue. I share the solution here:
Same Origin Policy
You cannot use the login page from your main Spring Application within actuator security. The reason is that the cookie is going to be associated with the domain + port + context path of the application. This is part of the Same Origin Policy
This means if you sent the user to localhost:9090/pizza/login and authenticated, when you visited localhost:9091/manage/ the JSESSIONID cookie would not be submitted to the management application which means you would not be seen as authenticated.
In order to authenticate across domains (i.e. different ports in this case) you would need some single sign on (OpenID, CAS, SAML, etc) mechanism.
Mapping a Login Page in the Management Application
In order to use this configuration you would need to setup a login page within the management application. To do this you would just need to return an HTML form when /login is requested. However, I'm not really certain how you would do that within the Boot management application. Perhaps #philwebb or #dsyer can elaborate on how one would do that.
Distinct Security Configuration for the Management Application
Alternatively you could create separate security configuration for the management application that allows authenticating with Basic Authentication. To do this you would create another Security Configuration that looks something like this:
#Order(0)
#Configuration
public class ManagementSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.requestMatchers(request -> "/manage".equals(request.getContextPath()))
.and()
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}
}
This would make sure that if the context root is "/manage" that this security configuration is used. A few points of interest:
#Order(0) makes sure the configuration occurs before your other security configuration since by default any subclass of WebSecurityConfigurerAdapter will be ordered at 100. This is important because only the first WebSecurityConfigurerAdapter is used (similar to the authorizeRequests() matchers).
The request matcher is using a lambda for matching on the contextPath. I had thought there was a better way to distinguish Spring Boot application from the main application, but it does not appear that is the case. Perhaps #dsyer knows how this should be done.
NOTE
You can rewrite your configuration much more concisely as:
http
.authorizeRequests()
.antMatchers("/pizzas","/info","/addPizza").hasAnyRole("USER","ADMIN")
.antMatchers("/users","/addUser").hasRole("ADMIN")
.antMatchers("/static/**","/logout","/login").permitAll()
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error")
.permitAll()
.and()
.logout()
.logoutSuccessUrl("/?logout")
.deleteCookies("remember-me")
.permitAll();
You might consider reading Spring Security Java Config Preview: Readability for details on how to format the configuration to better read it too.