Mind the Flex

Securing your Flex application with Spring Security and Active Directory

July 7th, 2008 | Posted by sven-
Filed under Flex, Java, Microsoft, Spring |

Download Sample

See also my follow up article: Securing your Flex app: smart card authentication with Spring Security

The goal of the current article is to provide a clear overview how to integrate a Flex application with Active Directory using the authentication and authorization mechanism offered by the new Spring Security.

Before downloading the sample project, you should have: Java web app server (I'm using Apache Tomcat) and Active Directory with login credentials. Instead of AD you can use any LDAP directory server (for example ApacheDS).

To run the sample Flex project you don't need download extra .jar or .swc libraries or create a Java project with an IDE. Just unzip the sample project into your Tomcat webapps directory and change LDAP server settings. However, to recompile the Flex project you should download the Flex source project with Granite DS library granite.swc, add it to the Flex Build Path and to define Flex Server. The directory structure for the project looks like.

For those who don't know: Spring is an lightweight Java framework. Spring Portfolio includes now the Spring Security 2.0. providing comprehensive security services for J2EE-based enterprise applications. Spring Security 2 builds upon the popular Acegi Security, but it is much easier to use than former Acegi Security. Rod Jonson, creator of the Spring framework, noticed recently that one of the problems with Acegi Security was that it was very powerful but it wasn't simple to use.

Version 2.0 of the Spring framework introduced namespace configuration. For example, it allows a more clearer way of configuring your LDAP server. To allow the security namespace in your application context just add the schema declaration to application context file:

  1.  
  2. <beans
  3. xmlns="http://www.springframework.org/schema/beans"
  4. xmlns:s="http://www.springframework.org/schema/security"
  5. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  6. xsi:schemaLocation="http://www.springframework.org/schema/beans
  7. http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  8. http://www.springframework.org/schema/security
  9. http://www.springframework.org/schema/security/spring-security-2.0.2.xsd">
  10. </beans>
  11.  

Before we go further, take a look to the UML sequence diagram. The diagram itself (as the slogan "Security is hard, let's use tools!) is taken from the presentation of Mike Wiesner Using Spring Security 2 (SpringOne'08). Treat the policewomen like a Security Interceptor.

Authentication

First, let's look at the web.xml that has a DelegatingFilterProxy. It maps all the requests to springSecurityFilterChain.

  1.  
  2. <filter>
  3. <filter-name>springSecurityFilterChain</filter-name>
  4. <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  5. </filter>
  6. <filter-mapping>
  7. <filter-name>springSecurityFilterChain</filter-name>
  8. <url-pattern>/*</url-pattern>
  9. </filter-mapping>
  10.  

We can now edit our application context file /WEB-INF/conf/applicationContext-security.xml. The first thing we need to do is to configure the ldap-server element by providing the URL to our Active Directory server and a full DN for the manager we want use for lookups. Instead of definining the DN for the user (by replacing the user login name in the supplied pattern) we are configuring an LDAP search filter to locate the user. As Active Directory uses a different account object, we have to specify sAMAccountName for the UID object. Next we are loading authorities from groups in the LDAP directory using ldap-authentication-provider element and group-* attributes.

  1.  
  2. <s:ldap-server
  3. url="ldap://activedirectory:10389"
  4. manager-dn="CN=My Service Account,OU=Accounts, DC=mindtheflex, DC=com"
  5. manager-password="password"
  6. />
  7.  
  8. <s:ldap-authentication-provider
  9. user-search-base="OU=Accounts, DC=mindtheflex, DC=com"
  10. user-search-filter="sAMAccountName={0}"
  11. group-search-filter="member={0}"
  12. group-role-attribute="cn"
  13. group-search-base="OU=Groups, DC=mindtheflex, DC=com"
  14. role-prefix="ROLE_"
  15. />
  16.  

Using ApacheDS, you can change ldap-server and ldap-authentication-provider configuration:

  1.  
  2. <s:ldap-server
  3. url="ldap://localhost:10389"
  4. manager-dn="uid=admin,ou=system"
  5. manager-password="secret"
  6. />
  7.  
  8. <s:ldap-authentication-provider
  9. user-dn-pattern="uid={0},ou=people"
  10. group-search-filter="uniqueMember={0}"
  11. group-role-attribute="cn"
  12. group-search-base="ou=groups,dc=example,dc=com"
  13. role-prefix="ROLE_"
  14. />
  15.  

 

GraniteDS

Now, let's examine again the web.xml. I'm using Granite Data Services library for integrating my Flex application with J2EE application server. Granite DS (developed by Franck WOLFF) is a free, open source alternative to Adobe LiveCycle Data Services. See project home for more documentation. GraniteDS seems to me to be more "flexible" than Adobe LDS (now known as BlazeDS) for integrating rapidly Java community-driven features (Spring framework, hibernate etc). If you are interested how to hack BlazeDS and put it work with Spring Security 2.0, see the Igenko project (more links bellow) and Gridshore's blog.

GraniteDS uses AMF3 binary format for data serialization/deserialization and remote method invocation. We have to define AMFMessageServlet and url pattern. This servlet handles all requests matching the /graniteamf/* pattern and is pretty similar to BlazeDS MessageBrokerServlet. Both GraniteDS and BlazeDS are using binary remoting to convert data objects between your Java application on the back-end and AS3 in Flex.

  1.  
  2. <filter>
  3. <filter-name>AMFMessageFilter</filter-name>
  4. <filter-class>
  5. org.granite.messaging.webapp.AMFMessageFilter
  6. </filter-class>
  7. </filter>
  8. <filter-mapping>
  9. <filter-name>AMFMessageFilter</filter-name>
  10. <url-pattern>/graniteamf/*</url-pattern>
  11. </filter-mapping>
  12. <servlet>
  13. <servlet-name>AMFMessageServlet</servlet-name>
  14. <servlet-class>
  15. org.granite.messaging.webapp.AMFMessageServlet
  16. </servlet-class>
  17. <load-on-startup>1</load-on-startup>
  18. </servlet>
  19. <servlet-mapping>
  20. <servlet-name>AMFMessageServlet</servlet-name>
  21. <url-pattern>/graniteamf/*</url-pattern>
  22. </servlet-mapping>
  23.  

The next step is to configure your Spring destinations in /WEB-INF/flex/services-config.xml file:

  1.  
  2. <service id="granite-service"
  3. class="flex.messaging.services.RemotingService"
  4. messageTypes="flex.messaging.messages.RemotingMessage">
  5. <destination id="login">
  6. <channels>
  7. <channel ref="my-graniteamf" />
  8. </channels>
  9. <properties>
  10. <factory>springFactory</factory>
  11. <source>loginService</source>
  12. </properties>
  13. <security>
  14. <security-constraint>
  15. <auth-method>Custom</auth-method>
  16. <roles>
  17. <role>ROLE_ADMIN</role>
  18. <role>ROLE_USER</role>
  19. </roles>
  20. </security-constraint>
  21. </security>
  22. </destination>
  23. </service>
  24. <channels>
  25. <channel-definition id="my-graniteamf" class="mx.messaging.channels.AMFChannel">
  26. <endpoint uri="http://{server.name}:{server.port}/{context.root}/graniteamf/amf"
  27. class="flex.messaging.endpoints.AMFEndpoint"/>
  28. </channel-definition>
  29. </channels>
  30.  

To enable Spring Security, you have to put a declaration in /WEB-INF/granite/granite-config.xml file:

  1.  
  2. <granite-config>
  3. <security type="org.granite.messaging.service.security.SpringSecurityService"/>
  4. </granite-config>
  5.  

 

Flex application

My example is based on the GraniteDS demo, but I have simplified it considerably just to login into Active Directory and calling two method form Java — one for 'user' and another for 'admin'. Indeed, there is nothing complex here — but should it? One thing I'am going to say is that the new Spring Security with GraniteDS are great tools to make your life easier if you are building enterprise-level apps in Flex.

Login.mxml

  1.  
  2. <mx:Panel title="Login" xmlns:mx="http://www.adobe.com/2006/mxml">
  3. <mx:Script>
  4. <![CDATA[
  5. [Bindable]
  6. public var onCredentialsSet:Function = null;
  7. [Bindable]
  8. public var loginMessage:String = "";
  9. [Bindable]
  10. public var loggedIn:Boolean = false;
  11. ]]>
  12. </mx:Script>
  13. <mx:Text text="(Type in user/user or admin/admin)" textAlign="center"/>
  14. <mx:Form>
  15. <mx:FormItem label="Username">
  16. <mx:TextInput id="username"/>
  17. </mx:FormItem>
  18. <mx:FormItem label="Password">
  19. <mx:TextInput id="password" displayAsPassword="true"
  20. enter="onCredentialsSet(username.text, password.text)"/>
  21. </mx:FormItem>
  22. </mx:Form>
  23. <mx:Text text="{loginMessage}" textAlign="center"/>
  24. <mx:Button label="Login" click="onCredentialsSet(username.text, password.text)"/>
  25. </mx:Panel>
  26.  

Main.mxml

  1.  
  2. import org.granite.rpc.remoting.mxml.SecureRemoteObject;
  3.  
  4. [Bindable]
  5. private var srv:SecureRemoteObject = null;
  6. ...
  7. public function onCredentialsSet(username:String, password:String):void {
  8. srv.setCredentials(username, password);
  9. }
  10.  

 

Method authorization

Configuring the method level authorization you just have to define the secure methods either with pointcuts in the XML or with annotations in Java. The global-method-security element (in /WEB-INF/conf/applicationContext-security.xml) provides method security for all beans registered in the Spring application context. To restrict access to any method in the application you can enable annotation-based security and annotate secured method directly in Java code. If you are using Java 5 or greater, then more standard-compliant JSR-250 security annotations (@RolesAllowed( {"ROLE_ADMIN"} )) can be used as well.

  1.  
  2. package mypackage;
  3. import org.springframework.security.annotation.Secured;
  4. public class Login {
  5.  
  6. @Secured({"ROLE_ADMIN"})
  7. public String getAdminData() {
  8. return "Login.getAdminData()";
  9. }
  10.  
  11. @Secured({"ROLE_USERS"})
  12. public String getUserData() {
  13. return "Login.getUserData()";
  14. }
  15. }
  16.  

But there is also another way that allows you to leave the Java code as it is and you can define a protected pointcut and the access control configuration attributes in XML. Using protect-pointcut allows you to apply security only with a simple declaration. The methods starting with getAdmin need the role ROLE_ADMIN. Every bean registered in the Spring application context that provides a method that matches the pointcut will have security authorization.

  1.  
  2. <s:global-method-security>
  3. <s:protect-pointcut expression="execution(* mypackage.Login.getAdmin*(..))" access="ROLE_ADMIN"/>
  4. </s:global-method-security>
  5.  

You can even use XML to override method security metadata expressed by @Secured annotations, or @Secured annotations overriding method security metadata expressed by JSR 250 annotations. Note that using a protected pointcut the other dependent jars *.jar files (Aspectj and CGLIB2) are required.

You can propagate Spring Security exeptions to Flex:

  1.  
  2. public function onSecurityEvent(event:SecurityEvent):void {
  3. switch (event.type) {
  4. case SecurityEvent.INVALID_CREDENTIALS:
  5. loginView.loginMessage = "Invalid username or password";
  6. loginView.loggedIn = false;
  7. break;
  8. case SecurityEvent.NOT_LOGGED_IN:
  9. srv.logout();
  10. loginView.loginMessage = "";
  11. loginView.loggedIn = false;
  12. break;
  13. case SecurityEvent.ACCESS_DENIED:
  14. Alert.show("You don't have required rights to execute this action\n"+event);
  15. break;
  16. }
  17. }
  18.  


Flex and Active Directory Sample Project

Download sample project.

Anyone else who is interested to look at the source code can download it here.

External links:


BlazeDS
GraniteDS

Igenko:
http://code.google.com/p/igenko/wiki/FlexDataServices
http://tech.groups.yahoo.com/group/graniteds/message/1374

BlazeDS and Spring Security
http://www.machine501.com/blog/2008/02/14/blazeds-and-spring-security/
http://www.machine501.com/blog/2008/05/30/blazeds-spring-and-acegi-security-part-2/
http://www.machine501.com/blog/2008/06/01/blazeds-and-springacegi-security-part/

BlazeDS and Spring/Acegi integration
Acegi LoginCommand for FDS
Integrating flex 3 with spring security (formerly known as Acegi)
Granite with ACEGI


17 Responses to “Securing your Flex application with Spring Security and Active Directory”

  1. » Securing your Flex application with Spring Security and Active… Apache: What The World Is Saying About Apache Says:

    […] Securing your Flex application with Spring Security and Active… Before downloading the sample project, you should have: Java web app server (I’m using Apache Tomcat) and Active Directory with… […]

  2. Gridshore » Blog Archive » Integration spring security (Acegi) and flex 3 the sequel Says:

    […] and integrate authentication and authorization with spring security. A few days a go I received a trackback from sven. Curious as I am I started reading the material he provided and especially the other links he […]

  3. Integrating Flex, BlazeDS, and Spring security « Arunbluebrain’s Flex Says:

    […] Securing your Flex application with Spring Security and Active Directory […]

  4. daniel boromisa Says:

    hey so, i have the example you wrote up almost working, Thanks for taking the time to publish it, its really neat, however i am banging my head against one really (trivial thing im guessing)

    when i direct this to my company ldap i get:
    [LDAP: error code 48 - Inappropriate Authentication]; nested exception is javax
    .naming.AuthenticationNotSupportedException: [LDAP: error code 48 - Inappropriat
    e Authentication]

    I feel like I need to somehow add a password encoder sha, but not certain where one can do that?

    here is my config

  5. Bookmarks about Security Says:

    […] - bookmarked by 3 members originally found by sanyaissues on 2008-11-11 Securing your Flex application with Spring Security and Active… http://www.mindtheflex.com/?p=67 - bookmarked by 3 members originally found by HotPinkMidNite on […]

  6. flashmattic Says:

    Great article, but one note, if I may:
    when using annotation for method security, you forgot to mention that we need to declare in on our application security context. like so:

    other wise it won’t work :).

  7. loop Says:

    well, i have done the same thing without ldap, but with the login/pass stored in the spring file.

    and when i enter good login/pass, it works,
    when i enter wrong login/pass, i’ve got rejected => this is what i want,
    but if i re-enter good login/pass, i’ve got rejected too !
    the only solution i’ve found is to reload the current page.

    any idea ?

  8. Securing your Flex app: smart card authentication with Spring Security (Part 2) | Mind the Flex Says:

    […] In this article I am going to show you how to implement Smart Card authentication mechanism in a Flex application with Spring Security.  I will use X.509 certificate authentication and database authorization simultaneously. To get a full picture of the topic, you should take a look at my previous article Securing your Flex application with Spring Security and Active Directory. […]

  9. magomarcelo Says:

    did you use comic life for that UML sequence diagram? really nice, actually

  10. sissoko Says:

    Great article, thanks,
    By the way, what tool did you use for your UML sequence diagram (http://blog.mindtheflex.com/wp-content/uploads/2008/07/uml.png)?
    it looks great !!

  11. sven- Says:

    Comic Life, it’s better than Visio :))

  12. sandrar Says:

    Hi! I was surfing and found your blog post… nice! I love your blog. :) Cheers! Sandra. R.

  13. agung Says:

    hi sven
    i have trouble, i can’t send the value and this details
    “Fault: Client.Error.MessageSend - Send failed”

    can you help me….
    thx

  14. lennon Says:

    hi sven, i’m beginner
    how to open the project sample using eclipse…..?

    please help me….
    answer my question..

  15. sanka dilmadu Says:

    very nice article.keep it up.

  16. Angel Ramirez Says:

    I have the same problem as agung.

    “Fault: Client.Error.MessageSend - Send failed”

    Do you know the reason????

  17. John Marton Says:

    Do you use Eclipse? I cannot open the project from eclipse with flex plugin.

Leave a Reply