We need to add access control to our application, making sure that every command is performed by a user who has the proper authorities for the given domain objects. We are already using Spring Security 4.0 for authentication and intend to use it for authorization as well.
What makes this complex is the way that authorities are granted to a given user. In our problem space, a User can found several Companies and hire other Users, making them Employees. Each User can be an Employee of several Companies. Some authorities can be granted to a User directly (e.g. canResetOtherUserPassword); other authorities can also be granted by a Company to an Employee based on their Role in the Company (e.g. canOpenProject, canRenameProject). When performing Company-independent commands, User-specific authorities must be checked by the service layer. When performing Company-specific commands (e.g. open a project for a company, rename an existing project), Employee-specific authorities must be checked.
Now let's consider these last two commands, which would have the following service signatures:
long openProject(long companyId, String title)
void renameProject(long projectId, String title)
To control access for the 1st method, the authorization component could retrieve the acting User through the thread-local SecurityContext.authentication, retrieve the Company using the companyId parameter, retrieve the Employee corresponding to the current User, then match Employee-specific authorities against the required canOpenProject authority.
To control access for the 2nd method, the authorization component could again retrieve the acting User through the Thread-local SecurityContext.authentication, retrieve the Project using the projectId, retrieve the owner Company through project.ownerCompanyId, retrieve the Employee corresponding to the current User, then match Employee-specific authorities against the required canRenameProject.
Clearly, this can be done using procedural code, as I just described. We would prefer to use a declarative approach similar to the #PreAuthorize interceptor that Spring Security already offers, and obviously to write as little code as possible. We just don't know where to start.
Any ideas?
Thanks in advance!
You can implement UserDetails (org.springframework.security.core.userdetails.UserDetails) or just extend a default implementation of UserDetails, like User (org.springframework.security.core.userdetails.User) ---> CustomUserDetails with additional attributes like company (with getters).
finally : use simply #PreAuthorize("principal.company.companyId == #companyId")
Reference : Spring Security 3.1 chapter 10 (you need to go back to chapter 3 for UserDetails implementation)
It was very useful for me !
Related
Given :
a oauth client using Authorization code flow used by a website to fetch resources from an API located behind a Reverse Proxy,
some users with differents roles (admin & customer) defined in the roles part of the SCIM 2.0 User schema in Curity
a custom claim 'roles' based on the 'roles[]' field retrieve from the account-manager-claims-provider
two scopes (product_read & product_write)
How can we attached the right scope based on a given role for an unique client in Curity to get :
the product_read scope for all users with 'customer' role
the product_write scope for all users with 'admin' role
Curity docs or videos talk about custom mapper for claims, but it seems there is no example of procedure to dynamically verify which scopes must be attached to a token based on the role of an authenticated user.
I'm looking for an answer dedicated to Curity.io solution and the recommanded best practices to adapte scopes based on a given user role in a web app using RBAC, to secure the calls to the APIs during the user journey.
This type of scenario is usually managed as follows:
Scopes are application level privileges set at design time, and are requested before the user is known
Claims are identifiers with user specific values set at runtime, once the user has been identified
MULTIPLE ROLES APP DESIGN
Personally I would look to model the authorization around the mainstream use case:
Customers can buy things and look at products, and this constitutes the majority of app usage
There is an internal admin operation to update products, which is an exception
This might lead to the following API authorization code:
updateProduct(input: Product) {
if (!this.hasScope('product') || !this.hasRole('admin')) {
throw new ForbiddenError();
}
this.repository.updateProduct(input);
}
I think my personal preference for your use case would be to use the below values:
Scope: product_read
Claim: (role=customer)
You may prefer to call this scope product or product_write. It is true to say that the app has scope to a product but that exact permissions are not known until the user's claims are identified.
APP PER ROLE DESIGN
At one previous company we used to design separate apps for each persona, since the security and UX effort sometimes varied between the two cases:
The main internet app for customers, with scope=product_read
An internal UI for administrators, with scope=product_write
If this made sense for you at some future point, I think my suggested scope would translate nicely.
If two users have same username in the database then how can spring security handle that?
I have two users with following login CREDENTIALS in database:-
1.Username:rohit password:1234
2.Username:rohit password:123
That means the user cannot be unique identified by the username only. So you have to think about the business requirements how to unique identify an user based on the information collected from the user request.
Enforcing the username to be unique across the system can definitely solve the problem. Ask the product owner if it is okay to do it .If not , ask him how to handle such case from the business 's point of view. Then based on the actual requirements of how to unique identify an user , you may need to customise the following classes (Assuming you are using the default username and password login form and authenticate against the user records from DB using JDBC) :
UsernamePasswordAuthenticationFilter
DaoAuthenticationProvider
UserDetailsService
In my Spring Boot application i'm working with Auth0 to manage access to my rest api.
In addition to Auth0's scope i would like to add a ROLE to each user which in turn will provide an additional layer of access control where specific API's won't be accessible to low privileged users.
I've been reading about custom rules and authorization extensions but couldn't quite understand what is the right implementation for me.
Here's my WebSecurityConfigurerAdapter code snippet:
So basically i want only 'ADMIN' for example to be able to access /test/**
#Override
protected void configure(HttpSecurity http) throws Exception {
JwtWebSecurityConfigurer
.forRS256(configBean.getAuth0ApiAudience(), configBean.getAuth0Issuer())
.configure(http)
.authorizeRequests()
.antMatchers(HttpMethod.GET, "/test/**").hasAuthority("read:test")
.anyRequest().authenticated();
}
Any help would be much appreciated!
You have a few options here (at least..).
1). You could conceivably use a Rule to do handle the decision logic on which "ROLES" are assigned to given user - and rather than tag this onto scope (which you could do too..), you may decide they belong instead as a custom claim on that access token. Body of Rule may contain something like
// lookup the permissions for given user somehow (secured webhook, static map etc) - here lets imagine we want ROLE_USER assigned
context.accessToken.scope = "ROLE_USER"
// or
context.accessToken['https://mydomain/roles'] = "ROLE_USER"
2). Simply use the fact that you have the auth0 userid available in the JWT Access token from Auth0 that you send to the API - you could use this knowledge to look up the finer grained permissions for that use "out of bands" of Auth0 (using your own database storage for permissions keyed on user Id etc or some other customer claim tagged on the access token - or by using auth0 if for example you tagged the ROLE information as metadata onto the Auth0 User profile. You could then do an Auth0 user profile lookup (management api) by user id and get details that way. See example here for an illustration in Java on getting the userId claim from the JWT access token if you like this approach.
3). Take a look at the Auth0 authorization extension which provides support for user authorization via Groups, Roles, and Permissions. You can define the expected behavior during the login process, and your configuration settings will be captured in a rule that's executed during runtime.
There is no hard and fast answer here, each of the above merits consideration, and what you need for your project. If you really want to leverage the existing declarative authorization as per your code above, then Option 1, and pegging the ROLES information to the scope is the easiest approach.
However, I would actually advocate option 2). above myself, for most "pragmatic" small to medium sized ventures. Here, you would require a little programmatic code inside your Controller endpoint to lookup the ROLES and then make a security decision that way. You could also push out the lookup code into a common Custom Filter that executes before the Controller code is reached, and does the necessary Spring Security manipulation that way - more of an advanced developer option - (I have written libraries in the past that supported this approach for Spring Boot / Security - and can therefore vouch it is a reasonable approach. See here for demonstration but again, sure you would prefer to get on with building your business logic and not detour into building a library, right?).
Option 3). is definitely worth exploring if you are building out a serious enterprise app, and need all the integrations - especially where integration with enterprise connections such as Active Directory are in play.
Leave me comments if you are still confused, but hopefully the above offers sufficient insights to explore further.
Quick update
Further to our discussions, here is a little Rule that gives you the idea you were asking about:
function addRoleScopesToAccessToken(user, context, callback) {
console.log("add-role-scopes-to-access-token rule");
user.app_metadata = user.app_metadata || {};
var roles = user.app_metadata.roles;
if (roles && roles.length > 0) {
context.accessToken.scope = roles.join(' ');
}
callback(null, user, context);
}
And this is how your "app_metadata" might look like:
{
"roles": [
"role1",
"role2"
]
}
You should end up with a JWT access token with the roles added to the scope. eg.
Hi have an app in Spring mvc 3 and Spring Security 3. Happens that i decide promote an user( I have a database with user,role and user_role tables), but when i add the new role to database comes the problem, how updating the principal authorities without logout the user? Looking for an answer i found this:
// update database with new role
//... you fill in this part
// update the current Authentication
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority> (auth.getAuthorities());
authorities.add(new GrantedAuthorityImpl('ROLE_NEWROLE'));
Authentication newAuth = new UsernamePasswordToken(auth.getPrincipal(),auth.getCredentials(),authorities)
SecurityContextHolder.getContext().setAuthentication(newAuth);
Now, this approach looks good, but my question is, given that securitycontextholder retrieves the information concerned to the current user which calls him, how can I apply the code of above to each user in the system, from my admin account?
I am using my own authentication provider.
One option would be to implement the following strategy:
Keep a global registry of users whose roles have been modified. This could be implemented using a ConcurrentHashMap (or a distributed cache if you have multiple app servers).
As soon as an admin changes the role of a user, push the user's (whose role has been changed) principal (email address, username, etc.) to this registry.
Write a filter that checks whether the current user's principal in the registry. If the principal is in the registry, the filter refreshes the user's role and then removes the principal from the registry. The rest of the request is then handled as usual.
Let's say I have users and articles.
Anonymous can list and read articles.
Only registered and logged user can create articles.
User can edit only own articles.
And, of course, admin can do anything.
I've looked at spring security, but didn't found a way to do that. My app don't need roles, and ACL will be too "heavy" for that.
Maybe I should implement my own security?
You're right, ACL would be too much for the task.
You can use Spring Security's authorize tag in JSP, which provides access to the logged in user via the principal object. Example to limit access to editing an article to the user with a given username:
<sec:authorize access="hasRole('SOME_PRIVILEGE_OR_ROLE') and ${someArticle.username} == principal.username">
...
</sec:authorize>
Note that SOME_PRIVILEGE_OR_ROLE could be some role like 'LOGGED_IN_USER', but could also rather specify a certain privilege, e.g. 'READ_ARTICLE' or 'UPDATE_ARTICLE'. Spring Security is flexible here. Whatever you choose, it needs to be in the GrantedAuthorities collection of your user object.
Note also that you can implement your own user object, adding further info to what the UserDetails interface provides, e.g. comparing the user's id rather than the username.
Finally, note that you need a recent version of Spring Security (>=3.1) for the Spring EL to work as in the example.