I have a very specific requirement in my project related to identity & authorization. I want to open 3 paths /public/, /protected/ & /private/ from my REST service module, which will behave as follows:
URLs starting with /public/ can be accessed without any authentication or authorization.
URLs starting with /private/ can be accessed only if the user is authenticated.
URLs starting with /protected/ can be accessed only if the user is authenticated as well as authorized.
To achieve this I have built a Configurator by extending "spring resource server configurator & overriding the configure method". But unfortunately it's not working. I have also tried to use "spring web service configurator & using the ignore ant url support " but the same is also not working. The configuration which is working only for /private/ & /protected/ URLs is as follows.
http.anonymous()
.disable()
.requestMatchers()
.antMatchers("/protected/**", "/private/**")
.and();
for (String protectedApiEp : configuredApis) {
http.authorizeRequests()
.antMatchers("/protected/" + protectedApiEp + "/**")
.hasAuthority(protectedApiEp);
}
http.authorizeRequests()
.antMatchers("/protected/**").denyAll()
.antMatchers("/private/**").permitAll()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
Can anyone guide me how I can enable /public/ URLs as open to all users, with the above configuration?
The following configuration should work:
#EnableWebSecurity
public class WebApplicationSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
// Allow Spring Security to authorize requests.
http
.authorizeRequests()
// Allow anyone to access URLs starting with /public/.
.antMatchers("/public/**").permitAll()
// Allow anyone with the protected role to access URLs starting with /protected/.
.antMatchers("/protected/**").hasAuthority("protected")
// Allow anyone who is authenticated successfully to access all other URLs.
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
Here is a sample application that shows this configuration in action. Start the application as mvn clean spring-boot:run and then navigate to http://localhost:8080 to access the application.
Related
I have configured my SecurityFilterChain thus:
#EnableWebSecurity
public class WebSecurityConfig {
....
#Bean
public SecurityFilterChain configure(final HttpSecurity http) throws Exception {
http
.csrf().disable()
.cors().disable()
.authorizeRequests()
.antMatchers(HttpMethod.DELETE, "/api/user/*").access("hasRole('ADMIN')")
.antMatchers(HttpMethod.POST, "/api/user").access("hasRole('ADMIN')")
.antMatchers("/auth/login").anonymous()
.anyRequest().authenticated()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
Yet, the URL paths are open to any authenticated user irregardless of the assigned role.
I have debugged the request filter to confirm that the Principal has the right role yet a USER role can call the protected URLs successfully.
I am using Spring Boot 2.7.5.
If the path you're calling matches the authorization rule that you've declared as the last one (i.e. anyRequest().authenticated()), that implies that your test-requests don't match any of your rules that are meant to guard URLs that should be accessible only for Admins, namely:
.antMatchers(HttpMethod.DELETE, "/api/user/*").access("hasRole('ADMIN')")
.antMatchers(HttpMethod.POST, "/api/user").access("hasRole('ADMIN')")
Reminder: the matching rule declared first always weens
So, either HTTP-method or URL don't match (or both). For instance, if you're sending GET request, these restrictions would not be applied.
Regarding the URL, it should match exactly because you're using antMatchers(). I.e. path "/api/user" would not match other existing aliases of that path like "/api/user/" (more on that see here).
That's one of the reasons why in Spring Security 6.0 antMatchers() (as well as mvcMathcers() and regexMatchers()) have been removed from the API and replaced requestMatchers().
So make sure that HTTP-method is correct and path you're calling matchers exactly, and consider updating the Spring dependencies and switching to using new request-securing methods.
If you have no planes to update soon, then you can make use of the mvcMatchers(), which use Spring MVC matching rules (i.e. they take into consideration all the existing aliases of the given path), instead of antMatchers().
Here's an example of how your configuration might be implemented with Spring Security 6.0 and Lambda DSL (if you feel more comfortable with chaining configuration options using and() this flavor of DSL is still supported as well):
#Configuration
public class SecurityConfig {
#Bean
public SecurityFilterChain configure(final HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf.disable())
.cors(cors -> cors.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers(HttpMethod.DELETE, "/api/user/*").hasRole("ADMIN") // in Spring Security 6.0 method access() has been changed, and you don't need it anyway to verify the Role
.requestMatchers(HttpMethod.POST, "/api/user").hasRole("ADMIN")
.requestMatchers("/auth/login").anonymous()
.anyRequest().authenticated()
)
.sessionManagement(sm -> sm.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class)
.build();
}
}
I have an application where users/applications can authenticate either with an OpenID provider or with a JWT token.
Here is my spring security configuration class.
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.oauth2Login()
.userInfoEndpoint()
.oidcUserService(oidcUserService()).and()
.and()
.oauth2ResourceServer()
.jwt();
}
private OAuth2UserService<OidcUserRequest, OidcUser> oidcUserService() {
return oidcUserRequest -> {
OidcUserService oidcUserService = new OidcUserService();
OidcUser oidcUser = oidcUserService.loadUser(oidcUserRequest);
return oidcUser;
};
}
}
It's working as expected but I would like to disable session creation for the JWT authorization part. Do I need to split this into multiple configurations? I understand that if we have multiple configuration classes we need to differentiate based on URL pattern which I can't do in my case as a user authenticated via OpenId or via JWT still should be able to access the same URLs.
Here is the complete sample code in Github.
I solved by splitting the configuration into two classes. One for OAuth login and the other for the resource server. Configured
http.requestMatcher(new RequestHeaderRequestMatcher("Authorization"))
on the resource server Configuration class and made it's Order as 1 and Open Id configuration order as 2. In Resource server configuration I have disabled session creation.
In this way, if any external clients are calling with a JWT token with header 'Authorization' then it will be handled by Resource server configuration or else it will be handled by the second/OAuth configuration.
I'am trying to setup Spring OAuth2 and using a custom WebSecurityConfigurerAdapter (#EnableWebSecurity).
As a base I copied the following two projects:
vanilla-sample
a client application with #EnableOAuth2Sso and the corresponding properties
This works as expected out-of-the-box.
But, when I try to add a WebSecurityConfigurerAdapter with #EnableWebSecurity to the Auto-Server (vanilla), it fails.
I'm getting a
Authentication Failed: Could not obtain access token when redirect back after login and authorization at the login page of the client.
I have setup a security.oauth2.resource.userInfoUri which worked just fine without the WebSecurityConfigurerAdapter.
Any ideas how to configure oauth2 with a WebSecurityConfigurerAdapter?
Change your http security configuration to something like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers()
.antMatchers("/", "/login", "/oauth/authorize", "/oauth/confirm_access")
.and()
.authorizeRequests()
.anyRequest().authenticated();
}
I am trying to configure spring boot-Embedded Tomcat basic HTTP authentication with multiple roles, with most of the url's similar but few of them specific to each role. Here for first role the basic HTTP authentication pops up and working fine. With below code,
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class TestSecurityAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests().antMatchers(null, getAppAdminRolePaths()).authenticated()
.anyRequest().hasAnyRole("APPADMIN")
.and()
.httpBasic();
http.csrf().disable()
.authorizeRequests().antMatchers(null, getAppUserRolePaths()).authenticated()
.anyRequest().hasAnyRole("APPUSER")
.and()
.httpBasic();
http.authorizeRequests().antMatchers(null, new String[]{"/app/appOwnerView.html"}).authenticated()
.anyRequest().hasAnyRole("APPOWNER")
.and()
.httpBasic();
}
#Override
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("appadminname").password("appadminpwd").roles("APPADMIN").and()
.withUser("appusername").password("appuserpwd").roles("APPUSER").and()
.withUser("appownername").password("appoownerpwd").roles("APPOWNER");
}
private static String[] getAppAdminRolePaths(){
return new String[]{"/appweb/*",
"/app/checkService.html",
"/app/index.html",
"/app/testData.html",
"/app/adminView.html",
"/app/demo.html"};
}
private static String[] getAppUserRolePaths(){
return new String[]{"/appweb/*",
"/app/checkService.html",
"/app/index.html",
"/app/testData.html",
"/app/userView.html",
"/app/demo.html"};
}
}
For HTTP username/password popup in browser with url http://localhost:8080/app/index.html say with appadminname/appadminpwd it works fine. But for same url if I enter appusername/appuserpwd it throws HTTP 403 Forbidden access error. Here why is the second role APPUSER configured is throwing this error is I am not sure. Please let know if some way to get this resolved.
Thanks
I appreciate this question is a little old now, but this may still be useful to someone.
Firstly, I'm not sure why your calls to antMatchers() supply null as the first argument; antMatchers() expects a list of strings defining the URLs to be covered by this rule, so I'm not sure what null is expected to match in this case.
Secondly, anyRequest() means that this rule will be applied to any request made to the application regardless of the URL used, and Spring will apply security rules in the order that they are defined. You would typically define URLs and their associated roles first, and then default to a rule for any other request that must be authenticated (but does not necessarily need any specific roles) with something like anyRequest().authenticated()
Your first rule says that any request made to the application must be made by users with the role APPADMIN, which denies you access when you try to log in as appusername, so the second rule to allow APPUSERs is not even processed.
Thirdly, you are making multiple calls to http.authorizeRequests() when you should probably actually be chaining them together, for example:
http.csrf().disable().authorizeRequests()
.antMatchers( getAppAdminRolePaths() ).hasRole("APPADMIN")
.antMatchers( getAppUserRolePaths() ).hasRole("APPUSER")
.anyRequest().authenticated();
Lastly, when you have just a single role to check against, you can use hasRole() instead of hasAnyRole().
You also don't need to supply authenticated() and hasRole() in the same rule because hasRole() implies that the user is already authenticated.
You can find more explanations and examples in the Spring documentation: http://docs.spring.io/spring-security/site/docs/4.0.3.RELEASE/reference/htmlsingle/#authorize-requests
Using Spring Security
Basic authentication setup works against some hardcoded username passwords as shown here:
http://thoughtfulsoftware.wordpress.com/2013/12/08/adding-security-to-spring-guides-rest-service/
So trying to extend it to use LDAP.
Completed the set up for LDAP authentication with our LDAP server
Now when I try to call my rest service through REST Console plug-in an authorization window keeps on popping up for username password. If I cancel it authorization fails, not sure where I am going wrong
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.csrf().disable()
.httpBasic();
#Override
protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception {
authManagerBuilder
.ldapAuthentication()
.userSearchFilter("(uid={0})").userSearchBase("ou=people,dc=zzz,dc=xxxx,dc=yyy")
.groupRoleAttribute("cn").groupSearchFilter("(member={0})")
//.userDnPatterns("uid={0},ou=people")
//.groupSearchBase("ou=groups")
.contextSource().url("ldaps://ldap.xxxx.yyy:636/cn=cw-grpreader,ou=people,dc=xxx,dc=xxxx,dc=xxx")
.managerDn("cn=xx-xxr,ou=people,dc=med,dc=xxxx,dc=xxx")
.managerPassword("#$%^^");
}
This is one way I tried which give the recurring authentication popup
if I cancel the popup I get
HTTP Status 401 - [LDAP: error code 49 - NDS error: failed authentication (-669)]; error even if the credentials are correct
Link to some tutorial will be really helpful
This is due to httpbasic authentication that you have set up. Spring boot generates a random password thats shown on console which you could use.
To disable that pop-up simply add this to your application.properties file.
security.basic.enabled: false