I am currently using WebSecurityConfigurerAdapter in my Spring Boot application. There i have configured the pipeline of security checks. There is also this:
http
.authorizeRequests()
.anyRequest()
.authenticated()
So every request is allowed as long as the requester is authenticated. Now I have added #PreAuthorize("hasAuthority('SOME_ROLE')") to my methods. But if I miss one method, the default is allowed. How do I configure the WebSecurityConfigurerAdapter to permit all requests, to methods who not contain any PreAuthorize annotation?
I tried the AccessDecisionManager, but it does not work (or i am doing something wrong).
How do I configure it? It should be an easy thing, since permit should be default to secure the application.
I have a current solution. Since all controllers implement one base controller, i just added #PreAuthorize("denyAll()") to the base controller.
Then if the implementation does not override #PreAuthorize with a custom value, every request will be denied. This is also written as best practice in the quarkus docs: https://quarkus.io/guides/spring-security
Adding #PreAuthorize("denyAll()") to a method will ensure that that method is not accessible by any user. Adding it to a class will ensure that all public methods of the class that are not annotated with any other Spring Security annotation will not be accessible to any user.
Related
I am creating a Restful API with Spring Boot 2.5 and would like to know the right way to implement validation while checking roles for some routes. Also, for some routes I need to make sure that only admins can modify the resource or its owner.
#PreAuthorize seems to be the solution, but #Valid seems to be processed before an actual method call, otherwise known as executed before #PreAuthorize.
See : How to check security acess (#Secured or #PreAuthorize) before validation (#Valid) in my Controller?
Is this really the only available and clean solution to make a Restful API with both validation and roles with Spring Boot & Spring Security?
I'm afraid that that is the cleanest solution.
To check roles for some routes, you can configure your HttpSecurity to check roles before even getting to the controller, like so:
#Bean
SecurityFilterChain app(HttpSecurity http) throws Exception {
http.authorizeHttpRequests((requests) -> requests
.antMatchers("/route1").hasAnyRole("ADMIN", "USER")
)
return http.build();
}
So, with this configuration, you are making sure that only ROLE_USER or ROLE_ADMIN are allowed to request /route1.
But now, the ROLE_USER is allowed only if they are the resource owners. For this, you must have to resolve the method parameters to know which resource you are requesting. And then, in the #PreAuthorize, you can do something like this:
#PreAuthorize("#myBean.isResourceOwner(resourceId, authentication)")
#PutMapping("/{resourceId}")
public void update(#PathVariable Long resourceId) {
...
}
I would like to ask if there is a point to secure the methods which I call in a REST Controller with Pre and Post annotations. I have configured a security through java configuration like this:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.and()
.formLogin()
(...)
.and()
.authorizeRequests()
.antMatchers("/api/**").hasAuthority("ROLE_USER");
}
So every request under /api should be authorized with ROLE_USER. I tried to find some information about this in the internet but the only thing i could find was this:
https://coderanch.com/t/549265/Spring/method-security-spring-security
However I really can't think of a use case where a hacker would access somehow the methods in the service layer.
URL security and method security in service layer aims at different use cases.
If all you need is control that only users with a certain role can call URL with a given prefix (here API) URL security is what you need full stop.
If you have a complex application where some service methods can be called from different controllers and you want to make sure that you did not fail to restrict an access, method security can come to help by ensuring that only valid users can do certain business actions.
If you have a complex security model, for example several officse with one manager in each that has read and/or write access to his own employees data, method security on service layer directly using business model objects is the way to go.
BTW, using method security in a controller or even worse on a rest controller is generally design smell: if you can do it inside a controller it is generally better to use URL security. If it seems to make sense, you probably have imported business logic into a Fat Ugly Controller. Not speaking about method security being implemented with Spring AOP using by default JDK proxies, when controllers generally do not implement interfaces.
In addition to making it possible to have some kinds of functionality, using both techniques gives an additional layer of security.
Method level security is used to authorize the user. Spring security performs two basic operations before allowing the access.
Authenticate (Who is the user)
Authorize (What authorities the user has)
so for example if the user is having an authority of ROLE_USER and later in the architecture you decide to have rights assigned to some of the roles.
for example let's consider a role 'ROLE_USER'
and following rights has been assigned to the USER
CAN_VIEW_DATA
CAN_ADD_SUB_USERS
and so on.
so when some of the users have the right of CAN_ADD_SUB_USERS and some dont, then the method level security comes in handy.
Of course you have to play with the spring configurations for the rights and authority. But Once configured it provides an extra level of security that the applicaton might need.
Refer to this link for more info http://www.baeldung.com/role-and-privilege-for-spring-security-registration
REST is stateless. You should send something like access token (like Google API) with every request:
https://{server}/api/customers?access_token=BGhznFGDS
You can also send this information via Header-Attribute. The validation layer (Filter) decides whether the controller method may be called or not.
I prefer to implement my own Filters to get 100% of control.
I have a lot of API endpoints that need authenticated requests, and a few that are allowed for any request. I would like Spring Security to block anonymous requests by default, but to let me overwrite it:
aHttpSecurity.authorizeRequests().anyRequest().authenticated()
...
#PreAuthorize("permitAll()")
#RequestMapping("/foobar")
public ResponseEntity<FooBar> get() {
...
}
Unfortunately, this does not work: /foobar outputs 401. Any idea how to do?
#PreAuthorize is just an annotation which wraps method to check if user can execute annotated method. It works not just with controllers.
When you have http requests, firstly requests go through some spring security filters and when you write .anyRequest().authenticated() you just do not go to some wrapped controller endpoint.
So, If you have a few endpoints you can exlude it
aHttpSecurity.authorizeRequests()
.antMatchers(HttpMethod.GET, "/foobar/**").permitAll()
.antMatchers("/**").authenticated()
and delete #PreAuthorize("permitAll()")
Spring Security has two levels of Security.
Filter Level and Method Level.
Filter Level would work with URL and If a URL is not configured to be accessed it will be denied access with 401 or 403 accordingly. This is handled by FilterSecurityInterceptor
Method Level is often used as a second level of defense to Authorize who can access a method and what operations or objects he/she can manipulate. This is handled by MethodSecurityInterceptor
I am using Spring-security in a Spring-boot appplication. By default, all methods are restricted to authenticated users thanks to this configuration :
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
Now, I would like to mark some urls as public. I could do it with ant matchers but I would prefer to be able to directly mark the relevant methods with an annotation.
I saw that some #PreAuthorize annotation exist but I could have it work only if I remove those lines from the configuration :
.authorizeRequests()
.anyRequest().authenticated()
This forces me to annotate manually every method that I want to secure with this annotation :
#PreAuthorize("isAuthenticated()")
This is highly dangerous because every forgotten url will be publicly accessible by default. Is there a way to make every url accessible to authenticated users by default and open some urls with
#PreAuthorize("permitAll()")
Also, I saw in another post that the OP was answered :
But it is really a bad idea to use pre-post annotation on a controller, for what could be done directly in HttpSecurity configuration. It forced you to use proxyTargetClass = true.
What is wrong with that? (Also, I did not need to use proxyTargetClass = true)
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.