Spring security - securing method request with hasPermission - spring

The common usage is:
<intercept-url pattern="/**" access"ROLE_ADMIN" />
Is it possible to do something like:
<intercept-url pattern="/**" access"hasPermission("addSomething1") />
I haven't seen hasPermission among security expression listed under allowed:
We have only:
authentication; denyAll; hasAnyRole(list of roles); hasIpAddress; isAnonymous() etc.
I am just guessing if "hasPermission" is allowed for method security then it should be also for web-requests too.
Thanks,

Yap, it is possible. You just need to switch to expression based evaluation
 <security:http use-expressions="true">
and provide PermissionEvaluator to your expression handler:
<security:expression-hanlder ref="webSecurityExpressionHandler" />
<bean id="webSecurityExpressionHandler" class="org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler>
<property name="permissionEvaluator" ref="aclPermissionEvaluator" />
</bean>
Of course you need to have PermissionEvaluator implementation. You can write your own or you can use spring-acl project.

Pavel Horal already described how to enable expressions in the intercept-url tag (BTW. After enabled it, all access attributes must been written as SpEl expression!)
But there is one thing you need to know: the expressions that are available for the intercept-url tag differ from them that are available for method based security SpEl expressions (like #PreAuthorize). It is because the first are implemented in WebSecurityExpressoonRoot but the others are implemented in MethodSecurityExpressionRoot.
See my answer at this question stackoverflow.com/questions/8321696/… it describe how to extend the web security expression root with additional expressions.

Related

A simple pointcut expression in Spring

I'm using Spring security 3.2.0 with the same version of the Spring framework. Spring security works well in my project. In order to protect methods in my DAO classes (and others), I want to use the following pointcut approach (in the spring-security.xml file).
<global-method-security>
<protect-pointcut expression="execution(*controller.*.*(..))" access="ROLE_ADMIN"/>
</global-method-security>
I expect the pointcut expression as specified to protect all the methods in all classes inside the controller package and to be accessed only by the users who have the authority ROLE_ADMIN as specified.
But when I try to use this expression, the process terminates with following exception on saving my spring-security.xml file.
PropertyAccessException 1:
org.springframework.beans.MethodInvocationException: Property
'pointcutMap' threw exception; nested exception is
java.lang.IllegalArgumentException: Pointcut is not well-formed:
expecting 'name pattern' at character position 26
execution(controller..*(..))
^
I'm trying to follow the approach as specified by the reference document in the Adding Security Pointcuts using protect-pointcut sub-section of the 3.4.1 The <global-method-security> Element section.
What is correct expression syntax in this scenario?
EDIT:
Adding Security Pointcuts using protect-pointcut
The use of protect-pointcut is particularly powerful, as it allows you to apply security to many beans with only a simple declaration. Consider the following example:
<global-method-security>
<protect-pointcut expression="execution(* com.mycompany.*Service.*(..))" access="ROLE_USER"/>
</global-method-security>
This will protect all methods on beans declared in the application context whose classes are in the com.mycompany package and whose class names end in "Service". Only users with the ROLE_USER role will be able to invoke these methods. As with URL matching, the most specific matches must come first in the list of pointcuts, as the first matching expression will be used. Security annotations take precedence over pointcuts.
Copy & pasted the section explained in the reference document (as someone may find it to be tedious to scroll the document).
Try with this expression :
<protect-pointcut expression="execution(* your.package.controller.*.*(..))" access="ROLE_ADMIN"/>

Programmatically change property value

<beans:bean id="loginUrlAuthenticationEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/session-timeout-1.do" />
</beans:bean/>
I have 2 different session-timeout pages for different types of users. After a user logs in, the value of the property may have to change from "/session-timeout-1.do" to "/session-timeout-2.do" after checking the type of the user.
I am wondering that is there an API that can change the property value at runtime?
Or is it possible to have a variable in the config file, e.g.
<beans:property name="loginFormUrl" value="${time-out-url}">
where variable "time-out-url" can be set programmatically?
You could subclass the LoginUrlAuthenticationEntryPoint class and provide your own logic.
See the class source here:
http://git.springsource.org/spring-security/rwinchs-spring-security/blobs/2d271666a406a4409def9afcd73ea340c40a7a88/web/src/main/java/org/springframework/security/web/authentication/LoginUrlAuthenticationEntryPoint.java
Specifically the method:
determineUrlToUseForThisRequest
which "Allows subclasses to modify the login form URL that should be applicable for a given request".

Spring Security: custom userdetails

I'm pretty new to Java and Spring 3 (used primarily PHP the past 8 years). I've gotten spring security 3 to work with all the default userDetails and userDetailsService and I know I can access the logged in user's username in a controller by using:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName(); //get logged in username
But there are two problems I can't figure out:
There are a lot of other user details I would like stored when a user logs in (such as DOB, gender, etc.) and to be accessible via the controllers later on. What do I need to do so that the userDetails object that is created contains my custom fields?
I'm already calling "HttpSession session = request.getSession(true);" at the top of each of my methods in my controller. Is it possible to store the logged in user's userDetails in a session upon login so that I don't need to also call "Authentication auth = SecurityContextHolder.getContext().getAuthentication();" at the beginning of every method?
Security-applicationContext.xml:
<global-method-security secured-annotations="enabled"></global-method-security>
<http auto-config='true' access-denied-page="/access-denied.html">
<!-- NO RESTRICTIONS -->
<intercept-url pattern="/login.html" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<intercept-url pattern="/*.html" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<!-- RESTRICTED PAGES -->
<intercept-url pattern="/admin/*.html" access="ROLE_ADMIN" />
<intercept-url pattern="/member/*.html" access="ROLE_ADMIN, ROLE_STAFF" />
<form-login login-page="/login.html"
login-processing-url="/loginProcess"
authentication-failure-url="/login.html?login_error=1"
default-target-url="/member/home.html" />
<logout logout-success-url="/login.html"/>
</http>
<authentication-manager>
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource" authorities-by-username-query="SELECT U.username, UR.authority, U.userid FROM users U, userroles UR WHERE U.username=? AND U.roleid=UR.roleid LIMIT 1" />
<password-encoder hash="md5"/>
</authentication-provider>
</authentication-manager>
login.jsp:
<%# taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%# taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<%# taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<tiles:insertDefinition name="header" />
<tiles:insertDefinition name="menu" />
<tiles:insertDefinition name="prebody" />
<h1>Login</h1>
<c:if test="${not empty param.login_error}">
<font color="red"><c:out value="${SPRING_SECURITY_LAST_EXCEPTION.message}"/>.<br /><br /></font>
</c:if>
<form name="f" action="<c:url value='/loginProcess'/>" method="POST">
<table>
<tr><td>User:</td><td><input type='text' name='j_username' value='<c:if test="${not empty param.login_error}"><c:out value="${SPRING_SECURITY_LAST_USERNAME}"/></c:if>' /></td></tr>
<tr><td>Password:</td><td><input type='password' name='j_password' /></td></tr>
<tr><td> </td><td><input type="checkbox" name="_spring_security_remember_me" /> Remember Me</td></tr>
<tr><td> </td><td><input name="submit" type="submit" value="Login" /></td></tr>
</table>
</form>
<tiles:insertDefinition name="postbody" />
<tiles:insertDefinition name="footer" />
There's an awful lot going on in this question. I'll try to address it in pieces...
Q#1: There are a couple possible approaches here.
Approach #1: If you have other attributes that you want to add to your UserDetails object, then you should provide your own alternate implementation of the UserDetails interface that includes those attributes along with corresponding getters and setters. This would require that you also provide your own alternate implementation of the UserDetailsService interface. This component would have to understand how to persist these additional attributes to the underlying datastore, or when reading from that datastore, would have to understand how to populate those additional attributes. You'd wire all of this up like so:
<beans:bean id="userDetailsService" class="com.example.MyCustomeUserDetailsService">
<!-- ... -->
</beans:bean>
<authentication-manager alias="authenticationManager">
<authentication-provider ref="authenticationProvider"/>
</authentication-manager>
<beans:bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>
Approache #2: Like me, you may find (especially over the span of several iterations) that you're better served to keep domain-specific user/account details separate from Spring Security specific user/account details. This may or may not be the case for you. But if you can find any wisdom in this approach, then you'd stick with the setup you have currently and add an additional User/Account domain object, corresponding repository/DAO, etc. If you want to retrieve the domain-specific user/account, you can do so as follows:
User user = userDao.getByUsername(SecurityContextHolder.getContext().getAuthentication().getName());
Q#2: Spring Security automatically stores the UserDetails in the session (unless you've explicitly taken steps to override that behavior). So there's no need for you to do this yourself in each of your controller methods. The SecurityContextHolder object you've been dealing with is actually populated (by SS) with SecurityContext including the Authentication object, UserDetails, etc. at the beginning of every request. This context is cleared at the end of each request, but the data always remains in the session.
It's worth noting, however, that it's not really a great practice to be dealing with HttpServletRequest, HttpSession objects, etc. in a Spring MVC controller if you can avoid it. Spring almost always offers cleaner, more idiomatic means of achieving things without the need for doing so. The advantage to that would be that controller method signatures and logic cease to be dependent on things that are difficult to mock in a unit test (e.g. the HttpSession) and instead of dependent on your own domain objects (or stubs/mocks of those domain objects). This drastically increases the testability of your controllers... and thus increases the liklihood that you actually WILL test your controllers. :)
Hope this helps some.
In my opinion, Custom UserDetails implementation is great but should only be used for immutable characteristics of your user.
Once your custom User object overrides UserDetails, it's not easily changed. You have to create a whole new authentication object with the modified details and cannot just stick the modified UserDetails object back into the security context.
In application that I'm building I've realized this and had to rearchitect it so that upon successful authentication details about the user that are changing with every request (but that I don't want to reload from the db on every page load) are going to need to be kept in the session separately, but still only accessible/changeable after an authentication check.
Trying to figure out if this WebArgumentResolver mentioned in https://stackoverflow.com/a/8769670/1411545 is a better solution for my situation.
Accessing the session directly is a bit messy, and can be error prone. For example, if the user is authenticated using remember-me or some other mechanism which doesn't involve a redirect, the session won't be populated until after that request completes.
I would use a custom accessor interface to wrap the calls to the SecurityContextHolder. See my answer to this related question.

Make a check on AOP pointcut expression

I need to make a check in my pointcut expression like.
I have this bean:
<bean id="logConfig"
class="com.celfocus.ufe.base.logging.domains.LoggingConfiguration">
<property name="logDetails" value="STANDARD" />
<property name="logLvl" value="COMPLETE" />
</bean>
In my aop pointcut expression i need to make a check to verify the value of bean property "logLvl".
<aop:config>
<aop:aspect ref="ufeLogger">
<aop:pointcut id="complete" expression="execution(* *.*(..)) and bean(logConfig)==COMPLETE" />
<aop:before pointcut-ref="complete" method="logBefore" />
</aop:aspect>
</aop:config>
My expression isn't working... what I can change to make this check?
What makes you think that and bean(logConfig)==COMPLETE is a valid pointcut? Spring AOP uses AspectJ pointcut syntax, no Spring additions. Also you are not even referencing logLvl property, so has is this suppose to work?
Unfortunately to achieve this you must implement check manually. This isn't so intrusive though: simply inject logConfig into ufeLogger aspect and add a simple condition in logBefore() method.
This is the most relevant question, for solution below. I write aspect expressions from time to time. And expression might not work. You need to write right expression, which will be matched with your target method. I found a simple decision to check that everything is clear:
#Around(value="execution(* *.find(..))")
public Entity filterEntity(ProceedingJoinPoint pjp) throws Throwable {
Entity entity = (Entity) pjp.proceed(); // put breakpoint here
}
In Debug mode you can check target method real signature that is used for match with expression, in path pjp.methodInvocation.method
I hope this answer will save your time to find an error.
P.S If there are exists better decision to check expressions, glad to see it

How can I mix and match custom Spring schema types with traditional Spring schema types?

Let's say I have a class Person with properties name and age, and it can be configured with Spring like so:
<beans:bean id="person" class="com.mycompany.Person">
<beans:property name="name" value="Mike"/>
<beans:property name="age" value="38"/>
</beans:bean>
I'd like to have a custom Spring schema element for it, which is easy to do, allowing me to have this in my Spring configuration file:
<Person name="Mike" age="38"/>
The schema definition would look something like this:
<xsd:complexType name="Person">
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="name" type="xsd:string"/>
<xsd:attribute name="age" type="xsd:int"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
Based on this, let's now say I would like the option of mixing and matching my custom schema element with traditional elements and attributes of Spring beans, so I could have the option of doing this:
<Person name="Mike">
<beans:property name="age" value="38"/>
</Person>
How would I go about doing that? Perhaps this is impossible without some major customization, but I'm hoping there is some fairly simple mechanism to achieve this. I thought extending "bean" might be the trick, but that doesn't look to be correct.
First of, if your example is really all you want to do, consider using p-namespace instead and save yourself some major headache:
<beans:bean id="person" class="com.mycompany.Person" p:name="Mike" p:age="38"/>
Yes, it doesn't look as pretty as <Person name= age= /> but there's no custom code to write :-)
If that does not satisfy your requirements, you're looking at implementing your own namespace / bean definition parser. Spring documentation has a chapter dedicated to that which will explain it better then I can. If you hit any issues, please post back specific questions and I'll try to help.

Resources