Spring Finance > Part 6: Spring Security 3.0 Integration

Now that Spring Security 3.0.0.M1 has been released it’s time for me to continue with the Spring Finance Manager sample application series. This article demonstrates how to use Spring Security to protect the sample application in it’s different layers. Furthermore, this article illustrates how to use the new expression language (EL) features introduced in this first milestone release of Spring Security 3.

The new version of the Spring Finance Manager Application which includes the Spring Security 3.0 integration is now available at the project’s Google code site.

Dependencies

The first step is to install Spring Security into the Spring Finance Manager sample application. Since my samples involve different layers I will need to make the following dependencies available in the classpath:

  • Spring Security core
  • Spring Security config
  • Spring Security taglibs

Note, that the packaging structure has changed in this new milestone release in Spring Security to allow a more modular approach where the user would typically install only the modules required for his specific application. While Spring Security core contains all necessary artefacts to secure your application you would typically want to use the config module to allow for the convenient configuration of Spring Security in the Spring container. The third module I have installed is rather optional as you do not necessarily need to use the Spring Security tag libraries in your JSPs as the JSP EL offers you access to all necessary information already. If you take a look at menu.jsp you can see that I have shown both approaches; pure JSP EL to access the user principal as well as Spring Security-specific tag libraries.

Application Context

The second step for the installation of Spring Security in the Finance Manager sample application is the creation of the configuration file. I have created the FinanceManager-security.xml configuration file which uses the Spring Security namespace as default. More about the configuration details later. The third step is the integration of the Spring Security org.springframework.web.filter.DelegatingFilterProxy filter which is integrated into the web.xml. This filter is required if you use the http element in your Spring Security configuration. Finally, I have created a login.jsp page which allows for form-based login.

I have decided to secure the Spring Finance Manager application mostly through the service layer which functions as a facade to the repository and is used used as a transaction boundary already. Furthermore it is used directly by MVC controllers as well as any other remoting mechanisms I may integrate later on. There are several options to integrate Spring Security in the service layer of your application. You can use aspects to intercept calls to methods exposed by the services layer (which is what Spring Security does internally even if you are using other mechanisms), you can use the JSR 250 annotations. You can also use Spring Security’s @Secured annotation which is still supported but it is superseded by the new @PreAuthorize annotation introduced in Spring Security 3. The latter offers integration convenient integration between the new Spring EL features and Spring Security. The new EL features make it much easier to fine-tune your interceptors to secure your methods or classes or even create filters for return values.

So let’s take a look at the FinanceManager-security.xml configuration:

<global-method-security pre-post-annotations="enabled" />

<http use-expressions="true">
     <intercept-url pattern="/**" access="permitAll" />
     <form-login login-processing-url="/j_spring_security_check" login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=t"/>
     <logout logout-url="/j_spring_security_logout" logout-success-url="/"/>
</http>

<authentication-provider>
     <jdbc-user-service data-source-ref="dataSource"
	    users-by-username-query="select email as username, password, true from person where email = ?"/>
</authentication-provider>

<beans:bean id="adminUser" class="net.stsmedia.financemanager.domain.Person">
[…]
</beans:bean>

As you can see, the security configuration is positively lean. It instructs Spring Security to scan for its @PreAuthorize and @PostAuthorize annotations (the component-scan element is already supplied in the parent configuration). Then we use the http element of the Spring Secuirty namespace to define form-login details such as the name and location of the custom login.jsp page (it will even provide this form if you don’t supply it). You can also configure interceptors to secure you application by protecting certain URL patterns. This is certainly the easiest way to secure your application in case it is a pure Web based application.

Finally, I use an authentication-provider element to configure Spring Security to use the existing data source to retrieve all information required for authentication and authorization. I use a custom query as I am reusing the person table to retrieve usernames (in my case those are the email addresses) and passwords instead of installing a separate table for security information. Further, the security context contains a default user (super admin) which is used to login and create some initial data. Typically such user detail would already exist in the database and therefore this configuration is merely used to bootstrap the Spring Finance Manager application which builds the in-memory database upon initial deployment. The insertion of this first user is handled by the SeedAdminData class. The final release of Spring 3 will contain new support for in-memory databases which makes such configurations even easier.

Web context configuration

