RSS Feed!

Recent Posts

Recent Comments

Archive for the ‘Spring’ Category

Applying Acegi Security (SpringSecurity) to an existing JavaEE ap

Friday, April 11th, 2008

So I have a JavaEE application and I have to make sure that I use Acegi (called Spring Security or SS from here on) properly. I will try to go through all the steps that are required to implement SS in an existing Spring based application. I will not delve into the details of putting together a Spring Framework based application and I will not provide in-depth details of the implementation.

First of all here are the assumptions:
1. You understand what the differences between Authentication and Authorisation are.
2. You know what Form, Basic, Digest, LDAP Authentication mean.
3. You know what Annotations are and you are not in the mood to argue XML configurations vs. Annotations
4. I am not responsible if the information you found here has not solved your problem ;)

So let’s just say that there is no security in place and we need to plug SS in.


1. Adding Spring Security to the project

- copy the acegi-security-xxx.jar to your lib folder (this depends on how you have configured your project) or just include it in your build path.

- create a new xml file (i will call it ss.xml) where to put all the configuration information or copy one from the SS distribution

– import this file in your spring configuration xml (or point to it in your web.xml where you configure the contextConfigLocation)

– in the web.xml configure the Acegi Filter Chain Proxy. Then make sure the FilterToBeanProxy’s class points to the org.acegisecurity.util.FilterChainProxy (should you use FilterToBean you’ll end up writing lots and lots of xml to define the filters, but it’s your choice).

