I am applying spring security to a web application where i need to do the following:
Limit access to certain pages for certain roles/authorities
Limit access to certain data based on user access and user role (for
example admin can see all data, a user can see only data on which the admin granted access for the user)
Allow actions on data based on the access right the user has (read,
manage, etc)
So, i was thinking:
Limit access to certain pages for certain roles/authorities -> use
hasRole
Limit access to certain data -> filter directly in the queries
getting the principal from the security context
Allow actions on data based on the access right the user has -> use
my custom PermissionEvluator's hasPermission method
Now this is a setup i came up with, but would like to know if this makes sens and if it is according to a good use of the spring security framework or am i simply twisting it too much.
Spring security provides all these features and makes implementing these features simple. Yes your approach is right. you can add below cases.
security none: allow unauthenticated users access to certain
pages.(login, public pages) authenticated: allow access to
authenticated users.. (general access to all registered users)
restrict based on role: readonly, editor/manager, based on
permissionEvaluator on the data user has access to
You can also use spring security to protect your web application against malicious users with features like
- CSRF protection (enabled by default)
- XSS protection
for further detail read: spring security manual
Related
Currently our spring boot app uses okta for login. There is a need to implement RBAC for the application so I was trying to see if I can leverage okta itself for mapping users to specific roles.
I would like to implement the standard RBAC model in which I would map multiple permissions under a role and the roles are associated to users. Basically it involves 3 levels permissions > roles > users.
But in okta I don't see the standard way for mapping roles and permissions. RBAC is achieved by creating groups and associating groups to the users, which is two levels. And groups needs to be added as a custom claim.
How do I achieve the standard RBAC mapping(permissions > roles > users) in okta or it's something that needs to handled outside the IDP provider.
Thanks in advance.
Possible Solution:
You can make the scopes (scp in access token) be your permissions. Below are the steps:
In your Authorization Server, create your custom scopes(permissions) and set them as default scopes (this is necessary).
For example create 2 default scopes:
books.read (default=true)
books.write (default=true)
Go to access policies in your Authorization Server create one if none is defined.
Create access policy rules in the access policies page, the rules will be your mapping between groups and scopes.
Test that in Token Preview tab, the trick here is to leave scopes field empty so that the Authorization server can return the default scopes that are set for the user, as explained by Okta:
A default scope will be returned in an access token when the client omits the scope parameter in a token request, provided this scope is allowed as part of the access policy rule.
Now in your application when requesting an authorization code make sure that scope query param is empty.
Depending on the library you are using you may face some issues if by default they are expecting an id_token to be always returned but you will probably be able to customize it. For example: https://github.com/okta/okta-auth-js/issues/827
Solution Limitations:
As mentioned in steps 4 and 5 we are omitting the scope query parameter, this mean that only our custom scopes assigned for the user or his groups will be returned, since the base scopes that are predefined by Okta such as profile, openid, email ... will not be returned. Which also means that we are skipping OIDC which needs the openid scope, so id_token will not be returned and only an access_token will. So this solution assumes that you don't need any of the base scopes predefined by Okta.
In case you need any of the base scopes
As described in the limitations, the solution assumes that you don't need any of the base scopes predefined by Okta. But in case you do then below is a solution that works in that case but not that nice.
When requesting an authorization code in the oauth flow, you need to send the request twice
first one: omit scope query param, so the default scopes are returned.
second one: append the returned scopes returned from the first request to the list of base scopes you wanted such as openid, profile, 'email`. So you would send something like (encoded already)
?scope=books.read%20books.write%20openid%20profile%20email
Disclaimer:
The above solution may not be recommended, but it works. If anyone can find any security issues with the above solution please leave it in the comments.
When you get into the details of roles and permissions, the data tends to be domain specific and to change often. I would advise against trying to manage it in the Authorization Server.
One design pattern that will give you full control over claims is to form a custom AuthenticationPrincipal that includes roles or permissions from your application database(s).
If interested in this pattern, see these resources of mine:
Custom Claims Blog Post
Java Custom Claims Code
How to run Java Code Sample
Assume I have a database composed of user and projects. A user has a one to many relationship with projects. The user can do operations using rest endpoints.
The problem is:
how can I verify that this user owns this resource?
I don't want a malicious user to change an id then suddenly he views another person's project details/images/etc. Think of it like a social media (my app is not a social media but trying to illustrate the issue): where you can view only your images but not another person's images despite having the same "status".
Most spring-security blogs online is using a role based approach. I have no idea what to even search for in this case (tried multiple search queries to no avail).
One option is to run some sort of multijoin query on every resource request/operation till I reach that resource id and check it's owning user to check if it is the logged in user. However, I am not sure if this way is efficient since there are multiple tables in a chain in the real app (could have a lot of joins if I go this way manually; example: user -> project -> tasklist-> ... -> Note; deleting a note would trigger a large chain) or how to make the "authorizer" use it.
what are my options?
In case it matters:
I am using spring-boot + hibernate/JPA + spring-security
Spring Security has the following concepts:
Authentication:
Proving the an actor is who it vouches to be. Authentication is done using credentials, where credentials can take any number of forms - username/password, token, hardware key, etc.
You can set up Spring Security with a set of acceptable authentication providers.
Authorization:
Given an authenticated user, deciding if that user has access to a given resource. Where the resource can be:
An HTTP endpoint.
An Java Method.
A property of an object.
What you want to do here is provide a custom authorization scheme.
You can read about Spring Security's authorization architecture here, including how to set up custom authorization. Once you're ready you might ask specific questions as you go.
I have a requirement where I need to use role based access to service methods. I have restful services and i use spring-data to interact with MongoDB.
There are some of the restrictions that I have. I deal with a document in DB called "Organization". In each organization, I know who are the Admins. I do not have a repository of users who can access the services.
So the only way I can enforce some access based rules is to check if the logged in user is one of the admin's configured for each organization and then allow the user to access the methods.
Should I think of applying Spring security in this case? Otherwise will a simple check on user against the configured admins in the database document help? Can I make this check at a single point so that I can apply it to service methods based on my use case needs.
Please provide your suggestions / thoughts on how to go about this.
If you use Spring Security your rest methods can take advantage of a passed-in authenticated Principal object (example here) whereupon you can do whatever extra validation desired (such as checking if the admin is good for the given organization requested, etc.) There are many other parameters also available, perhaps allowing for this org checking to be done once and stored in the session object.
Let's consider a fairly simple hypothetical application where users can read or write posts.
Some users can read and write articles while some others can only read them. With Spring Security (3.2.1) I modeled this by having 2 roles:
ROLE_WRITE: this role grants users access to writing posts.
ROLE_READ: this role grants users access to reading posts.
Implementing this with Spring security is fairly straightforward...
Now I want to also allow third-party apps to read and write posts on behalf of users by implementing an OAuth2 provider using Spring Security OAuth (version 2.0.0.M3 ATM).
During the authorization step, the app asks the user whether they are willing to grant the right to read and/or write posts on their behalf. The user here is granting scopes here (not roles).
Then when the OAuth2 consumer calls my REST API, Spring Sec OAuth authorizes the token granted and creates an authentication containing the user with all their roles and only the scopes granted.
The problem (and the question) is that I now have to write different security logic depending on whether the API is called by a user normally authenticated (just check the roles) or whether it's called through OAuth2 (check roles + scopes).
Is it possible to "merge" the concepts of roles and scopes in Spring Security OAuth2 so that during the authorization step, the user grants the app a subset of the roles they have (and have the OAuth2 authentication only report these in the granted authorities)? That way when the 3rd party app makes an API call, the roles on the authentication are the ones granted? That way I don't have to write any OAuth2 specific security logic.
Scopes (and roles) are arbitrary strings, so there is no problem if you want to make then the same. To make the access rule declarations identical you could write an ExpressionHandler that tested authorities or scopes with the same values depending on the type of Authentication it found.
A different approach suggests itself after you read the comments: add a custom TokenStore or ResourceServerTokenServices. These are easily accessible extension points and would permit modifying the OAuth2Authentication so that its granted authorities were the same as the scopes.
My preference, however, is to control the allowed scopes using a OAuth2RequestFactory, limiting them at the point of the token grant to values that are consistent with the user's authorities.
You can configure your own AccessTokenConverter (mainly for JWT) and extract the claims you want from the JWT access token and generate an Authority object. Just define a Bean factory that return an AccessTokenConverter
I am working on a Grails project that protects resources using Spring Security ACL plugin.
This application also allows resource owners to delegate permissions to other users and those users can further delegate their permissions to other users in viral fashion.
This works fine with standard Spring ACL API, but now I have new requirements:
Track who granted/delegated the given permission [User should be able to
see his/her permissions on a given resource as well as all other users
permissions that he/she delegated for that resource].
Control viral delegate by grantee by setting a flag to indicate if
this permission can be further delegatable.
I am planing to support those requirements by adding two additional fields [ 1. grantee (SID) , 2. isDelegatable ] to ACL_ENTRY table.
I wonder if it will impact any of the Spring ACL core functionality. How can I access those fields using standard Spring ACL API? Can I cast to custom Permission object and access those extended fields?
We are also planing to support time based expirable Permissions which are only applicable during given start and end time frame. where should I add this validation logic so that hasPermission() method call consider the time validity of the granted Permission?
Please advice.