Spring security with database and multiple roles? - spring-security

I'm trying to make an application using spring 3.0.
Now I've decided to try my hand at spring-security and hibernate.
I've already seen that it's possible to back it with a databasem and I've seen a reference to defining your own queries?
Now the problem I have is that the tutorials I've been finding aren't too clear and that they assume that a user can only have one role. I want to give some users multiple roles.
So I was thinking about a database scheme along the lines of:
User:
user_id
username
password
registrationDate
User_Role:
user_id
role_id
Role:
role_id
rolename
Now I was wondering if anyone had some pointers to some usefull tutorials/advice/comments.

You need to implement your own UserDetails (supports multiple roles for each user). This custom UserDetails implementation is then returned by your own UserDetailsService implementation that's injected on your daoAuthenticationProvider.
See also my answer # Spring Security 3 database authentication with Hibernate for a complete example.

Something like this:
public class CustomUserService implements UserDetailsService {
private UserDao userDao;
public CustomUserService(UserDao u) {
userDao = u;
}
public UserDetails loadUserByUsername(String username) {
CustomUser user = userDao.getUser(username);
if (user == null)
throw new UserNotFoundException("User "+username+" does not exist");
return user;
}
}
And your UserDao implementation is a simple DAO that can easily use hibernate annotations and assign multple roles to your CustomUser object. Pretty basic.

Related

Injecting user on Spring Data JPA queries

I´ve largely used JPA and Hibernate, but I'm relativy new to Spring Data JPA. I'm trying to inject the user logged so queries get visibility restriction upon user.
Let's say we have this entity:
public class Group {
private String code;
private String name;
private String creationUserId;
}
And CreationUserId is a FK to the column Id of entity User. This tries to represent that this group should only be accessed to the user whose Id equals this creationUserId.
So, taking into account I'm using JWT (the subject on the token is the userID) and springSecurity (so the user is in SecurityContextHolder.getContext().getAuthentication()), is there any fancy way of doing something like
public List<Groups> findMyGroups () {
return groupsRepository.findMyGroups();
}
using the capabilities SpringDataJPA gives us?
Im trying to avoid doing something like
public List<Groups> findMyGroups () {
MyUser u = (MyUser)SecurityContextHolder.getContext().getAuthentication().getDetails();
return groupsRepository.findGroupsByUserCreationId(u.getId());
}
I don't have a problem on doing so, but it would result in such boilerplate, and maybe there is some workaround for achieving it.
Of course I don't want this on every single query, just in somes (there are two different security roles for listing, group:readAll and group:readMine).
Spring Security provides integration with Spring Data to achieve what you want. Take a look at the reference documentation about that.
In short, you have to add the dependency and expose a Bean of type SecurityEvaluationContextExtension, like so:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-data</artifactId>
</dependency>
#Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
When you have this, you can use the Authentication in your queries:
#Query("SELECT g FROM Group g WHERE g.creationUserId = ?#{principal?.id}")
List<Group> readMine();

Wicket Security - Change Roles of an Inmemory User

I'm using Wicket 7.0 in an application I'm developing and I would like some advice regarding using Inmemory-users during development.
The idea is to have one single Inmemory user whom I set the roles of right before I log in.
My first intended approach is to instantiate the user at startup with "username" and password but without any roles. Then I would like to add/remove roles through ticking Checkboxes in a component in the Login-form and finally log in with the predefined user/pwd.
Can an instance of an Inmemory-user have it's roles changed when the application is running? Or should I delete it and create a new instance of it everytime I want it to have different roles? Is this even the best and simplest way to go about ti?
This is only during development for convenience.
Thanks in advance
Inject UserDetailsManager and use its updateUser() method to update its roles:
#Service
public class SingleUserSwitchService {
#Autowired
private UserDetailsManager userDetailsManager;
public void changeUserRoles(String ... roles) {
Collection<GrantedAuthority> roles = ... // new roles
User user = new User("login", "password", roles);
userDetailsManager.updateUser(user);
}
}
Here, I assume that your user login is 'login' and you hardcode the password.
Then you just need to call your service with the list of the desired roles.

Add roles to ADFS IPrincipal