– while in the web.xml define a filter-mapping for the URIs that you want to secure. How about /* ?


All done with the web.xml You should have something like this:

[...]

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/spring-core.xml, /WEB-INF/classes/ss.xml</param-value>
</context-param>

<filter>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
<init-param>
<param-name>targetClass</param-name>
<param-value>org.acegisecurity.util.FilterChainProxy</param-value>
</init-param>
</filter>

<filter-mapping>
<filter-name>Acegi Filter Chain Proxy</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

[...]


– move to the ss.xml file that i pointed to above and configure the filter. I will have different filters for web services and for the rest of the application. The order is very important so make sure you put the more specific rules first. I will also put some stuff in /notsecured that will just not be protected.

    <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy">
<property name="filterInvocationDefinitionSource">
<value>
CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
PATTERN_TYPE_APACHE_ANT
/webServices/**=httpSessionContextIntegrationFilterWithASCFalse,basicProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
/notsecured/**=#NONE#
/**=httpSessionContextIntegrationFilter,authenticationProcessingFilter,exceptionTranslationFilter,filterInvocationInterceptor
</value>
</property>
</bean>

Just a few comments on what we have above: the authenticationProcessingFilter could be used to audit the logon attempts as it provides onSuccessfuAuthentication and onUnsuccessfulAuthentication methods. The exceptionTranslationFilter is responsible for detecting security exceptions thrown by the AbstractSecurityInterceptor.The filterInvocationInterceptor is needed to check web URIs.


- now it’s time to configure the authenticationProcessingFilter. Here is what it should end up looking like:

<bean id=”authenticationProcessingFilter” class=”class.that.implements.AuthenticationProcessingFilter”>
<property name=”authenticationManager”>

<ref bean=”authenticationManager”/>

</property>
<property name=”authenticationFailureUrl”>

<value>/logon.jsp?tryagain=true</value>

</property>
<property name=”filterProcessesUrl”>

<value>/j_acegi_security_check</value>

</property>
<property name=”defaultTargetUrl”>

<value>/admin/home.html</value>

</property>
<property name=”alwaysUseDefaultTargetUrl”>

<value>true</value>

</property>
</bean>


So let’s look at the properties, one at a time.


First the class that implements the processing filter can be any the AuthenticationProcessingFilter itself or your own class that extends it. You would extend it to be able to do stuff when something goes wrong for example.

The authenticationManager is responsible with delegating to its list of AuthenticationPr
oviders
to check an Authentication request. It can also be configured with a ConcurrentSessionController that manages how many session one user can have at a time.

The authenticationFailureUrl points to where the user will be redirected to in the event of an authentication failure. The request parameter tryagain is there to let you do some processing in the logon page.

The filterProcessesUrl is represents the URL that this filter responds to. In this example you can see the default value.

The defaultTargetUrl points to the URL that follows a successful authentication (unless the HttpSession attribute called ACEGI_SAVED_REQUEST_KEY points to somewhere else). Fully qualified URLs can be used too.

The alwaysUseDefaultTargetUrl just overrides the ACEGI_SAVED_REQUEST_KEY. Event if this key exists the redirect will still be made to the default target URL.


- it’s now time to configure the AuthenticationProvider (used by the authenticationManager above).


There are quite a few options here: DAO Authentication Provider, JAAS, Run-As, Form, Basic, Digest, Remember Me, LDAP, X509, CAS, Container Adapter, etc. I will only talk about the DAO Authentication Provider here. An authentication provider is basically a class that can process a specific Authentication implementation. The provider will use a a userDetailsService to retrieve the UserDetails object via the loadUserByUsername(String username) call.

The official documentations says: “The returned UserDetails is an interface that provides getters that guarantee non-null provision of basic authentication information such as the username, password, granted authorities and whether the user is enabled or disabled“. So basically the UserDetails object is what you all you need ;)

You need not do anything to this DAOAuthenticationProvider unless you have specific needs. let’s have a look at how the configuration looks like:


[...]

<bean id=”daoAuthenticationProvider” class=”org.acegisecurity.providers.dao.DaoAuthenticationProvider”>
<property name=”userDetailsService”><ref bean=”jdbcDaoService”/></property>
<property name=”saltSource”><ref bean=”saltSource”/></property>
<property name=”passwordEncoder”><ref bean=”passwordEncoder”/></property>
</bean>

[...]


The userDetailsService points to a bean that is configured to retireve user details from a database. A default database structure is available but you can override the usersByUsernameQuery and the authoritiesByUsernameQuery if you need to. Typically this should be enough:

[...]

<bean id=”jdbcDaoImpl” class=”org.acegisecurity.userdetails.jdbc.JdbcDaoImpl”>

<property name=”dataSource”>

<ref bean=”dataSource”/>

</property>

</bean>

[...]

I will not explain how to configure a dataSource here.


The saltSource is just some salt that you can add to the passwords, while the passwordEncoder (e.g. Md5PasswordEncoder) is used to encode and decode the passwords in the UserDetails object returned by the UserDetailsService.


2. The logon.jsp

When a resource that is protected is accessed, the exceptionTranslationFilter will use the authenticationEntryPoint to load the logon form (assuming that is how we configured it). So in the ss.xml there should be something like this:

[...]

<bean id=”exceptionTranslationFilter” class=”org.acegisecurity.ui.ExceptionTranslationFilter”>
<property name=”authenticationEntryPoint”><ref local=”authenticationFilterEntryPoint”/></property>
</bean>

<bean id=”authenticationFilterEntryPoint” class=”org.acegisecurity.ui.webapp.AuthenticationProcessingFilterEntryPoint”>
<property name=”loginFormUrl”>
<value>/logon.jsp</value>
</property>
<property name=”forceHttps”>
<value>false</value>
</property>
</bean>

[...]


Now these beans look quite obvious. Let me know if you want more details on this.


The logon.jsp page itself will be built around the form. Here is a simplistic approach:

<form action=”j_acegi_security_check” method=”POST”>

<input type=”text” id=”j_username” name=”j_username”>

<br />

<input type=”password” name=”j_password”>

<br />

<input type=”submit” class=”button” value=”Logon”/>

</form>


When the form is submitted, Spring Securit
y will intercept and process it.



3. Controlling the JSP output

This is where the authorization tag libraries come into play. SS’s (lol) authorization tag lib is called authz and you can find it in the >../acegi-security-x.x.x.jar/META-INF/authz.tld
The AuthorizeTag declares three attributes: ifNotGranted, ifAllGranted, ifAnyGranted. This is also the order in which they are verified. With any of the tags you can specifiy a list of comma separated ROLEs (the whitespaces are ignored). Here’s an example taken from Ben Alex’s guide:
<authz:authorize ifAllGranted=”ROLE_SUPERVISOR”>
<td>
<A HREF=”del.htm?id=<c:out value=”${contact.id}”/>”>Del</A>
</td>
</authz:authorize>Basically, if the principal (remember the UserDetails ?) doesn’t have the ROLE_SUPERVISOR then the user won’t even see the Del anchor. So, with the ifAllGranted all roles must be granted to this principal, with ifAnyGranted at least one role must be granted while with the ifNotGranted none of the roles should be granted in order to output the code enclosed by this auth:authorize tag.

I will only mention that SS also provides support for Access Control Lists via authz:accesscontrollist. Please see the official documentation for more details.


4. Secure Object Implementations

Securing the front end is not always (okay never) enough. The better way of making sure that the business objects are not available to un-authenticated users. To protect them SS uses something called MethodSecurityInterceptor.

<bean id=”bankManagerSecurity” class=”org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor”>

<property name=”validateConfigAttributes”>

<value>true</value>

</property>

<property name=”authenticationManager”>

<ref bean=”authenticationManager”/>

</property>

<property name=”accessDecisionManager”>

<ref bean=”accessDecisionManager”/>

</property>

<property name=”runAsManager”>

<ref bean=”runAsManager”/>

</property>

<property name=”objectDefinitionSource”>

<value>

org.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER

org.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER

</value>

</property>

</bean>



The important thing to look at in this example is the objectDefinitionSource. There are three ways to define with method invocations will be intercepted and checked.

1. Using a property editor

2. Using Jakarta Commons Attributes (you know, the @@SecurityConfig(“”ROLE_DUMB”) syntax…)

3. Using Java Annotations (where you will make full use of the @Secured annotation).


Here is the example from the official documentation for using java 5 style annotations:


<bean id=”attributes” class=”org.acegisecurity.annotation.SecurityAnnotationAttributes”/>

<bean id=”objectDefinitionSource” class=”org.acegisecurity.intercept.method.MethodDefinitionAttributes”>

<property name=”attributes”>

<ref local=”attributes”/>

</property>

</bean>

<bean id=”bankManagerSecurity” class=”org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor”>

<property name=”validateConfigAttributes”>

<value>false</value>

</property>

<property name=”authenticationManager”>

<ref bean=”authenticationManager”/>

</property>

<property name=”accessDecisionManager”>

<ref bean=”accessDecisionManager”/>

</property>

<property name=”runAsManager”>

<ref bean=”runAsManager”/>

</property>

<property name=”objectDefinitionSource”>

<ref bean=”objectDefinitionSource”/>

</property>

</bean>


    import org.acegisecurity.annotation.Secured;

public interface BankManager {

/**
* Delete something
*/
@Secured({"ROLE_SUPERVISOR","RUN_AS_SERVER" })
public void deleteSomething(int id);

