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
Related
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.
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 am trying to understand if there is a way to use spring security which helps my used case. Basically, I want to call spring security on each REST call in spring boot, rather than one time during the start of the application, and find the role of the user and further restrict endpoints based on the user roles.
I have 3 different rest controllers namely /admin1/*, /admin2/*, /admin3/*.
I have tried restricting endpoints manually as below.
http.authorizeRequests()
.antMatchers("/admin1/**").permitAll()
.and()
.authorizeRequests()
.antMatchers("/admin2/**").permitAll()
.anyRequest().authenticated();
This will actually allow /admin1/* and /admin2/* APIs to work and restrict /admin3/*. However, my used case is as below.
In each rest call, we pass the user id in the header. I would like to use spring security on each rest call, and use the user id from the header to find the user roles from the database.
If user has ADMIN 1 user role, we have to just enable /admin1/* endpoints and restrict /admin2/* and /admin3/*. Similarly, if user has ADMIN 2 user role, we have to just enable /admin2/* endpoints and restrict /admin1/* and /admin3/*. In the same way, if user has ADMIN 3 user role, we have to just enable /admin3/* endpoints and restrict /admin1/* and /admin2/*.
Is there a way to achieve this using spring security?
Thank you
AS far as I understood, you want to authenticate & authorize users on each call. True?
one way is tokenizing your REST APIs with JWT (JSON Web Token).
The example in https://dzone.com/articles/spring-boot-security-json-web-tokenjwt-hello-world would probably help.
I Also suggest that instead of using antMatchers In configure method to restrict URL access based on Roles, you use #PreAuthorize and #PostAuthorize annotations above the classes or methods you want to secure. This way gives you more flexibility on your restriction policies.
The example in https://www.baeldung.com/spring-security-method-security also may help you with that.
I just want to make sure if I get this correctly, so I would be thankful for any response; in my configure-override:
#Override
protected void configure(HttpSecurity http) throws Exception
{
http.
[...]
permitAll()
[...]
}
the permitAll() allows any request, while:
anonymous()
will only grant access for users that are not logged in but
in both cases a HttpSession-Object is created by default.
Is that right?
From the Spring documentation:
It's generally considered good security practice to adopt a “deny-by-default” where you explicitly specify what is allowed and disallow everything else. Defining what is accessible to unauthenticated users is a similar situation, particularly for web applications. Many sites require that users must be authenticated for anything other than a few URLs (for example the home and login pages). In this case it is easiest to define access configuration attributes for these specific URLs rather than have for every secured resource. Put differently, sometimes it is nice to say ROLE_SOMETHING is required by default and only allow certain exceptions to this rule, such as for login, logout and home pages of an application. You could also omit these pages from the filter chain entirely, thus bypassing the access control checks, but this may be undesirable for other reasons, particularly if the pages behave differently for authenticated users.
This is what we mean by anonymous authentication.
and
Note that there is no real conceptual difference between a user who is "anonymously authenticated" and an unauthenticated user. Spring Security’s anonymous authentication just gives you a more convenient way to configure your access-control attributes.
Using the .permitAll() will configure the authorization so that all requests(both from anonymous and logged in users) are allowed on that particular path.
The .anonymous() expression mainly refers to the status of the user(logged in or not).
Basically until a user is "authenticated" it is an "Anonymous user". It is like having a "default role" for everybody.
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.