I have been looking for answer to this question for a few days now, but I have not found any success. I would post the links, but it would probably take up the entire page.
So here is what I have...
I have an MVC application, which uses the WC-Federation protocol. I have been able to configure the application, so that it authenticates the users, and returns the claims from ADFS. This works perfect. I can also extract all the claims with no issues. But I am doing this within one of the actions in the controller.
And here is what I want to do...
I want to use ADFS to authenticate the user, but I want to use my own internal roles to authorize the user to have access to specific controllers (e.g. [Authorize(Roles = "CoolRole")]). I want to be able to do this, because I already have a Web API that uses OAuth 2.0, with a backend SQL Server database to manage users and roles (internal and external user.) I now want a secure portal that will allow internal users to access the data with a single-sign-on experience. Looking at the Controller model, I noticed there are some properties associated with the authentication process (OnAuthentication, OnAuthenticationChallenge) and one for the authorization process (OnAuthorization.)
I don't necessarily need the code, but I feel like I've hit a brick all, and I need to be pointed in the right direction.
UPDATE
I tried this:
protected override void OnAuthorization(
System.Web.Mvc.AuthorizationContext filterContext)
{
//Private class to create a new IPrincipal based on my AppUserMgr
var user = _setCurrentUser(
(ClaimsIdentity)filterContext.HttpContext.User.Identity);
filterContext.HttpContext.User = user;
base.OnAuthorization(filterContext);
}
This returned a 401 (Unauthorized) response.
and...
protected override void OnAuthentication(
System.Web.Mvc.Filters.AuthenticationContext filterContext)
{
//Private class to create a new IPrincipal based on my AppUserMgr
var user = _setCurrentUser(
(ClaimsIdentity)filterContext.HttpContext.User.Identity);
filterContext.Principal = user;
base.OnAuthorization(filterContext);
}
This just calls the STS numerous times, before it fails. I even tried swapping after the assignment to after the base is called in both. No luck.
Prior to the previous ones, I also tried to add an AuthorizeFilter to the control, but that didn't help:
http://pratapreddypilaka.blogspot.in/2012/03/custom-filters-in-mvc-authorization.html
I found this link: http://brockallen.com/2013/01/17/adding-custom-roles-to-windows-roles-in-asp-net-using-claims/
From there, I guessed my way through
Here is the basics of what I did:
I ended up overriding the OnAuthentication method of the Controller, but still made sure to call the base. I did this from within an extended class. Here is the concept:
public class AdfsController : Controller
{
//Some code for adding the AppUserManager (used Unity)
protected override void OnAuthentication(
System.Web.Mvc.Filters.AuthenticationContext filterContext)
{
base.OnAuthentication(filterContext);
//Private method to set the Principal
_setCurrentUser(filterContext.Principal);
}
private void _setCurrentUser(IPrincipal principal)
{
//Put code to find to use your ApplicationUserManager or
//dbContext. roles is a string array
foreach(var role in roles)
{
((ClaimsIdentity)((ClaimsPrincipal)principal).Identity)
.AddClaim(new Claim(ClaimTypes.Role, role));
}
}
}
In the Controller, you can now add the follow:
public class HomeController : AdfsController
{
//I used a magic string for demo, but store these in my globals class
[Authorize(Roles = "CoolRole")]
public ActionResult Index()
{
return View();
}
}
I tested this by checking a role assigned to the current user, and that worked! Then I changed the role to something like "reject", which the user was not assigned; and I received a 401 Unauthorized.
ADFS is the authentication/token service in Azure. to enable the Roles Based Authentication, you can use Azure RBAC (Role Based Access Controll) service to basically Augment the claims that you get back from the ADFS and add the roles that you get back from RBAC to the token, and use the same token in your API so lock down or secure the backend with that augmented token...
here is the reference for RBAC:
http://azure.microsoft.com/en-in/documentation/articles/role-based-access-control-configure/

2 UserDomainClass in Spring Security

