I'm currently looking into the spring-security framework - great stuff so far, pretty impressed.
However, I haven't found out where or how to define a inheritance of permissions.
e.g. I want the ROLE_ADMIN to have at least the same rights as the ROLE_USER. I defined three intercep-urls for spring:
<intercept-url pattern="/auth/login.do" access="permitAll"/>
<intercept-url pattern="/voting/*" access="hasRole('ROLE_USER')"/>
<intercept-url pattern="/admin/*" access="hasRole('ROLE_ADMIN')"/>
When trying to access any site nesting from /voting/, while being logged in as a ROLE_ADMIN user, I am being denied. Am I missing something here? I know, I could define several roles for the /voting/* branch, but if I imagine that I might have 10 different user roles in one of my real-life usecases, I can imagine the .xml file to get really messy, really fast.
Can I configure the inheritance of roles somewhere?
cheers
EDIT:
Thanks to the great community and their input, I came up with a working solution - it may be good style or not - it works :D
I defined an enum which reflects the inheriting spring-sec roles:
public enum UserRoles {
ROLE_USER(new String[]{"ROLE_USER"}),
ROLE_ADMIN(new String[]{"ROLE_USER", "ROLE_ADMIN"});
private final String[] roles;
private UserRoles(String[] roles) {
this.roles = roles;
}
public String[] getRoles() {
return roles;
}
}
I then implemented my own UserDetailsService:
Within the methode
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException { ... }
where it comes to adding granted authorities to a UserDetail, I get the corresponding enum value and append all the roles defined by this enum value:
List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>(2);
for (String role : UserRoles.ROLE_ADMIN.getRoles()) {
authList.add(new GrantedAuthorityImpl(role));
}
UserDetails user = null;
try {
//user = new User(username, md5.hashPassword(username), true, true, true, true, authList);
} catch (NoSuchAlgorithmException ex) {
logger.error(ex.getMessage(), ex);
}
My domain object which is persisted, contains a #Enumerated field with a UserRole - in a real environment, this field is loaded from the DB and the corresponding Roles are picked from that enum.
thanks again for the input - love this community ^^
Check out RoleHierarchy and RoleHierarchyImpl and this question.
As far as I know, Spring Security does not support the concept of Roles and Privileges. In Spring security are only Roles sometimes called Authority -- Moreover: In Spring Security are Roles/Authorities that what in a Roles and Privileges System is called Privileges.
So if you want to build a System of Roles and Privileges, then you need to do it by your one by building your own Spring Security AuthenticationManager, and tread the Spring Security Roles/Authorities like Privileges.
#See This Blog: Spring Security customization (Part 1 – Customizing UserDetails or extending GrantedAuthority) -- It is written for Spring Security 2.0 and shows how to implement what I am talking about. It also stayes that RoleHierarchy has some drawbacks, but this article is about 2.0, may the drawbacks are gone in 3.0
Related
Spring Authorization Server OAuth 2.1.
How can i programatically simulate the authorization_code grant?
Since all grants except for authorization_code and client_credentials have been dropped this has become quite a headache.
The scenario calls for a #Scheduled job to login as a specific user where the client credentials are encoded properties within the server performing the login.
The user roles are important when executing downstream resources and is considered a regular user of the registered Client.
Using the Password grant was perfect for this scenario in OAuth 2.0.
Before i start hacking our Spring Auth server and implement a Password grant for registered resources or maybe overloading the client_credentials for user_credentialed payloads.
Quite a pain if you ask me, so please enlighten me? Are there any patterns for implementing this that i have not yet discovered?
While I'm curious what specific use case you have that needs to perform tasks as a particular user (as opposed to a single confidential client), it should still be possible with customization.
maybe overloading the client_credentials for user_credentialed payloads
This approach makes the most sense to me as a way to adapt supported flows in OAuth 2.1 to emulate a deprecated flow like the resource owner password grant. You can use a variation of this github gist, extending it with your user's authorities if needed. One possible solution might look like the following:
#Component
public final class DaoRegisteredClientRepository implements RegisteredClientRepository {
private final RegisteredClient registeredClient;
private final UserDetailsService userDetailsService;
public DaoRegisteredClientRepository(RegisteredClient registeredClient, UserDetailsService userDetailsService) {
this.registeredClient = registeredClient;
this.userDetailsService = userDetailsService;
}
#Override
public void save(RegisteredClient registeredClient) {
throw new UnsupportedOperationException();
}
#Override
public RegisteredClient findById(String id) {
return this.registeredClient.getId().equals(id) ? this.registeredClient : null;
}
#Override
public RegisteredClient findByClientId(String clientId) {
UserDetails userDetails;
try {
userDetails = this.userDetailsService.loadUserByUsername(clientId);
} catch (UsernameNotFoundException ignored) {
return null;
}
return RegisteredClient.from(this.registeredClient)
.clientId(userDetails.getUsername())
.clientSecret(userDetails.getPassword())
.clientSettings(ClientSettings.builder().setting("user.authorities", userDetails.getAuthorities()).build())
.build();
}
}
This uses a single client registration, but makes use of a UserDetailsService to resolve a subject representing your user's username and a secret which is actually the user's password. You would then need to provide an #Bean of type OAuth2TokenCustomizer<JwtEncodingContext> to access the user.authorities setting and add those authorities to the resulting access token (JWT) using whatever claim your resource server expects them in.
Alternatively, you could just override the scopes parameter of the returned RegisteredClient if desired.
I had the similar problem and ended up creating a password grant emulation servlet filter. Please refer to my example:
https://github.com/andreygrigoriev/spring_authorization_server_password_grant
I’m unable to use hasRole method in #PreAuthorize annotation. Also request.isUserInRole(“ADMIN”) gives false. What am I missing?
Although .hasAuthority(“ADMIN”) works fine.
I am assigning authorities to the users from a database.
You have to name your authority with prefix ROLE_ to use isUserInRole, see Spring Security Reference:
The HttpServletRequest.isUserInRole(String) will determine if SecurityContextHolder.getContext().getAuthentication().getAuthorities() contains a GrantedAuthority with the role passed into isUserInRole(String). Typically users should not pass in the "ROLE_" prefix into this method since it is added automatically. For example, if you want to determine if the current user has the authority "ROLE_ADMIN", you could use the following:
boolean isAdmin = httpServletRequest.isUserInRole("ADMIN");
Same for hasRole (also hasAnyRole), see Spring Security Reference:
Returns true if the current principal has the specified role. By default if the supplied role does not start with 'ROLE_' it will be added. This can be customized by modifying the defaultRolePrefix on DefaultWebSecurityExpressionHandler.
See also Spring Security Reference:
46.3.3 What does "ROLE_" mean and why do I need it on my role names?
Spring Security has a voter-based architecture which means that an access decision is made by a series of AccessDecisionVoters. The voters act on the "configuration attributes" which are specified for a secured resource (such as a method invocation). With this approach, not all attributes may be relevant to all voters and a voter needs to know when it should ignore an attribute (abstain) and when it should vote to grant or deny access based on the attribute value. The most common voter is the RoleVoter which by default votes whenever it finds an attribute with the "ROLE_" prefix. It makes a simple comparison of the attribute (such as "ROLE_USER") with the names of the authorities which the current user has been assigned. If it finds a match (they have an authority called "ROLE_USER"), it votes to grant access, otherwise it votes to deny access.
I had to improvise a little, maybe there is other ways simpler then mine, but at the time I worked on this I had no other choice but to improvise a bit, after a thorough research came up with this solution.
Spring Security has an interface called AccessDecisionManager, you will need to implement it.
#Component
public class RolesAccessDecisionManager implements AccessDecisionManager {
private final static String AUTHENTICATED = "authenticated";
private final static String PERMIT_ALL = "permitAll";
#Override
public void decide(Authentication authentication, Object o, Collection<ConfigAttribute> collection) throws AccessDeniedException, InsufficientAuthenticationException {
collection.forEach(configAttribute -> {
if (!this.supports(configAttribute))
throw new AccessDeniedException("ACCESS DENIED");
});
}
#Override
public boolean supports(ConfigAttribute configAttribute) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.isAuthenticated()) {
String rolesAsString = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.joining(","));
if (configAttribute.toString().contains(rolesAsString))
return true;
else
return (configAttribute.toString().contains(PERMIT_ALL) || configAttribute.toString().contains(AUTHENTICATED));
}
return true;
}
#Override
public boolean supports(Class<?> aClass) {
return true;
}
}
Now to support this custom access-decision-manager with your security config do this in the security configuration:
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
// other configs
.accessDecisionManager(this.accessDecisionManager)
accessDecisionManager is the autowired bean of the AccessDecisionManager implementation you've created.
You can use either hasRole() or hasAuthority(). The difference is that, you have to user ROLE_ for hasAusthority() method.
So for the ROLE_ADMIN,
#PreAuthorize("hasRole('ADMIN')") == #PreAuthorize("hasAuthority('ROLE_ADMIN')")
I am new to Spring security and learnt the concepts of AuthenticationInterceptor, AuthenticationManager, UserLoginService. I know how to implement the userloginservice for checking a valid user in the system. The problem is we have two types of users 1)Specialists 2) Users and their credentials are stored in two different tables. The implementation of UserDetailsService should check both tables to authenticate and get the details of the user. Is there possibility to use multiple authentication providers and use the appropriate one based upon the type of user? or Do I have to use the same authentication provider to query both tables to find out the user validity? What is the best way to handle this scenarios when the user has to be searched in two tables?
I think you can do sth like that:
#Autowired
private UsersDAO usersDAO;
#Autowired
private OtherDAO otherDAO;
#Override
#Transactional
public UserDetails loadUserByUsername(final String username) throws UsernameNotFoundException {
Users user = usersDAO.find(username);
Other oth = otherDAO.find(username);
// your queries
if(check if your desire is correct based on user){
List<GrantedAuthority> authorities = buildUserAuthority(user.getUserRole());
return buildUserForAuthentication(user, authorities);
} else {
//...
}
}
In my applications I usually create three tables for access management. Roles, Rights and an association table that maps between Roles and Rights.
I am trying to translate this approach to Spring security and after reading [this article][1] I thought I was on the right track. I created a custom AuthenticationProvider and implemented the authenticate() method like so:
#Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UserProfile profile = userProfileService.findByEmail(authentication.getPrincipal().toString());
if(profile == null){
throw new UsernameNotFoundException(String.format("Invalid credentials", authentication.getPrincipal()));
}
String suppliedPasswordHash = DigestUtils.shaHex(authentication.getCredentials().toString());
if(!profile.getPasswordHash().equals(suppliedPasswordHash)){
throw new BadCredentialsException("Invalid credentials");
}
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(profile, null, profile.getAuthorities());
return token;
}
The profile.getAuthorities() method creates a list of Rights (rights are wrapped in my own implementation of GrantedAuthority). So, the UsernamePasswordAuthenticationToken object is created with this list. This is the UserProfile.getGrantedAuthorities() method that takes care of this:
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<ProduxAuthority> authorities = new HashSet<ProduxAuthority>();
for (Role role : roles) {
for (Right right : role.getRights()) {
ProduxAuthority produxAuthority = new ProduxAuthority(right.getName());
authorities.add(produxAuthority);
}
}
return authorities;
}
My question is whether this is a correct approach. I am getting the impression that I should stuff roles into GrantedAuthorities instead of rights, but I would like to use rights to secure methods and urls, because it gives me more fine grained control over authorization. How would I accomplish this? And what is the difference between a ROLE and a PERMISSION in Spring? Do permissions map to rights and could I use hasPermission() to secure stuff bases on rights instead of roles?
I am going to answer my own question again:
Spring doesn't know rights and permissions that are used by the hasPermission method apply only to the relatively complex Domain Object Security/ACL in Spring security. Spring's simple security knows just roles and roles or more generic "permissions" (in the general sense of the word, not to be confused with permissions in Domain Object Security/ACL) like IS_AUTHENTICATED_ANONYMOUSLY are handed to Spring in the third constructor parameter of the Authentication object's.
I summerized everything on my own website and created an example implementation that stuffs rights into roles and in that way still manages to be pretty flexible.
http://en.tekstenuitleg.net/blog/spring-security-with-roles-and-rights
I want to use Spring Security to manage user, group and permissions.
I want to use ACL to secure my domain objects but I can't find a way to assign a group to an acl.
For example:
I've got users and groups. Each group can have the following securities:
- manage forums (can be a role like ROLE_FORUM_MANAGER)
- edit a specific forum (acl on the specific forum).
Moreover, Groups are defined by users which have role ROLE_PERMISSION_MANAGER. BUT all groups defined by this user can only be edited and managed by this user. So group are attached to a user. Exactly, imagine that user creates a google group: this user can manage right permission groups only for the group he has created. And so he can create group to manage specific forum of its own google group.
How can I do it?
I read the spring security docs and the following tutorials (so please don't send me to these links):
http://grzegorzborkowski.blogspot.com/2008/10/spring-security-acl-very-basic-tutorial.html
http://blog.denksoft.com/?page_id=20
Check Spring Security 3.0, you might be able to avoid using ACL at all by using the Spring Expression Language.
For instance, for editing a forum, you would have a method secured like this:
#PreAuthorize("hasRole('ROLE_FORUM_MANAGER') and hasPermission(#forum,'update'))
public void updateForum(Forum forum) {
//some implementation
}
You would then implement the hasPermission method in a custom permission evaluator, like:
public class ForumPermissionEvaluator implements PermissionEvaluator {
public boolean hasPermission(Authentication authentication,
Object domainObject, Object permission) {
//implement
}
public boolean hasPermission(Authentication authentication,
Serializable targetId, String targetType, Object permission) {
//implement
}
}
Finally, wire it up together in the application config:
<beans:bean id="expressionHandler"
class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<beans:property name="permissionEvaluator" ref="permissionEvaluator"/>
</beans:bean>
<beans:bean id="permissionEvaluator"
class="x.y.z.ForumPermissionEvaluator" />
I would just use your Groups like Roles. I've found the Spring ACL implementation to be pretty unwieldy and for the most part unusable. Just assign users to "groups" (Roles in all actuality) and check them as you would normal role based authorization.
I did something similar 'manually': i.e. I had my own code to determine which instances could be edited/deleted by a specific user and only relied on Spring security to ensure they had the right role to access the functionality and to provide role/authentication information for the current user.
So in my code I determined the current principal (our own User class) and based on that I decided what rights this user had on a specific instance.
public static User getCurrentUser() {
User user = null;
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth != null) {
Object principal = auth.getPrincipal();
if (principal instanceof User) {
user = (User)principal;
}
}
return user;
}