I am simply trying to allow a user access to a method if they are authenticated, but nothing I am doing seems to work. Is there a way to just check if the user has been authenticated? The following still denies the user even when authenticated... Is there a built in role for an authenticated user?
#RequestMapping("/secure")
#PreAuthorize("hasRole('IS_AUTHENTICATED_FULLY')")
public String secure(ModelMap map){
return("secure");
}
IS_AUTHENTICATED_FULLY is not a role - it is a pre-defined credential (aka 'magic' string) recognized by the AuthenticatedVoter to indicate that you have logged in. This voter also supports anonymous and remember-me login.
Roles are processed by the RoleVoter which recognizes any sting starting with "ROLE_" (prefix is configurable). Thus hasRole('IS_AUTHENTICATED_FULLY') doesn't work because it's not a role. #RolesAllowed("IS_AUTHENTICATED_FULLY") wouldn't work for the same reason.
When using Spring expression language, the correct expression is:
#PreAuthorize("isAuthenticated()")
Alternatively, you can use:
#Secured("IS_AUTHENTICATED_FULLY")
No custom classes are required - both voters are enabled by default.
hasRole('ROLE_USER') is the traditional name for any user who is authenticated. You would typically use ROLE_ANONYMOUS for parts where you don't care if the person is authenticated or not.
(Added later:)
I think you will need to implement a custom AccessDecisionVoter that will always vote ACCESS_GRANTED whenever the parameter authentication has isAuthenticated() true, and the CONFIG_ATTRIBUTE is ROLE_USER or similar.
There is further discussion of this in this forum discussion, giving details of a web.xml and other config.
In your custom UserDetailService implementation just add the Role "IS_AUTHENTICATED_FULLY" to the User object before it's returned.
This is what I have ended up using:
#PreAuthorize("isAuthenticated()")
this should work:
#PreAuthorize("isFullyAuthenticated()")
Related
In spring security, or RBAC, the Authority is described as a string, such as "download-file" means user can download file. If I need to limit user maximum daily download times and assign different values to different user, means the Authority contains dynamic values, how can I do this in spring security?
As you are alluding to there is a difference between authorities (i.e. roles) and permissions. Authorities tend to broadly apply for an application and have no state while permissions tend to be on specific objects and contain state.
This seems more like a domain problem than a permissions problem. Putting the logic into security feels a bit like having a form that must contain a valid email and checking the email format in security. I'd consider moving the logic outside of the security code.
If you really want to do this with Spring Security, I'd use a custom Bean that performs the check:
#Component
public class Download {
public boolean isAlowedForUser(Authentication authentication) {
// ...
return result;
}
public boolean isAllowedForCurrentUser() {
return isAllowedForUser(SecurityContextHolder.getContext().getAuthentiation());
}
}
Then you can autowire the Bean into your code and check the permission by invoking the code. If you prefer, you can also integrate into Spring Security's method security to perform the checks. To enable it you need to specify #EnableGlobalMethodSecurity(prePostEnabled = true) at the top of one of your configuration classes. Then you can use something like this on a Spring managed Bean:
#PreAuthorize("#download.isAllowedForCurrentUser()")
public void downloadFile(String fileName) {
Please refer this link
Spring Boot : Custom Role - Permission Authorization using SpEL
You can add new permission , like "DOWNLOAD_FILE" and authenticate if the current user has that permission using -
#PreAuthorize("hasPermission('DOWNLOAD_FILE')")
You can also limit access for Roles as well
#PreAuthorize("hasRole('ADMIN') and hasPermission('DOWNLOAD_FILE')")
I couldn't understand a concept when using ZfcRbac.
1. I use my own User entity with implementing ZfcRbac\Identity\IdentityInterface
2. This interface has addRole and getRoles methods and getRoles() should return array of Rbac\Role\RoleInterface so I have an array of Rbac\Role\RoleInterface
3. I get roles from my custom model and add roles to User entity via addRole() when authenticating the user
4. Rbac\Role\RoleInterface has hasPermission() method which returns role's permissions
Summary:
After authentication I have my authenticated User identity information, roles and permissions for per role. Why I need another RoleProvider and list my all roles in it? What am i missing?
As you can see in the php doc in the IdentityInterface The getRoles() method can return two things:
1. an array of strings
2. an array of Rbac\Role\RoleInterface
In case you return an array of strings you need an additional RoleProvider to "translate" the strings to actual instances of a Rbac\Role\RoleInterface. If you return an array of Rbac\Role\RoleInterface it seems to me that you do not longer need a RoleProvider.
It seems to me that Role Providers are not for generating a user role list, but rather to the load and build an accessible listing of application roles with permissions to be used during and in the authorization service.
So I am extending the Zend\Authentication\AuthenticationService so I can implement the abstract method getRoles() of the ZfcRbac\Identity\IdentityInterface.
I still need to code for the accessing of user roles and storage of user roles to be authorized. There are not many examples of loading user roles using the AuthenticationService or IdentityInterface, and the loading of the role provider seems well documented. I am trying to decouple Authentication from Authorization. I Authenticate and then I load the user's role in my Authorization module because I may have cases where authentication is all that is necessary and the loading of a guest role is overhead.
In my application I have a top level entity called Organization. The relationship between User and Organization is many-to-many.
Because of this I could have the following scenario:
UserA has role ROLE_ADMIN for OrganizationA
UserA has role ROLE_USER for OrganizationB
I need to ensure that when UserA accesses resources for OrganizationB he is not doing it as an ADMIN. So I need an additional check that the user has the correct roles at the organization level. Is there anything built into Spring Security that allows for this? If not, does anyone know what the best way would be to about solving this?
UPDATE: A bit more information...
A User logs in and chooses which org they want to work with. That is stored in the session. Beyond that, URLs are locked down with the Secured annotation. What that means is that if UserA were to log in and select OrgA, they should be able to access /admin/user/create however, if they log in and choose OrgB they should not have access to that URL.
The long way is to add additional checks in every method where this matters. So call some service method that says "ok, you're an admin for OrgA but not for OrgB and you're logged in using OrgB, so deny this request".
I'm hoping for a more grails / spring-security way of handling this.
You can probably do this by using a custom AccessDecisionVoter. The vote method will supply you with the "configuration attributes" for the resource (method or URL), which will typically be the required roles, and you can obtain the current user's roles/authorities either directly from the Authentication object, or by reading the current org and selecting the appropriate roles for the user.
I'm assuming that you have some way of differentiating the user's roles, based on the org they've selected.
Essentially, you'd be writing an extended version of the standard RoleVoter, which takes the organization into account.
I think I'm little late here but this is what worked for me:
When an organization is selected, you can set a new Authentication object with new roles in your session(The previous Authentication object gets invalidated). Something like this:
#RequestMapping(value = "/org-a")
String orgA(HttpServletRequest request) {
request.getSession().setAttribute("org", "org-a")
Organization org = new Organization("org-a")
reloadRolesForAuthenticatedUser(org)
....
}
private void reloadRolesForAuthenticatedUser(Organization org) {
Authentication auth = SecurityContextHolder.getContext().getAuthentication()
List<String> newRoles = getRoles(auth.getPrincipal().getUsername(), org)
List<GrantedAuthority> authorities = getAuthorities(newRoles)
Authentication newAuth = new UsernamePasswordAuthenticationToken(auth.getPrincipal(),auth.getCredentials(),authorities)
SecurityContextHolder.getContext().setAuthentication(newAuth)
}
private List<GrantedAuthority> getAuthorities(List<String> roles) {
List<GrantedAuthority> auths = new ArrayList<GrantedAuthority>()
if (!roles.isEmpty()) {
for (String r : roles) {
auths.add(new SimpleGrantedAuthority(r))
}
}
return auths
}
User's authority is frequently changed in my web service.
In this case, how do I check user's authority effectively?
I wrote code that check user's authority in every controller temporarily.
But I think this way would not good for maintenance.
How do I check user's authority without writing checking method in every controller?
Not sure what you are doing - Spring Security automatically keeps track of authorities in the User's security context. If you need to programmatically check for some other reason, then implement the HandlerInterceptor interface, and in the preHandle method, call SecurityContextHolder.getContext().getAuthentication() to get the current user. You can then check the User's authorities.
The interceptor would be configured as follows:
<mvc:interceptors>
<bean class="com.my.package.MyInterceptor" />
</mvc:interceptors>
Add an intercept-url element to your config with the role that is required, eg.
<http auto-config='true'>
<intercept-url pattern="/**" access="ROLE_FOO" />
</http>
Use HandlerMethodArgumentResolver to let Spring inject GrantedAuthority in the controller method. If a user can have more than one authority then you will need to create a class to hold user's authorities (can be named as GrantedAuthorities). After you are done, your controller method will look something like this:
#RequestMapping({"/xyz"})
public String handleXYZRequest(GrantedAuthorities authorities) {
/* use authorities if not null */
...
}
In resolver, you will use the same code that your are currently using to get authorities and it will return either null or GrantedAuthorities object. If you are using older version of Spring then use WebArgumentResolver and register it with AnnotationMethodHandlerAdapter.
Above approach avoids duplication of code and it can be used to inject anything you need from SecurityContextHolder in controller methods.
Edit
This is similar to the approach used by greenhouse. Please see WebConfig, where principal (which is Account object) is injected in controller through argument resolver.
Hi im trying to make facebook's login in a grails app, the problem I have is that when the user is logged in facebook, spring security core doesn't recognize him, how can I set the user's principal manually?
I can look for the user object but i don't know how to set it in order to get a true user when i call getAuthenticatedUser() (now it returns a null object)
Thanks in advance,
Regards
Cannot say anything regarding facebook, but Spring Security has a SecurityContextHolder that can be used to manipulate the authentication (and therefore the principal) like this:
import org.springframework.security.core.context.SecurityContextHolder as SCH
import org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken
....
def securityContext = SCH.context
def principal = <whatever you use as principal>
def credentials = <...>
securityContext.authentication = new PreAuthenticatedAuthenticationToken(principal, credentials)
Maybe you'll need to use a different implementation of the Authentication interface as the one used in the example.