in our app, we have the following:
<intercept-url pattern="/app/**" access="ROLE_ADMIN,ROLE_USER,ROLE_CUST_ADMIN" />
but, in our app, we can create custom roles too, and, when a user of a custom role, for ex, ROLE_LIMITED_USER tries login, the access is denied.
how can I secure the app without listing the roles ? or how can I make it accept a pattern ROLE_* ?
I tried the following :
<intercept-url pattern="/app/**" access="IS_AUTHENTICATED_FULLY" />
but, this is causing the session time out and user is required to login. Before the change, the user login was remembered.
Appreciate any solution
thanks
A couple things:
The roles that you are requiring to access functionality in your app should not change - think of them more as "permissions" instead of "roles". (The Spring Security default here may be a misnomer.) Then you can map sets of permissions to roles (via your own code), allowing custom roles to be created as a different bag of permissions, but the actual permissions that you are coding/checking against are static - they don't change. When a user is authenticated, the set of GrantedAuthoritys you populate in the UserDetails should be a merged collection of permissions based on the user's assigned roles.
That said, I think you can still do what you want without changing the security model by using Expression-Based Access Control. Assuming you're using the security namespace (i.e. xmlns="http://www.springframework.org/schema/security"), then you need to set use-expressions="true" on the <http> element and change your access attribute values to SpEL expressions, such as:
<http use-expressions="true">
<intercept-url pattern="/app/**" access="hasAnyRole('ROLE_ADMIN','ROLE_USER','ROLE_CUST_ADMIN')" />
<intercept-url pattern="/other1/**" access="isAuthenticated()" />
<intercept-url pattern="/other2/**" access="authentication.authorities.?[authority.startsWith('ROLE_')].size() != 0" />
</http>
Note that this code snippet has not been tested, and I'm pretty sure the 3rd intercept-url example won't work as is but should be pretty close. (It's attempting to filter the Collection<GrantedAuthority> to authorities that start with ROLE_ and make sure the filtered list isn't empty.)
My guess is that it will be easier to use the 2nd intercept-url and do any further custom checking in code, where you can get access to the current SecurityContext / Authentication / principal via:
SecurityContextHolder.getContext()
Hope this helps.
Note similar question here as well:
Spring Security Authorize Access Role with a Wildcard
Use Spring's #PreAuthorize annotations in your classes, and reference a custom permission evaluator via SpEL. Don't worry about building an expression parser, as you can simply reference a boolean method from within the annotation:
#PreAuthorize("#myCustomClass.booleanMethod(param1, param2, #passedParam) and isAuthenticated()")
myMethod(passedParam) {
//do something
}
Then, in the custom class, define the boolean method, and it can handle your roles (permissions) however you like -- including accessing a database to discover your newly added roles.
You won't be able to add new roles to the XML configuration on the fly, so if your question pertains to new role creation (which seems to be the case), you'll need something like the above to make it happen. Using SpEL and a custom boolean method gives you access to a potentially limitless set of restrictions and requirements you can add to your application.
Related
We've an application which performs form login with spring security. But now we wanted to authenticate user from the query string as well. I tried with custom filter but it didn't solve the purpose. Can anyone please help me in solving the problem?
Authentication via GET is disabled in spring security for, well, security reasons. GET-requests (and their parameters) make their way into log files what is a very bad thing for login credentials. They can also be cached in upstream proxies where the logging is totally out of your control. You have been warned, but if you really want to:
You can enable auth via GET by setting a property on your loginFilter. Depending on your config style (xml or javaconfig) this will be:
<bean id="loginFilter" class="org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter"
p:postOnly="false" />
or
#Bean
public UsernamePasswordAuthenticationFilter getLoginFilter() {
UsernamePasswordAuthenticationFilter loginFilter = new UsernamePasswordAuthenticationFilter();
loginFilter.setPostOnly(false);
return loginFilter;
}
Is it possible to have to have UserDetailsService implementations in a single web application ?
To be more precise, my requirement is I have a Servlet which listens to http POST requests which needs to authenticated against a one type of user(lets say UserType 1), the Http POST request contains some fields that I could used to authentication user(user id, and some Hash String). Upon successful authentication user is again forwarded to another login page where again authentication happens this time user type is UserType 2.
Here,
The UserType 1 and UserType 2 have two separate principal and credentials.
I need to Http POST request parameters to flow to session of the UserType 2( I.e. session 2).
session 2 should survive till session 1 is destroyed.
I also guess I need to have two authentication entry points as well?
My gut feeling is that this is not possible(I wish I were wrong) !
Any clarifications or ideas regarding this?
I am not sure how nested authentication may be implemented with Spring Security. But you can have two separate UserDetailsService implementations. Consider case when you have two types of URLs /** and /admin/**, and they can be used by two separate groups of users. Starting from Spring Security 3.1 you can use multiple http tags (see corresponding documentation):
<http pattern="/admin/**" authentication-manager-ref="adminAuthenticationManager">
<intercept-url pattern="/**" access="ROLE_ADMIN" />
...
</http>
<authentication-manager id="adminAuthenticationManager" >
<authentication-provider user-service-ref="adminUserDetailsService"/>
</authentication-manager>
<bean id="adminUserDetailsService" class="com.mucompany.security.AdminUserDetailsService"/>
<!-- No pattern, so everything will be matched -->
<http authentication-manager-ref="adminAuthenticationManager">
<intercept-url pattern="/**" access="ROLE_USER" />
...
</http>
<authentication-manager id="userAuthenticationManager" >
<authentication-provider user-service-ref="publicUserDetailsService"/>
</authentication-manager>
<bean id="publicUserDetailsService" class="com.mucompany.security.PublicUserDetailsService"/>
You can even declare different entry points for each http tag using entry-point-ref attribute.
I need receive two string parameters in loadUserByUsername method. I do not want to use spring security authentication, for this a have my own implementation that needs password too (It´s a integration system).
Is it possible create another method with the same name loadUserByUsername(String username, String password) in the same class, and call that method instead another one ?
I don't understand this requirement but UserDetailsService.loadUserByUsername(String) is just fine. At the time this method is invoked the user is already authenticated and hence the password is not needed anymore. So, if you need a password at that point there's a fair chance you're doing something wrong.
If you want to implement your own authentication mechanism based on username & password you need to provide your own AuthenticationProvider.
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="yourProvider" />
</security:authentication-manager>
<bean id="yourProvider" class="package.yourProviderClass">
<!-- I suppose you need this, too -->
<property name="userDetailsService" ref="yourUserDetailsService" />
</bean>
Have a look at the existing implementations and find the one that most closely offers what you need.
Is it possible at all for me to use a wildcard in the access property of the <sec:authorize /> tag.
Currently I have
<sec:authorize access="hasRole('TICKET_VIEW') or hasRole('TICKET_EDIT')">
but I would like to be able to use
<sec:authorize access="hasRole('TICKET_*')">
Is this possible or does anyone know a work-around that would accomplish the same thing?
Thanks
It's possible in Spring EL starting from Spring 3.x. The expression you're looking for is hasAnyRole(..).
So it should look like this:
<sec:authorize access="hasAnyRole('TICKET_VIEW', 'TICKET_EDIT')">
...
</sec:authorize>
Here's a link for some more Spring EL expressions:
http://static.springsource.org/spring-security/site/docs/3.0.x/reference/el-access.html
I realize that this is an old question, but this answer might help future searchers.
1) Allow Single Role from a Fixed Set: This is the simple base case.
<security:authorize access="hasRole('ROLE_ADMIN_ABC')">
You are allowed to see these admin links.
</security:authorize>
2) Allow Any Role from a Fixed Set: For cases where you want to allow "any role that starts with ADMIN", you know all of the role names in advance, and you just have a few roles, jzelenkov's answer is perfectly correct. However, if you have too many roles to deal with, you will probably want to create a custom method call that can make the access decision, and insert it into the access attribute with SpEL. This solution is closer to the wildcard question that was originally asked.
<bean id="mySecurityBean" class="com.sample.MySecurityBean" />
<security:authorize access="#mySecurityBean.roleStartsWith(principal, 'ROLE_ADMIN_')">
You are allowed to see these admin links.
</security:authorize>
public class MySecurityBean {
/**
* Returns true if any role starts with some prefix.
*/
public boolean roleStartsWith(UserDetails user, String rolePrefix) {
for (GrantedAuthority auth : user.getAuthorities()) {
if (auth.getAuthority().startsWith(rolePrefix)
return (true);
}
return (false);
}
}
3) Allow Single Role from a Dynamic Set: For cases where you want to allow "a specific role that starts with ADMIN", but you don't necessarily know all of the allowed role suffixes, you can insert the role name at render time with JSTL. As an example, consider an app with many workspaces, each with a unique code. You want to create a ROLE_ADMIN_workspaceName role for each workspace. When someone is visiting the ABC workspace page, you only want the admin links to appear if the user has the ROLE_ADMIN_ABC role. Let us assume that every workspace uses the same JSP view, and the name is passed into the model as ${workspaceName}.
<sec:authorize access="hasRole('ROLE_ADMIN_${workspaceName}')">
You are allowed to see these admin links.
</sec:authorize>
4) Allow Any Role from a Dynamic Set: This is identical to the solution for #2.
I'm using Acegi/Spring Security in grails and when i use the annotations like #Secured(['ROLE_ADMIN']) it denies my login even though the user is part of ROLE_ADMIN.
In looking through the login is it seems that it's getting an IS_AUTHENTICATED_FULLY role also but I have never added that to a page so i'm not sure how to bypass that. I read somewhere to preauthorize the user, but i'm not sure how to do that with grails.
Have you enabled annotations based authentication in the security config?
E.g.
useRequestMapDomainClass = false
useControllerAnnotations = true
Also, triple check that the role is assigned (GORM might be silently failing your save).
You could printout the authorities assigned to the user just to make sure.
E.g.
user.authorities.each {
it.authority
}