In the existing Grails application, I have 2 user domains, say UserAdmin and UserBasic. Both these domains have few common fields and also some distinct fields(respective to domain) and currently the login/logout is maintained using sessions for both types of users separately. I want to integrate spring-security in the existing application.
What would be the best approach to do it ? Considering that both domains also have different field. Can we inherit both the domains in a single domain and use it as Spring Security user class ? Please suggest.
Spring Security Core uses one of the implementations of UserDetails interface as a projection of authenticated user. Grails provides e.g. GrailsUser class:
https://github.com/grails-plugins/grails-spring-security-core/blob/master/src/java/grails/plugin/springsecurity/userdetails/GrailsUser.java
Keep in mind, that this class is not a "domain" class in terms of Grails application layout - it does not get persisted in the database, it's just a projection of the user that is bounded to the current session.
If you have 2 different domain classes that represents users in your application, you can try to provide your own implementation of UserDetailsService, e.g.
class CustomUserDetailsService implements UserDetailsService {
#Override
UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
// 1. Check if expected user is type of UserBasic
// 2. If not, check if expected user is type of UserAdmin
// 3. If nothing found, throw an exception
// 4. Otherwise create new GrailsUser instance using UserBasic or UserAdmin data
// 5. Return created GrailsUser instance
return null
}
}
Then you have to inject your implementation by adding or modifying an entry in grails-app/conf/spring/resources.groovy e.g.
// Place your Spring DSL code here
beans = {
// other beans goes here
// ...
userDetailsService(CustomUserDetailsService)
}
This is just a concept that you can start from.

Spring 3, Spring Security. Extract authenticated User object

This is a Spring Security question.
In my application, I have a User entity as a domain object. This object contains implementation to support Spring UserDetails object. The authentication (login/logout) process works fine.
The challenge is that I need to extract that object from the session to make 'business logic' decisions in my code.
I've been reading about querying SecurityContextHolder, but frankly, I still don't know what is the best approach, given that multiple Spring versions seem to be a factor in those discussions. Also, the Principal object isn't a solution for me, as it does not seem to contain any access level or role information.
Below is a simple controller to illustrate my challenge. It has my User domain object hardcoded. I need to replace that block with code that will obtain the User object from Spring Security session. I'm looking for the best way to do this within Spring 3.
Can I get this object as my domain object or do I need to get it as Spring UserDetails object and manually convert it?
Can this Security context lookup be injected somehow into my controller?
public class HomeController {
#RequestMapping(value="/home.html", method=RequestMethod.GET)
public ModelAndView getHomePage(Map<String, Object> model) {
// Get current user
User currentUser=new User();
currentUser.setUserName("Admin");
currentUser.setAccessLevel(UserAccessLevel.ADMINISTRATOR);
// Construct HomePage bean
HomeBean bean=new HomeBean();
bean.setCurrentUserName(currentUser.getUserName());
// Construct list of catalogs
Collection<String> catalogList=new ArrayList<String>();
catalogList.add("articles");
catalogList.add("files");
catalogList.add("comments");
if(currentUser.hasAdministratorAccessLevel()) {
catalogList.add("users");
}
bean.setCatalogList(catalogList);
// Construct and return ModelAndView
ModelAndView mav=new ModelAndView();
mav.setViewName(WebView.HOME_PAGE.getViewName());
mav.addObject(bean.getBeanId(), bean);
return mav;
}
=== Update 2012-01-07 ======================================================
I'm working with Luke's suggestion. The method that gets UserDetails from session and converts it to a returned my domain User object is in my UserService.
Here's my controller:
#Controller
public class HomeController {
#Autowired
private UserService userService;
#RequestMapping(value="/home.html", method=RequestMethod.GET)
public ModelAndView getHomePage(Map<String, Object> model) {
// Construct HomePage bean
HomeBean bean=new HomeBean();
User currentUser=userService.getCurrentlyAuthenticatedUser();
bean.setCurrentUserName(currentUser.getUserName());
And here's key code from UserServiceImpl.getCurrentlyAuthenticatedUser():
#Override
public User getCurrentlyAuthenticatedUser() {
User currentUser=new User();
Authentication a = SecurityContextHolder.getContext().getAuthentication();
UserDetails currentUserDetails = (UserDetails) a.getPrincipal();
if(currentUserDetails==null) {
return currentUser;
}
currentUser.setUserName(currentUserDetails.getUsername());
This works but am I doing this right? Feedback much appreciated. I am still unable to retrieve my User domain object from the session. I'm retrieving Spring's UserDetails object and with it constructing my domain User object but in the process some information is lost.
Normally, the principal object contained in the successful Authentication will be an instance of your user object. So, for a quick solution, use
Authentication a = SecurityContextHolder.getContext().getAuthentication();
User currentUser = (User)a.getPrincipal();
But also (once you get that working), you might want to look at the answer I just gave (to a similar question) on how to inject a custom security context accessor.
Spring also provides an annotation #AuthenticationPrincipal, it is used to resolve Authentication.getPrincipal(). It can be used like below...
public ResponseEntity<UserProfileResponse>UserProfile(#AuthenticationPrincipal JwtAuthenticationToken principal){

Resources