Get user and roles from different servers at Spring Security - spring

I have an application that uses a LDAP server to authenticate. It works fine. But, there is a problem: in this LDAP server, I don't have the user roles. I have them in another server, in a database my application access. And I need to add the user roles to the application from now on.
I'd like to know how to get those roles and add them to the AuthenticationManagerBuilder auth at configureGlobal method. Is it possible?
Some information:
My configureGlobal method is:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.ldapAuthentication().userSearchFilter("uid={0}").contextSource().url(host);
}
I'm using hibernate 4.3.8 and Spring Security 4.1.1.
The table with the roles was created like this:
create table UserGroup (
user varchar2(250),
role varchar2(250)
);
And the records are something like this:
[user1, role1]
[user1, role2]
[user1, role3]
[user1, role4]
[user2, role1]
[user2, role2]
As you can see, the same user can have more than one role. The same role can be assigned to many users. I know it needs normalization, but I think that's not important at this point.

What I have done in the past is implement a UserDetailsService that populates the user name and roles from the application's database & AbstractUserDetailsAuthenticationProvider that does an LDAP bind check inside additionalAuthenticationChecks.
Works like a charm.
In fact, the UserDetails contains a flag that tells me where to validate the user and inside the additionalAuthenticationChecks, we validated the user against one of multiple validation sources, such as the local database, or various multi-tenant LDAP servers.

Related

Spring security - specific users

I am using ldap for authentication of requests.
I have configured by extending WebSecurityConfigurerAdapter and overriding configure(HttpSecurity) and configure(AuthenticationManagerBuilder) methods.
The credentials will be verified using ldap and on top of that, I need to maintain a static list that contains specific usernames to be allowed to access.
Can anyone help with the usernames validation part - do I need to write an extension of AuthenticationProvider to validate credentials and check for username? Just by configurations, I am able to take care of credentials verification.
do I need to write an extension of AuthenticationProvider to validate credentials and check for username
Yes. You need to have two different authentication provider. One to validate LDAP user's credential and other for static user list.
So, your configure method looks similar like below,
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(LDAPProvider);
auth.authenticationProvider(StaticUserProvider);
}
Here, an order is important because, user's credentials would validate according to above mentioned provider order.i.e first with LDAPProvider then with StaticUserProvider.

How can I get all roles of a user by user id in Spring Security?

