Spring Boot with OAuth 2 - java

I'm using Spring Boot to create my microservices and I'm enabling the OAuth2 to add security to my services.
However, there are some methods that I can not understand what are the differences between then. For example, I have the following code:
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.sessionManagement().sessionCreationPolicy(STATELESS);
http.authorizeRequests()
.antMatchers(POST, "/v1/files/").access("#oauth2.clientHasRole('ROLE_CLIENT')");
}
In this example, I used the access method to check if the system that is going to access my services has the ROLE_CLIENT role.
The question is : what are the main differences between the following methods:
hasRole
hasAuthority
access

hasRole(NAME) checks that client has ROLE_NAME whether hasAuthority(NAME) checks only NAME role.

hasRole("CLIENT") is equivalent to hasAuthority("ROLE_CLIENT")

Related

Adding Spring Boot Keycloak configuration of HTTP requests

Currently in my SecurityConfig.java class file where I define my KeycloakWebSecurityConfigurerAdapter I want to define so that every GET request can be done by two different roles. But only one role can do the other types of HTTP requests (POST, PUT, PATCH etc). How can this be achieved in my code below:
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.authorizeRequests()
.antMatchers(HttpMethod.GET).hasAnyRole("user", "admin")
.anyRequest().hasRole("admin");
}
What happens is that when trying to do POST request I get access denied 403. GET requests works fine. Any ideas?
You should disable csrf on your configure method :
public void configure(HttpSecurity http) throws Exception {
super.configure(http);
http.csrf().disable().authorizeRequests().anyRequest().authenticated();
}
}
You should not use KeycloakWebSecurityConfigurerAdapter nor anything else from Keycloak libs for Spring, it is deprecated.
Instead, you can follow this tutorial which proposes two solutions based on:
spring-boot-starter-oauth2-resource-server which requires quite some Java conf
spring-addons-webmvc-jwt-resource-server which enables to configure most of security from properties (way simpler than preceding)
All tutorials linked here show how to map Keycloak roles to spring-security authorities (and will keep CSRF protection enabled, even for stateless resource-servers).

Spring Security REST API roles based on URL parameters