This installation step is rather optional and depends on the nature of your application. If your application has a Web front-end (like most applications do) then you need to integrate the Spring Security filter chain into the web.xml file:

<filter>
     <filter-name>springSecurityFilterChain</filter-name>
     <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
[…]
<filter-mapping>
     <filter-name>springSecurityFilterChain</filter-name>
     <url-pattern>/*</url-pattern>
</filter-mapping>

Annotation Configuration

Finally, we can use the new Spring Security @PreAuthorize and @PostFilter annotations to secure and filter the service layer of the Spring Finance Manager sample application:

@PreAuthorize("hasRole('ROLE_ADMIN') or hasRole('ROLE_USER')")
public interface AccountService {

	@PostFilter("filterObject.owners.email == principal.username or hasRole('ROLE_ADMIN')")
	List<Account> findAll();

	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@Transactional
	void persist(Account entity);

	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@Transactional
	void merge(Account entity);

	@PreAuthorize("hasRole('ROLE_ADMIN')")
	@Transactional
	void remove(Account entity);

	Account find(Long id);
}

As you can see the new EL integration with these annotation save you a lot of custom code that was required previously. For example, the new EL features should remove the need for many custom access decision voters that were needed previously. The filter seen on the findAll() method ensures that only the admin can actually see all accounts in the database whereas the authenticated user can only see accounts that match his user credentials (email in our case) . This filter is applied after (post) the collection is returned from the repository and then the collection is reduced as per constraint expressed in the expression.

Securing Spring Web Flow

The new release of Spring Security 3.0 is not yet integrated into the current release of Spring Web Flow yet. For this reason I have not secured the wizard flow yet. However, the necessary configurations are already included in the FinanceManager-webflow.xml file:

	<webflow:flow-executor id="flowExecutor" flow-registry="flowRegistry">
    	<webflow:flow-execution-listeners>
        	<webflow:listener ref="securityFlowExecutionListener" />
    	</webflow:flow-execution-listeners>
	</webflow:flow-executor>

[...]

	<bean id="securityFlowExecutionListener" class="org.springframework.webflow.security.SecurityFlowExecutionListener" />

As you can see all you need to do is to create an instance of Spring Web Flow’s SecurityFlowExecutionListener and register this listener with the flow executor.

Now, in order to secure parts or all of your flows you simply insert secured elements into your flow definitions:

<flow [...]>
   <secured attributes="ROLE_ADMIN"/>

   <persistence-context />

   <view-state id="createNewPerson" model="person">
      <secured attributes="ROLE_ADMIN"/>
      [...]
   </view-state>
</flow>

I am planning to update the Spring Finance Manager application once a new Spring Web Flow release which is compatible with Spring Security 3.0 is made public.

Other changes

I added a password field to the person domain object so that this table can double as user table for Spring Security. As noted above this required a custom query in the security configuration. More commonly you would use a dedicated user table to achieve this. The schema for this is provided in the official Spring Security documentation.

Furthermore, I have introduced a new JPA managed authorities table which caters for the mapping between users and their authorities. This table is currently not exposed to the view layer for management by the admin but this could be done easily when required.

To try out the new features you can deploy the new version of the Spring Finance Manager sample application, login with super admin rights where the email for the super admin is super@admin.com and the password is admin. There you can see that the super admin has all rights in the application to create new products, persons and accounts.

After populating a few resources like this, you can log out as super admin and log back in with the credentials of one of the persons you have just created. This will give you access to a limited back-end which allows the user to only see his own account and update his own data accordingly.

Conclusion

In this article I showed how to configure and integrate Spring Security in Spring applications. I have put special attention to the new expression language features introduced with the first milestone release of Spring Security 3.0.

  • Share/Bookmark

18 Responses Subscribe to comments


  1. Kumar

    Hi

    I downloaded FinanceManager-0.4.zip. Unzipped it. Ran mvn install. Took the .war file and put it under C:\apache-tomcat-6.0.18\webapps\

    When I access http://localhost:8080/FinanceManager-0.4/index.jsp I get the main page , however when I click Login link I get

    The requested resource (/FinanceManager/login.jsp) is not available.

    I have to manually change it to http://localhost:8080/FinanceManager-0.4/login.jsp to get the login page.

    Note I had to add -0.4 to the name.
    I could login and but then none of the links work and I have to add -0.4 and make it work.

    Can you please tell me how to fix it.

    Thanks
    Kumar

    Jun 15, 2009 @ 10:08


  2. Kumar

    Just changed name of the deployed folder.. works fine

    Jun 15, 2009 @ 13:23


  3. sschmidt

    Hi Kumar,

    Maven will create a war file by default which contains the version number. There are different ways to address this depending on what you want to do. The easiest is to use the warName property in the maven war plugin as documented here:

    http://maven.apache.org/plugins/maven-war-plugin/war-mojo.html#warName

    I you want to deploy from command line straight to Tomcat or Jetty, these plugins will do the trick too:

    org.codehaus.mojo
    tomcat-maven-plugin

    org.mortbay.jetty
    maven-jetty-plugin
    6.1.10

    I usually use Eclipse WTP to deploy the application to Tomcat from my development environment.

    So as yu can see there are plenty of options to choose from :-)

    Hope this helps.

    -Stefan

    Jun 17, 2009 @ 10:20


  4. ka

    Thank you for this very helpful series.. can you provide some info on when do you think you will conclude it. Just wanted to know if you plan to have a final working version of the app or do U plan to continue making changes. I ask cuz I wanna download and learn the application design.. but if it’s in a state where all the functionality isnt working yet, I can wait for sometime.

    Jun 23, 2009 @ 10:38


  5. sschmidt

    @ka

    Every release of the Spring Finance Manager sample application is a fully working application. So you should be able to download, build and deploy it immidiately.

    With each new blog post in this series I have been extending the functionality of the application to demonstrate new features. So at the moment I am not planning to conclude this series but that is not really the point as you can use the current fully functional version to learn from it. If you find that it contains too many technologies (WebFlow, Security) you can use a previous version and learn from that first.

    Hope this helps.

    -Stefan

    Jun 23, 2009 @ 10:49


  6. vennela

    Hi,
    When i am trying to install, not able to install spring security 3.0 M1. Getting following error.

    Missing:
    ———-
    1) org.springframework.security:spring-security-core:jar:3.0.0.M1

    Try downloading the file manually from the project website.

    Then, install it using the command:
    mvn install:install-file -DgroupId=org.springframework.security -Dartifact
    Id=spring-security-core -Dversion=3.0.0.M1 -Dpackaging=jar -Dfile=/path/to/file

    Alternatively, if you host your own repository you can deploy the file there:

    mvn deploy:deploy-file -DgroupId=org.springframework.security -DartifactId
    =spring-security-core -Dversion=3.0.0.M1 -Dpackaging=jar -Dfile=/path/to/file -D
    url=[url] -DrepositoryId=[id]

    Path to dependency:
    1) net.stsmedia.financemanager:FinanceManager:war:0.4
    2) org.springframework.security:spring-security-core:jar:3.0.0.M1

    2) org.springframework.security:spring-security-config:jar:3.0.0.M1

    Try downloading the file manually from the project website.

    Then, install it using the command:
    mvn install:install-file -DgroupId=org.springframework.security -Dartifact
    Id=spring-security-config -Dversion=3.0.0.M1 -Dpackaging=jar -Dfile=/path/to/fil
    e

    Alternatively, if you host your own repository you can deploy the file there:

    mvn deploy:deploy-file -DgroupId=org.springframework.security -DartifactId
    =spring-security-config -Dversion=3.0.0.M1 -Dpackaging=jar -Dfile=/path/to/file
    -Durl=[url] -DrepositoryId=[id]

    Path to dependency:
    1) net.stsmedia.financemanager:FinanceManager:war:0.4
    2) org.springframework.security:spring-security-config:jar:3.0.0.M1

    3) org.springframework.security:spring-security-taglibs:jar:3.0.0.M1

    Try downloading the file manually from the project website.

    Then, install it using the command:
    mvn install:install-file -DgroupId=org.springframework.security -Dartifact
    Id=spring-security-taglibs -Dversion=3.0.0.M1 -Dpackaging=jar -Dfile=/path/to/fi
    le

    Alternatively, if you host your own repository you can deploy the file there:

    mvn deploy:deploy-file -DgroupId=org.springframework.security -DartifactId
    =spring-security-taglibs -Dversion=3.0.0.M1 -Dpackaging=jar -Dfile=/path/to/file
    -Durl=[url] -DrepositoryId=[id]

    Path to dependency:
    1) net.stsmedia.financemanager:FinanceManager:war:0.4
    2) org.springframework.security:spring-security-taglibs:jar:3.0.0.M1

    Aug 12, 2009 @ 06:56


  7. Srini

    It has been a while since you released a version (along with Spring 3.0 M1).

    We already have Spring 3.0 M4.

    When can we expect the next releases?

    Aug 15, 2009 @ 16:30


  8. Stefan Schmidt

    @Srini,

    The latest version of the Spring FinanceManager application already uses Spring framework 3.0.0.M3 and Spring Security 3.0.0.M1. I am currently waiting for a new milestone release of Spring Security which aligns with Spring 3.0.0.M4 as they are currently incompatible. As soon as it comes out and I find some time to test I will update the dependencies accordingly.

    HTH
    -Stefan

    Aug 16, 2009 @ 16:34


  9. Stefan Schmidt

    Ah yes, the maven repository location has changed in the meantime. Please edit your pom file and replace the current milestone repository URL with the following: < url >http://maven.springframework.org/milestone< /url > This should do the trick.

    -Stefan

    Aug 16, 2009 @ 16:36


  10. Nima

    You wrote:

    “The filter seen on the findAll() … This filter is applied after (post) the collection is returned from the repository and then the collection is reduced as per constraint expressed in the expression.”

    Is there an alternative for large sites – some kind of prefilter? Returning extremely large collections where only few elements are relevant will waste too many resources.

    Aug 22, 2009 @ 02:31


  11. Dennis Laping

    Stefan,

    First of all, it’s a very nice article. I have problem though.
    When I did “mvn install”, it downloaded a lot of files but it said some artifacts are missing.

    9 required artifacts are missing.
    for artifact:
    net.stsmedia.financemanager:FinanceManager:war:0.4
    (from all the repositories specified in the pom.xml)

    And also, where can I find the FinanceManager-servlet.xml?

    Thanks and regards,
    Dennis

    Aug 22, 2009 @ 13:53


  12. Stefan Schmidt

    Dennis,

    If you have dependencies missing that means that maven was unable to download them all as defined in the pom.xml. I am not sure what went wrong, but it may be that one of the repositories was temporarily not available. I have just released version 0.5 of the Spring Finance Manager application. Please try this one as I have made some changes to the repository list.

    The FinanceManager-servlet.xml has been moved and renamed to src/main/webapp/WEB-INF/config/FinanceManager-mvc.xml

    HTH

    -Stefan

    Aug 23, 2009 @ 19:03


  13. Stefan Schmidt

    @Nima,

    As you point out correctly, the @PostFilter is not always the best choice for your application. Spring Security offers the @PreFilter annotation (http://bit.ly/18Ta9p) but I have not tested it and I am not sure if that is the best solution for your problem. It would probably be best if you have a finder method in your repository which pulls only the records you really need.

    -Stefan

    Aug 23, 2009 @ 19:06


  14. Jon Hill

    Hi Stefan

    I’ve played around with @PostConstruct in my application and found it not really suitable for use within a @Transaction annotated method. There seems to be no guarantee that the required initialisation will have finished (see http://forum.springsource.org/showthread.php?t=58337)

    I did get it to work if I followed your example of annotating the interfaces of dao methods and using an aop proxy instead of aspectj, but I have now opted for a @PostInitialize routine instead.

    Jon

    Oct 20, 2009 @ 20:33


  15. kiran

    Hi,

    where i can download the sts security example.It would be greate any one helped me.

    Thanks,
    kiran

    Jul 10, 2010 @ 01:48


  16. Gengaraj

    how can i download spring finance source?

    Aug 19, 2010 @ 06:10


  17. Stefan Schmidt

    All sources are available on Google code: http://code.google.com/p/spring-finance-manager/

    Jan 23, 2011 @ 08:11


  18. Stefan Schmidt

    All code for the articles is available here: http://code.google.com/p/spring-finance-manager/

    Jan 23, 2011 @ 08:12

Reply