Is it possible in Spring Security to get all roles of a user if I only know a username? I am thinking of something like this:
List<String> userRoles=veryCleverObject.getRolesByUsername("user123");
I know how to do this for current user but not for any user. My workaround is I query it with JpaRepository from the db but this is not a good solution for obvious reasons.
I need this in a simple user management modul in my app where I list the users and I would like to show their roles.
How can I do that in Spring Security?
In general: no, as authentication may be made via AuthenticationProvider or even AuthenticationManager which, as a rule, require some credentials along with the username; even more, they require this data to be packed in some Authentication class instance. Usually, you don't have any credentials, only a username, and you don't know how to build that Authentication in a generic way.
But if you only use UserDetailsService-based mechanisms (like JDBC authentication http://www.mkyong.com/spring-security/spring-security-form-login-using-database/ or LDAP authentication https://spring.io/guides/gs/authenticating-ldap/ you could just use that UserDetailsService instance which has the following method:
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
It finds UserDetails by username, from which you can get user roles (aka granted authorities).
UserDetailsService may be obtained via dependency injection.

Spring Security, Customizing Authorization, AccessDecisionManager vs Security Filter

I'm going to implement a custom authorization based on ([User<-->Role<-->Right]) model and Rights should be compared to controller and method name (e.g. "controller|method").
I used customizing UserDetails and AuthenticationProvider to adjust granted authority (here), but as checked source codes and docs about how customizing the compare of authority I found there is a filter SecurityContextHolderAwareRequestWrapper) that implements isGranted and isUserInRole to compare authority, while the documents say using AccessDecisionManager voters to customize (As I understood). Which one should be used ? Where I have controller and method(action) name to compare authority with them ?
I got confused about Spring security a little. Is there any other resource than official docs that illustrate how it works, I mean sequence of actions and methods and how customize them.
There are several approaches:
Role based, where you assign each user a role and check the role before proceeding
Using Spring security expressions
There is also a new spring acl components which lets you perform acl control on class level and are stored in a database.
My personal usage so far has been 1 and 2, where you only assign roles to users.
But option 3 allows you to create finer grained security model, without having to rebuild your webapp when chaning the security model
Role Based
A role based security mechanism can be realised implementing the UserDetailsService interface and configuring spring security to use this class.
To learn on how to such a project can be realized, take a look at the following tutorials:
Form based login with in memory user database Link
Form based login with custom userdetails service Link
In short spring security performs the following behind the scenes:
Upon authentication (e.g. submitting a login form) an Authentication Object is created which holds the login credentials. For example the UsernamePasswordAuthenticationFilter creates an UsernamePasswordAuthenticationToken
The authentication object is passed to an AuthenticationManager, which can be thought of as the controller in the authentication process. The default implementation is the ProviderManager
The AuthenticationManager performs authentication via an AuthenticationProvider. The default implementation used is the DaoAuthenticationProvider.
The DaoAuthenticationProvider performs authentication by retrieving the UserDetails from a UserDetailsService. The UserDetails can be thought of as a data Object which contains the user credentials, but also the Authorities/Roles of the user! The DaoAuthenticationProvider retrieves the credentials via its loadUserByUsername method
and then compare it to the supplied UsernamePasswordAuthenticationToken.
UserDetailsService collects the user credentials, the authorities and builds an UserDetails object out of it. For example you can retrieve a password hash and authorities out of a database. When configuring the website url-patterns you can refer to the authorities in the access attribute. Furthermore, you can retrieve the Authentication object in your controller classes via the SecurityContextHolder.getContext().getAuthentication().
Furthemore to get a better understanding of the inner workings of these classes you can read the javadocs:
UserDetails - how the user credentials are stored and accessed
AuthenticationManager.authenticate(..) - contract on how AuthenticationExceptions are handled
UserDetailsService.loadUserByUsername(..)- contact on how username lookup failures are handled, e.g. user does not exist
Spel
Instead of checking authorities, SPEL enables you also to check other properties of a user.
You can use these in the URL patterns, but also annotate methods with #Preauthorize.
This way securing the business layer is less intrusive.
ACL Based
The ACL based model was introduced in spring security 3.0, but hasn't been well documented.
Their suggestion is to look at the Contacts XML example, since this one uses their new acl component.
Last this book contains great examples on how to further customize your security wishes.

Custom RoleProvider in a MultiTenant MVC App

I need to develop a custom RoleProvider for a MultiTenant web app.
At the DB level, we have a table that relates Users with Roles with Tenants.
My problem is that RoleProvider gets user roles just passing the User as parameter, and we need to take the Tenant into account.
In RoleProvider implementation we have:
public override string[] GetRolesForUser(string username)
{
//Code to retrieve roles from repo
}
As the roles are for a user in an specific Tenant, we need:
public override string[] GetRolesForUser(string username, int tenantId)
{
//Code to retrieve roles from repo
}
The current tenant is stored in the ControllerBase class (the one that all controllers inhereted from).
The Membership and Role Providers are in a separate project, so I don't see a way to use the current Tenant. I think I could create my custom RoleProvider in the web app project.
Any idea on how to implement the RoleProvider interface taking the Tenant as part of the input ?
Well, just to inform you what I did in my case:
As our routes are in the form of http://[tenantName].[domain]/[App]/[Area] we ended up getting the [tenantName] from the Request, since it is unique, and with the Tenant and the UserName that came as a parameter I can do my select on our UsersInTenants' table.
The very same can be done using cookies as a way to pass aditional information.
So you can access the request, with the cookies, but for what I research the Session is not yet initialized in most cases.
Hope it helps!