I have a REST API written in Spring Boot with Spring Security and OAuth2. The resources are secured this way:
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/v1/security/**").hasRole("ADMIN");
}
I'd like to introduce a new part of the API where the permissions are fine grained, based on projects. Let's consider a simple endpoint that prints the project configuration.
GET /api/v1/project/{projectId}/config
How would I configure the resource server to only allow access for users who have the role ROLE_PROJECT_{projectId}_ADMIN without having to manually specify all projects?
Also if this mechanism has a specific name, please let me know in comments to I can change the question title.
You can use path values in authorization expressions.
According to Path Variables in Web Security Expressions you should write your custom authorization logic.
public class WebSecurity {
public boolean checkUserHasAccessToProjectId(Authentication authentication, int projectId) {
// here you can check if the user has the correct role
// or implement more complex and custom authorization logic if necessary
}
}
Then in your Java security configuration you can refer to this method and pass it the value of the relevant path fragment.
http.authorizeRequests()
.antMatchers("/api/v1/project/{projectId}/config")
.access("#webSecurity.checkUserHasAccessToProjectId(authentication,#projectId)")
...

spring boot ldap group and restricted endpoints

I want to restrict certain rest endpoints to be only for LDAP users in a certain group.
I followed the guide https://spring.io/guides/gs/authenticating-ldap/ to setup LDAP authentication which is working perfectly. So how do I restrict certain rest endpoints?
I tried
#PreAuthorize("hasRole('developers')")
#RequestMapping("/foo")
public String foo(HttpServletRequest request) {
return "Welcome to FOO " + request.getRemoteUser();
}
but it still lets users not in the developers group access that endpoint
You can modify your WebSecurityConfigurerAdapter configuration to something like:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().fullyAuthenticated()
.and()
.antMatchers("/foo").hasRole("developers")
.and()
.formLogin();
}
I am not exactly sure of the syntax and if that first rule will override your second rule, but it will be similar to that.
Or, you can try configuring security on a method by method basis like this sample.
#EnableGlobalMethodSecurity(securedEnabled=true) needed to be added to the webSecurityConfig. Once I did that I was able to use #Secured("ROLE_DEVELOPERS") and that method was then restricted to that role.

Develop Spring Security as a Common Module and Swicting it in Spring Boot Micro Service Architecture

I have a micro service architecture with spring boot. I decided to add Spring security for each micro service which will authenticate, authorise the user.
So i develop a separate project with has Spring Security authentication.
I have use a Filter which extends AbstractAuthenticationProcessingFilter.
The paths which needs authentication and authorisation are mentioned in my filter class as below,
private AntPathRequestMatcher[] authenticationMatcher = {
new AntPathRequestMatcher("//api/myservice1/**"),
new AntPathRequestMatcher("/api/myservice")
};
private AntPathRequestMatcher[] authorizationMatcher = {
new AntPathRequestMatcher("/api/myservice")
};
So in the filter class doFilter method i check request path and do relevant logics.
My SecurityConfig class configure method just look like below,
#Override
protected void configure(HttpSecurity http) throws Exception {
http.addFilterBefore(getMyAuthenticationFilter(), BasicAuthenticationFilter.class);
}
So my questions are,
What approach i should do for introduce this module (project) to each micro service?
What i had in my mind is expose this as a jar file and use it in any micro service. In that case how can i over ride those authenticationMatcher and authorizationMatcher url's which will be specific to each micro services?
Am i declare those url's in correct place and if so what Object Oriented principles i should apply?
Is there a possibility i can by pass authentication filter if required and enable it when required? Like switching it?
I believe this approach can work like you want and can be done using Spring Boot. In regards to your questions:
In your filter class you can declare something like this which can be populated by bean initialization.
#Value("${security.checkValues}")
private String[] checkValues;
Below is an example I used with my own custom filter declared as a bean and passed in to the security configuration. You probably don't need all of it.
#Configuration
#Order(3)
public static class SubscriptionWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().antMatchers("/subscribe**","/subscribe/**").and()
.addFilterBefore(applicationSecurityTokenFilter(), UsernamePasswordAuthenticationFilter.class)
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic()
.and()
.csrf().disable();
}
#Bean
public ApplicationSecurityTokenFilter applicationSecurityTokenFilter() {
return new ApplicationSecurityTokenFilter();
}
}
Then each application.properties instance in your micro services (assuming they are separate projects) will have a line like below to specify the URLs to use.
security.checkValues=/api/myservice,/api/myservice2
If you include an empty string property like this:
security.checkValues=
Then the String array will be set to a 0 length array and you can know that it should not be active. I'm not entirely sure this is what your question was referencing so please review.
Let me know if this is what you are looking for. We can flush it out a little further if necessary.

Security config when using #PreAuthorize

My security config class (which inherits from WebSecurityConfigurerAdapter) has a method like the following.
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/restaurant/**").access("hasRole('ROLE_USER')")
.and()
.formLogin();
}
However I'd rather use #PreAuthorize on my controllers instead. If I remove the method everything requires auth. What should my method look like so everything is available and access is only determined by PreAuthorize?
As has been already stated, it is not very common to use method level security to secure controller methods but rather to secure methods with business logic. And even if you need to perform authorization based on request attributes, it should be possible to achieve this with URL based security and web security expressions.
Available expressions are defined by WebSecurityExpressionRoot class, an instance of which is used as the expression root object when evaluation web-access expressions. This object also directly exposed the HttpServletRequest object under the name request so you can invoke the request directly in an expression.
Here you can find more details on when to use URL based security and when method level security.
It is rather uncommon to use #PreAuthorize on controller methods, but there may me use cases, if the decision depends on request parameters ...
If you do not want to do any authorization at the request level, you can simply have :
#Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin();
}
You only declare a form login, and no request security. But do not forget that request security uses less resources than method security.
Instead of .access("hasRole('ROLE_USER')"), try .access("permitAll"). Note that for request mappings that doesn't have a #PreAuthorize, everyone will be given access.

Categories