I need to make a legacy application start using spring security 3.
This app already has its security data model with:
Very simple by far. I can write my custom usersByUsernameQuery and authoritiesByUsernameQuery.
The thing is that there is another table indicating the operation (i.e. #Service layer method) that a Role can execute:
So the administrator can enable/disable a role from accessing an operation through a web interface, without redeploying the app.
I still can annotate the business methods with #Secure('ROLE_ADMIN') for example, but my custom UserDetailsService must know at least the method name that is being secured, so I can perform the right query.
So, the question is: is there a way that my custom UserDetailsService can intercept the method's name that is being secured?
It sounds like your access-decision is based on the "operation role", rather than the user roles, so it might be better to use the "operational role" directly in the Spring Security constraints. That is essentially an RBAC approach, where there is a mapping between the user roles and the operations they are allowed to perform.
You would address the issue in the AuthenticationProvider rather than the UserDetailsService, by adding a mapping layer in there which translates the user roles (supplied by the UserDetailsService) into the rights that the user has within the application. These would make up the collection of authorities that are returned in the Authentication object created by the AuthenticationProvider.
The mapping layer would directly use the data which your administration interface provides.
You might want to take a look at this presentation, by Mike Weisner, which covers similar material, amongst other things.
Not also that Spring Security 3.1 will include an additional GrantedAuthorityMapper strategy to make it easier to plug in a mapping of this kind.
Related
I am new to Spring boot. I need to implement role based authorization in spring boot. I am having different roles and multiple users will be mapped to each role. I will be setting different access (read, add, delete, edit)
Whenever an api gets called, need to check the access and allow permission.
I am planning to use interceptor to call method having the query to get the access from DB and deny or access the api.
Is there any other better way I can use for the same?
If you are using Spring Security you can handle it with method security annotations like #PreAuthorize, #PostAuthorize .. even combine them to new annotations.
First your User need to implements UserDetails then you should implement getAuthorities() method according to your Role and Authority structure Spring Security basically checks what getAuthority() method returns if returned value prefixed with "ROLE_" like "ROLE_ADMIN" it will be processed as ROLE if it does not prefixed with "ROLE_" it will be processed as Authority
you can use method annotation for checking authority and role like following example:
#PreAuthorize("hasRole('ROLE_ADMIN') and hasAuthority("READ")")
and Spring Security will check your granted Authorities by getAuthorities() implementation of your User then, according to your annotation it will be checked automatically by Spring Security behalf of you.
For clarity you can check
https://www.baeldung.com/spring-security-granted-authority-vs-role
For quick working implementation you can check article below(I would not directly use it but you can understand the idea. Also you can use permissions but simple solution probably the solution below.):
https://www.baeldung.com/role-and-privilege-for-spring-security-registration
For authorization, there can be these two ways as well:
OAuth (Reference - https://medium.com/#bvulaj/mapping-your-users-and-roles-with-spring-boot-oauth2-a7ac3bbe8e7f)
Spring Security Roles and Privileges(Reference- https://www.baeldung.com/role-and-privilege-for-spring-security-registration)
You can create a custom annotation to handle request for each role. I you can read this article for more details about how to implement.
And in api will have format:
#GetMapping(...)
#YouCustomAnnotation("roleName")
public void doSomeThing(){
}
This api will be called if role of user matched with role define in annotation and server will return 404 code if user's role not match.
I am new to Spring Security. I have a Spring Boot application with two different types of entities. Customers and employees. In Employees I have normal employees, admins and super users. Since I am using JPA, each entity has its own repository. How to model my UserDetailsService with loadUserByUsername since this is a common method to validate against many repositories. Is there anything that I am missing to model around my entities?
Additional Info:
In my design, I have two entities. Customer and Employee. Employee will have roles like NORMAL, ADMIN and SUPER_USER. Customer is a different entity.
Will there be two UserDetailsService and two AuthenticationProvider each pointing to its own table (Customer and Employee)?
As your requirement is to have multiple authentication entry points it is not as simple as Atul's answer.
What you need is
You need to differentiate customer and employee while logging in. (Preferred way radio button)
You need to implement your custom authentication filter i.e, implementation of UsernamePasswordAuthenticationFilter instead of spring-security provided default .formLogin()
Create two UsernamePasswordAuthenticationToken as EmployeeUsernamePasswordAuthenticationToken and CustomerUsernamePasswordAuthenticationToken
In your custom filter get userType from request and based on userType set authToken as empAuthToken or customerAuthToken to differentiate required authentication provider.
Create AuthenticationProvider as EmployeeCustomAuthenticationProvider and CustomerCustomAuthenticationProvider where each AuthenticationProvider should be overridden supports method where AuthenticationProvider supports specific token either customerAuthToken or employeeAuthToken.
Override authenticate method where authenticate method has been passed with Authentication parameter from which you can get both username and password which you can pass to any of you custom service to authenticate user and grant authorities required for user.
While implementing your CustomAuthenticationFilter it is also required to provide your custom authenticationSuccessHandler and AuthenticationFailureHandlers.
If you implement all above without any mistake you can avoid fallback authentication which spring-security provides by default if two customAuthenticationProviders are configured.
For more detail of implementing multiple authentication entry point using java configuration refer my answer given below
Multiple AuthenticationProvider with different UsernamePasswordAuthToken to authenticate different login forms without fallback authentication
and also you can download working code from my github repository
"Will there be two UserDetailsService and two AuthenticationProvider each pointing to its own table (Customer and Employee)?" ..... The answer is yes.
Spring security has filter, UsernamePasswordAuthenticationFilter (check the name of the filter)where you can implement the specific implementation based on input type.
I did the same thing but for different auth mechanisms.
But as per your requirement, it is possible what your looking for.
I have a Spring REST-API which is secured by SpringSecurity.
I have different ways to authenticate in that application.
Customer (db)
Employees (ldap)
Other Applications/Services (inMemory)
Each of these are covered by a different authentication provider, which properly assigns the access roles. (Works)
However I need to know which authentication provider was used to authenticate the user, so I can write it to the logs, history...
User CUSTOMER/max.pain created a new entry.
And of course the username does not really contain that prefix, neither in the db, nor in ldap.
I considered adding a special role based on the authentication provider used, but extracting that information over and over is annoying and probably has bad performance and might cause problems in the future. (user.getGrantedAuthorities().findStartingWith("AP_"))
I also tried using org.springframework.security.config.annotation.SecurityConfigurerAdapter.addObjectPostProcessor(ObjectPostProcessor<?>) but i cannot use it to wrap the AuthenticationProvider with a custom AuthenticationProvider class, because it requires the use the same class for whatever reason.
Is there an inbuild method I could use to achieve that or do I have to use a custom implementation/configuration?
Prozess steps:
Login: EMPLOYEE/always.calm
Don't check CUSTOMER AuthenticationProvider
Check EMPLOYEE AuthenticationProvider
Don't check SERVICE AuthenticationProvider
authentication.getPrincipal().getAP() = EMPLOYEE
Here is what I'm trying to do: I have an authentication EJB that can grant user a "ticket" (pair of key and token) by validating username and password. Clients should pass the ticket every call to remote EJB and such ticket should be able to be fetched by EJB (method, or interceptor) and EJB/ or interceptor should validate the ticket and determine whether the call is valid or not.
I don't want to add ticket as parameter to each function that requires authentication, and I believe there should be a way to implement this. I've looked through several articles about JAAS custom login module, but still can't find a non-vendor specific way to do this. (And I am trying to avoid vendor specific implementation)
If JAAS can't do the job, is there anything like "header" in EJB?
Couldn't you just use roles to perform this authorization? Instead of granting a ticket to a user, assign him a role.
Then, it's just a matter of using the inbuilt functionality of checking whether a user is in a role or not.
Although I agree with #EdH, i.e. use #RunAs, you can accomplish what you want by adding to the EJB context your token.
Red Hat does something similar here by using the interface EJBClientInterceptor.
By looking the code of ReceiverInterceptor (which implements the EJBClientInterceptor) you can see how to modify the EJB context (on the client-side) and add your token:
context.setReceiverInvocationContext(new
EJBReceiverInvocationContext(context, receiverContext));
context.sendRequest();
Using a Jersey service, what would be the most elegant method to authenticate a user with more than just username and password? say, a Business Id, and username as the Principals, and password as the only Credential.
I have a postgres DB with a users table, the same username string can exist for multiple Business entities. (A unique constraint belongs to two columns, Business id and username together).
I Use Basic authentication, having the client send an additional HTTP Header for the Business id. how do I go on from here?
Now, Regarding Authorization, how would I set up Roles and Permissions, if roles are created specifically for each business entity (each business can define it's own roles and connect it to permissions.)? Permissions are static.
does apache shiro (or any other pluggable security extension) offer a solution in this case?
Thanks.
You might consider.
Implement auth logic in the good old servlet filter. JAX-RS application is just normal WWW aplication, so Filters fits well as a simple authorization mechanism.
JAX-RS interceptors (PreProcessInterceptor) where you can implement your auth logic as you need (calling database, etc.) This is "more idiomatic" while working with JAX-RS.
Use Spring Security. This is a good option if you are ready to learn a little it of Spring Framework. Spring Security provides full featured authentication and access control mechanism, so you can implement whatever you need. Note that the rest of application does not neeed to use Spring.
You might also use CDI decorators (example) to implement auth logic, but that would be sort of exotic given still low CDI adoption.
Personaly I would go with 1. or 2, for simple cases and 3 for something more advanced.
(Old question! a response for new users) As you tagged SHIRO in your question, you can just add your own logic by extanding org.apache.shiro.realm.jdbc.JdbcRealm and #Override: getRoleNamesForUser(...) , getPermissions(..), doGetAuthenticationInfo(..) This is an example:
#Override
protected Set<String> getRoleNamesForUser(Connection conn, String username) throws SQLException {
Set<String> roleNames = new LinkedHashSet<>();
Collection<UserRole> roles = /* Get roles from your DB, this example use JPA entity, **but you put here any logic you want**...*/
for(UserRole userRole:roles){
roleNames.add(userRole.getRole().getName());
}
return roleNames; // return roles so Shiro is 'aware' of roles to add them to current user
}
*note that same logic applies for other methods that you override.
** You don't need 2 http calls to log the user, you can just user Shiro programatic auth.
here is a Complete example with Shiro annotation enabled..and more