/**
* Delete another
*/
@Secured({"ROLE_SUPERVISOR","RUN_AS_SERVER" })
public void deleteAnother(int id);
}


Please note that when using BeanNameAutoProxyCreator to create the required proxy for security, the configuration must contain the property proxyTargetClass set to true. Otherwise, the method passed to MethodSecurityInterceptor.invoke is the proxy's caller, not the proxy's target.


If you want to hear the whole story, make sure you visit Acegi Security Guide. Ben Alex has done a great job documenting this framework, the API's are not too bad either, with just a few DOCUMENT ME exceptions :)

Cheers…

Spring Certification

Thursday, January 24th, 2008

Today I attended a presentation on Spring Certification. Woke up at 5:50 am so don't be surprised if I forgot something!

So if you are interested in getting a Spring Certification (from SpringSource the former Interface 21) here is what you need to know:

The SFPC (Spring Framework Professional Certificate):
- consists of 50 non-weighted multiple choice questions
- covers 10 topic areas
- lasts 88 minutes
- you pass if you score over 75%
- you'll get the result and the hardcopy on the spot at the test centre and a softcopy of result via email

Costs:
- free for those who attended Spring Courses until January 1st 2008
- free for grandfathered candidates (successful Spring product solution completed before January 1st 2008 or have added value to the Spring Community before January 1st 2008 )
- USD150 or Eur125 for everyone else

Don't fail or you'll be locked out for 30 days :)

Throughout the year 2008, SpringSource will also be offering the following certifications:

  • SpringSource Web Professional (S2WP)
  • SpringSource AOP Professional (S2AP)
  • SpringSource Integration Professional (S2IP)
  • SpringSource Management and Monitoring Professional (S2MP)

Useful links:
www.pearsonvue.com/SpringSource
www.springsource.com/certification
email: certifications at springsource .com

Good luck!