Custom RoleProvider in a MultiTenant MVC App - asp.net-mvc-3

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!

Related

Get user and roles from different servers at Spring Security

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.

get user role in resource server from authorization server

I have an authorization server which on the basis of username and password fetches the user details from the DB along with the roles.
Now while accessing the protected resource in the resource server (passing the access_token), I want to authorize the rest call on the basis of role.How do I do that ?
Because, while I am checking the Principal user in resource server, its getting the default [ROLE_USER]
//Will #preAuthorize() work here ?
#RequestMapping(value="/pinaki", method=RequestMethod.GET)
public String home(Principal principal) {
return "Hello World";
}
Please guide..Thanks in advance
AFAIK spring-security-oauth2 only supports getting the user details (including roles) for a Authorization Server/Ressource Server that share a common data store (either database or in memory)out of the box.
If you do have a common data store you can use the InMemoryClientDetailsService or JdbcClientDetailsService.
However it should not be too hard to extend this by yourself if in your setup there is no common data store. The key interfaces for this task are ClientDetailsService and ResourceServerTokenServices.
A ResourceServerTokenServices implementation returns a OAuth2Authentication including roles. So you could call the tokeninfo endpoint from the authorization server here.
Implementing a ClientDetailsService and using that would be more elegant. Here also you would need to call the tokeninfo endpoint.
In XML configuration you can setup the beans to use in the oauth:resource-server tag in the parameters token-services-ref and auth-details-source-ref.
Details on the Java config can be found on page http://projects.spring.io/spring-security-oauth/docs/oauth2.html
(My info refers to version 2.0.8 of spring-security-oauth2)

Proper way to dependency inject authenticated user to my repository class

I am using a service layer with repository pattern. The controller has a dependency on the service layer, and the service layer has a dependency on the repository.
I have to pass logged in user information to the repository layer for authorization purposes and am trying to determine the best approach for injecting the user information into the repository considering that I seem to have an extensive injection chain:
controller -> service(s) -> repositories -> logged in user info.
I guess the easy approach would be to pass the user information to the service methods that get called(i.e. FindById(int primaryKey, User currentUser), etc.)
But this seems very limiting and problematic down the road as opposed to injecting the User information.
What is the recommended approach to this problem?
I am a little confused about how the person in the article seems to be implementing the ICurrentUserFetcher. I assume that is would provide the extra properties that are not available from the IIdentity, but the article does not make this very clear.
class GenericRepository<T>: IRepository<T> {
private readonly ICurrentUserFetcher currentUserFetcher;
public GenericRepository<T>(Func<IIdentity> currentUserFetcher) {
this.currentUserFetcher = currentUserFetcher;
}
public void Update(T entity) {
var currentUser = currentUserFetcher();
...
}
}
var repo = new GenericRepository<Person>(() => HttpContext.Current.User.Identity);
Assign the user information to the current principal after the login. Google about IPrincipal and IIdentity. Those two classes are the built in way in .NET to handle the currently logged in user.
To access the user simply use Thread.CurrentPrincipal.Identity. I would however not use that property in the repository, but only in the service class. The reason to tha this that the repository should not be in charge of telling which user to fetch information for.
To assign the user on every request you have to use the PostAuthenticate event in global.asax.

Spring Security user account registration, creation and management

I've been looking into using Spring Security for the authentication/authorization of my web application (this will be JDBC based).
However, a core component seems to be left out from my perspective. How do I register/create new users? Is there an out of the box API for that?
Do i need to write user registration and management from scratch?
Things i need to do include:
- Registering a new user
- Resetting passwords
- Emailing a user to activate their account
- Emailing a user to reset their account.
Thank you in advance.
I use Spring Security on my project. The framework does not have an API for user creation or registration as you asked. For Spring Security to be generic and usable across multiple frameworks, it can only take you so far before you have to write custom code. You can't really get a more specific answer about a framework or tool to use because at this point you will just use the frameworks you are already using anyway.
If you've set it up to use users and roles in your database, from your data access layer you would create a record in the user table or update a password (preferably stored as a hash) in that record. And as Aravind said, Spring does provide email support.
If you really want to see one way to do it: I'm using Spring MVC, JSP, and Hibernate. I use Spring's form tags in a JSP to bind a new user form to a Person object, and my controller method passes that Person object to my Dao to persist it.
The controller method signature looks like this...
#RequestMapping(value = "/newUser", method = RequestMethod.POST)
public ModelAndView createNewUser(final #Valid #ModelAttribute Person user,
final BindingResult result,
final SessionStatus status,
final #RequestParam(value = "unencodedPassword", required = true) String password) {
...
user.getRoles().add(new Role(user, Role.APPLICATION_ROLE.ROLE_USER));
userDao.createNewUser(user);
...
}
and my PersonDao would use Hibernate to persist the user like so
#Transactional
public void createNewUser(Person user)
{
Session session = sessionFactory.getCurrentSession();
session.save(user);
session.flush();
}
Have a look at my answer here.
"I have implemented a JAVA project for this use case. It is open
source, based on Spring-Security. A release version is on
Maven-Central, so you do not need to compile it, but instead you can
fetch it as maven-dependency to your project!"
<dependency>
<groupId>com.ohadr</groupId>
<artifactId>authentication-flows</artifactId>
<version>1.5.0-RELEASE</version>
</dependency>
As far as I know, Spring Security does not have built in support for new user creation and registration. You will have to manage this yourself. However it does have emailing support. Check here for more on this.

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