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.
Related
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 REST service implemented using Spring MVC (RestControllers) with token based security (using Spring Security). How can i filter resources depending on user identity? Let's say user has some reports. How can I let authorized user by performing a call to /reports to see only his reports?
Obviously i can make userId to be a request parameter or path variable, but something tells me that this is a bad practice.
I assume i can achieve that using Spring Security features, but how exactly could i do that and, more important, where is the most appropriate place to apply such filtering? Should controllers perform calls to services passing user identity or should it be somehow retrieved at repositories level (I use Spring Data JPA)?
Thanks in advance
You have Authentication object whenever a user is successfully logged in.
It contains Object principal Object credentials and Set authorities.
All you need to do is override UserDetailsService to add new parameters for your authenticated user. Add your userId in authentication as shown in blog
Now when you do
SecurityContextHolder.getContext().getAuthentication().getPrincipal()
this will return you the User object of the spring security.
You can get the user id from here and use this in controller to do necessary actions.
I want to create Sign Up with Spring Security.
It has login(), logout(), but how does Spring perform register request with security?
I have no login, password when I do it. So I need to disable authorization for this page.
So, I need something like:
http
.authorizeRequests()
.antMatchers("/register").iHaveNoLogin().iHaveNoPassword().iHaveNothing();
Fixed.
I just marked only selected pages as authorized:
http
.authorizeRequests()
.antMatchers("/secured_pages**") ...
And other pages do not require authorization.
Spring Security does not provide a registration page for you. You have to do it yourself. It's not a complicated form to make yourself.
They are nice enough to supply the JdbcUserDetailsManager, and its createUser method, which can make it fast and simple to create a user in your database.
Generally all rest based framework provide authenticate.
But are there any framework/lib/pattern that helps to secure rest endpoint with following capability
Only a authenticated user with following roles can access a end point with only particular params.
Basically i am trying to prevent two user(with same roles) to view each other data by passing each other id in request urls
Yeah you should look at Apache Shiro it offers really good support role base/permission based authorization.
An example of how you can annotate an endpoint would be:
#RequiresRoles(value = "admin")
I'd recommend you to check the Instance-Level Access Control of this document.
I am using my own MVC implementation and I am not sure, whether the Spring Security isn't designed specifically for the Spring MVC implementation. Is it still okay to use it?
It is not clear to me, which parts of Spring Security I should use and which I don't need to. I suppose I don't need the URL filters as I need to validate the access specifically on the URL parameters in my controllers (for instance to check whether User is the owner of the Article). Something like:
if (request.getUser().isAllowedTo("EditArticle", 27)) {...}
if (request.getUser().isAllowedTo("CategoryManager", 123)) {...}
if (request.getUser().isInRole("Admin")) {...}
I could not find some clear way of users logging in/out programmatically. I've implemented my UserDetails and UserDetailsService classes to handle the users with JPA, but I don't see a way, how I can proceed with login and logout in my controllers.
EDIT:
I don't see a way how to put the <form> in my Freemarker templates - the only way of creating the form I found is with:
<http pattern="/login.htm*" security="none"/>
<form-login login-page="/login.htm" default-target-url="/home.htm"/>
</http>
How can I configure the structure of the login form? Can I create it by myself?
What I would like the most is to be able to handle the login by myself (for example with DWR) and not to use the magic j_security_checks...
It would be great, if I could handle the login request by myself and ask the auth service to login the user by myself (so I could easily use Direct Web Remoting (DWR)):
if (user.username.ok() and user.password.ok()) {
authService.setUser(user);
authService.setLoggedIn(true);
}
Spring security is not limited to spring mvc and can be used with your own framework implementation. It provides handy services for authentication and session management.
Spring is very convenient to use to leverage access by certain URLs but not limited to. You will be able to get which roles the current user has at the moment from the spring context and all the custom info you would include in your UserDetails object. There are number of ways to restrict access to certain actions by certain roles. However the code like if (request.getUser().isAllowedTo("EditArticle", 27)) {...} I think it will be simplier to check by yourself.
Login and logout are done by calling specific urls. For login: /j_spring_security_check. For logout: /j_spring_security_logout.