use existing domain classes with Spring Security plugin

I'm trying to convert a Stripes web app to Grails. The Stripes app uses Spring Security, but I would like the Grails app to use the Spring Security Grails plugin.
The app already has User and Role (Java) classes that I need to reuse, i.e. I cannot use the Grails domain classes that the s2-quickstart script generates.
The Spring Security plugin docs describe how to use an existing User domain class. The steps seem to be:
define a UserDetails implementation that reads from the existing User domain class
define a custom UserDetailsService implementation that returns instances of (1)
register an instance of (2) as a Spring bean named userDetailsService.
However the docs don't provide any information about how to use an existing Role class and the class that represents the many-to-many relationship between User and Role.
What other steps are necessary to use existing Role, User, and UserRole classes with the Grails Spring Security plugin? Is there any reason for me to run the s2-quickstart script if I don't want to generate any domain classes?
Follow-Up Questions to Burt's Answer
In the end, what you need is a new GrailsUser
Presumably GrailsUser here refers to the custom UserDetails implementation? In my case I'll probably just implement the interface directly. Does something like this seem reasonable?
class UserAdapter implements UserDetails {
private String password
private Collection<GrantedAuthority> springRoles
UserAdapter(User user) {
this.password = user.password
Collection<Role> roles = // load legacy Role objects
this.springRoles = roles.collect { new GrantedAuthorityImpl(it.authority) }
}
// If using password hashing, presumably this is the hashed password?
String getPassword() {
password
}
///////// other UserDetails methods omitted
Collection<GrantedAuthority> getAuthorities() {
springRoles
}
}
I'm not storing the whole User object within UserAdapter because of your warning about storing a potentially large object in the HTTP session.
what you need is.....and a List of GrantedAuthority instances (and the id if it's a GrailsUser)
If I use my own UserDetails implementation as above, then presumably I can ignore this comment about providing an id?
Finally, if I follow the approach outlined above, should I set these properties in Config.groovy and do I need to run the s2-quickstart script (or any others)?
Keep in mind that Spring Security doesn't care where the data comes from, it just needs a UserDetails instance when authenticating with the DAO auth provider and it can come from anywhere. It's convenient to use domain classes and database tables, but it's just one approach. Do what works for your data. In the end, what you need is a new GrailsUser (or some other impl) instance with the username and password set, the 3 booleans set, and a List of GrantedAuthority instances (and the id if it's a GrailsUser).
The simplest thing to do when you have legacy user and role data is to create a custom UserDetailsService. Use GORM, raw SQL queries, whatever you need to get the required data.
Another option is to write your own AuthenticationProvider like Glen did here: http://blogs.bytecode.com.au/glen/2010/01/15/hacking-custom-authentication-providers-with-grails-spring-security.html - although that's a larger solution that also involves a custom filter which you wouldn't need. The DAO provider uses a UserDetailsService but it's fine to create your own that combines the functionality into one class.
It's not a good idea to reuse your User domain class as the UserDetails though. Even if you implement the interface, you'd be storing a disconnected potentially large (if there are attached collections) object in the HTTP session. The POJO/POGO implementations (Spring Security's User class, the plugin's GrailsUser class, etc.) are very small and just a few Strings and booleans.
within the config.groovy file you have to specify your domain classes to use:
grails.plugins.springsecurity.userLookup.userDomainClassName = 'your.package.User'
grails.plugins.springsecurity.userLookup.authorityJoinClassName = 'your.package.UserRole'
grails.plugins.springsecurity.authority.className = 'your.package.Role'
i thinks it's not neccessary to implement your own userDetail service, because spring security uses
SpringSecurityUtils.securityConfig.userLookup
method to determine the domain class you configured before. your domain classes must provide the required fields and relations.

Resources