flexlogo.pngThis blog item show a way of doing security, after some additional experience I consider this method as being non optimal. The server side does not change a lot (spring security configuration), but the client does. I explain my current solution is this blog post:Integration spring security and flex 3 the sequel/

This article is actually about two things. It explains the basic steps to use the new spring security version 2 library in a java (web) application. I am going to show the basic configuration as well as web resource authorization and bean methods authorization. The other part is the integration of flex with spring security. I am going to show how to use authentication from within flex 3 using the spring security back end. After that I’ll show a service used from within flex through blazeds to ask for the roles a logged in user has. Using these roles I am going to hide buttons to actions non admin users must not use. Like the create new book.springlogo.pngIn short this article shows the complete picture of an application using flex 3, blazeds, spring security to authenticate users and authorize actions.

Read on if you want to learn about the integration of these frameworks.

Introduction

For a lot of my applications up till now I have used Acegi or spring security to take care of authentication and authorization. So the whole idea of securing certain url’s, presenting a login form, going to a database or ldap or whatever, checking password and obtain the roles a certain user has. This has become common through out all my jsp based web applications. Now I am moving into the flex domain. I have created an application that you can use to store all your books and browse through them. Now I want to make sure that not everybody can see the application, and only special users can insert and update books. Just because I know how to handle springframework at the server side, it seems logical to keep it that way. I have already written about the integration of flex and spring, now I want to reuse my security knowledge to secure my flex application.

One warning before you think this solutions solves all your problems. Please check the future directions, there are some differences between a normal web application and flex application in relation to session management and probably some other things as well.

So what do we need to do, let’s have a birds eye view over the complete solution:

  • change the pom
  • add a filter to your web.xml
  • Configure the filter chain using the excellent new spring security namespace support.
  • Configure the resources to secure (at first all)
  • Fine tune the resources to secure, only *.html so everybody can download the flex swf file
  • create the login form in flex, including the remote call and the event handling of the result.
  • Implement method level security
  • Create a remote call that returns the roles for an authenticated user
  • Use the obtained roles to prevent showing the button to open the new book form.

Enough has been said, let’s start configuring the basic security. If you want to have a look at the source code, go to my google code project @ http://code.google.com/p/gridshore. Check the books-overview project.

Configuring Spring security (authentication and resource authorization)

First the changes in the pom file, we exclude the spring-support jar, this is important since we use spring 2.5.x and that version does not contain the spring-support module anymore. This results in some jars from spring 2.0.x due to the dependency from spring-security.

    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-core-tiger</artifactId>
        <version>2.0.0</version>
        <exclusions>
            <exclusion>
                <groupId>org.springframework</groupId>
                <artifactId>spring-support</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

That takes care of the needed jars on the classpath, now can actually start by adding a filter including mapping to the web.xml. If you look at the filter-mapping, you can see we pass everything to the spring security filter. This gives flexibility to the actually secured resources, but you can optimize it a bit.

    <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>

Next step is to implement security, the following lines of code secures all web resources and creates an in memory user store with two users. As you can see in the code, there is almost nothing to configure. Spring security makes use of a lot of sensible defaults. You do not even have to configure your own login screen. There is even a default version for that as you can see in the image after the code.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.xsd">
    <security:http auto-config="true">
        <security:intercept-url pattern="*" access="ROLE_USER"/>
    </security:http>
    <security:authentication-provider>
        <security:user-service>
            <security:user name="admin" password="admin" authorities="ROLE_USER, ROLE_ADMIN"/>
            <security:user name="user" password="user" authorities="ROLE_USER"/>
        </security:user-service>
    </security:authentication-provider>
</beans>
defaultloginformspringsecurity.png

Now we can prevent people from downloading he swf file, could be a nice security thing, but not really what I want. I do not really care if they can download the swf, I care more about consistent look and feel and having some good authentication. Next step is to create the login form in the flex app.

Configure flex to use spring’s authentication

First we have to change the resources that are secured.

    <security:http auto-config="true">
        <security:intercept-url pattern="index.html" filters="none"/>
        <security:intercept-url pattern="*.swf" filters="none"/>
        <security:intercept-url pattern="*.html" access="ROLE_USER"/>
    </security:http>

Now that we have that out of our way, let’s have a look at the flex code. The Home.mxml is the application that gets started. First a public parameter called authorization, this parameter is of our on type AuthorizationControl and contains the username as well as the granted roles. Making this parameter public enables all other flex modules to ask for the value. Another function that is public and important for the same reason is the function isAuthorized. This returns false if the current user has not been authorized yet. After the screen has been created and is ready to be displayed we create the login form using the creationComplete event. The following function is called to create the login form and add it to the page. As you can see, we remove all the children of the main content panel before we add the login form.

    public function authenticateUser():void {
        myMainContentPanel.removeAllChildren();
        myMainContentPanel.addChild(new AuthenticationForm());
    }

Now we have a look at the implementation of the form. First the elements to present the form and the element that defines the remote http GET. In the code you’ll find the username TextInput, the password TextInput a Text element for showing a message in case of an authentication error and as said the element HttpService that defines the remote call. Take a good look at the HttpService element. We specify the special spring security url that we post the form to : j_spring_security_check. We define the method to call if everything goes well (result) as well as in case of an error (fault).

    <mx:HTTPService
            id="loginService"
            url="j_spring_security_check"
            showBusyCursor="true"
            method="POST"
            result="loginServiceResultHandler(event)"
            fault="loginServiceFaultHandler(event)">
        <mx:request>
            <j_username>{userName.text}</j_username>
            <j_password>{password.text}</j_password>
        </mx:request>
    </mx:HTTPService>
    <mx:Text id="authenticationMessage" visible="false" styleName="warning"/>
    <mx:Form defaultButton="{submitButton}">
        <mx:FormItem label="Username">
            <mx:TextInput id="userName"/>
        </mx:FormItem>
        <mx:FormItem label="Password">
            <mx:TextInput id="password" displayAsPassword="true"/>
        </mx:FormItem>
        <mx:FormItem>
            <mx:Button id="submitButton" label="submit" click="submitBook()"/>
        </mx:FormItem>
    </mx:Form>

In the code we saw three functions that are called when we push the login button, when a result comes back from the remote service and when an error comes back using the remote service. The function submitLogin just uses the remote service. The most interesting function is the loginServiceResultHandler. Here we call the initComponent function of the Application object. Remember we talked about this when discussing the Home.mxml. The result of this action is that we now have been authenticated on the server and we have security related information stored on the session.

        private function submitLogin():void {
            submitButton.enabled = false;
            loginService.send();
            submitButton.enabled = true;
        }
        private function loginServiceResultHandler(event:ResultEvent):void {
            Application.application.initComponent();
        }
        private function loginServiceFaultHandler(event:FaultEvent):void {
            authenticationMessage.text = "Problem while authentication ...";
            authenticationMessage.visible = true;
        }

We go back to the Home.mxml component. We now call the remote service booksSecurityServices and call the method obtainGrantedRoles which is actually a call to the spring bean. This bean uses some specific spring security classes to obtain the current authenticated user and requests the granted roles from this user. The object that is returned AuthorizationData has the same fields as the flex object AuthorizationControl. Using BlazeDS we obtain the data we want. If you want to know more about the configuration of blazeDS than check my previous post. Most important file is the remoting-config.xml.

public class BooksSecurityServicesImpl implements BooksSecurityServices {
    public AuthorizationData obtainGrantedRoles() {
        GrantedAuthority[] authorities =
                SecurityContextHolder.getContext().getAuthentication().getAuthorities();
        int numAuthorities = authorities.length;
        String[] grantedRoles = new String[numAuthorities];
        for (int counter = 0; counter < numAuthorities ; counter++) {
            grantedRoles[counter] = authorities[counter].getAuthority();
        }
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        return new AuthorizationData(grantedRoles,username);
    }
}

What do we do when we have received the AuthorizationControl instance? We assign it to our globally available authorization parameter. Then if the user is authorized we initialize the navigation object and clean out the main content panel. The next block of code shows the mxml component representing the remote object as well as the function that handles a successful call. The function isAuthorized is used to check if the authorization we have is not of type anonymous. This role is assigned to any user asking a resource going through the spring security filters

    <mx:RemoteObject id="securityService" destination="booksSecurityServices" 
                     fault="authorizationFaultHandler(event)">
        <mx:method name="obtainGrantedRoles" result="handleReceivedGrantedRoles(event.result)"/>
    </mx:RemoteObject>

private function handleReceivedGrantedRoles(eventResult:Object):void {
    this.authorization = AuthorizationControl(eventResult);
    if (isAuthorized()) {
        var mainNavigation:MainNavigationComponent = new MainNavigationComponent();
        menuDock.addChild(mainNavigation);
        mainNavigation.visible = true;
        mainNavigation.addEventListener(components.MainNavigationEvent.SELECT_ITEM, eventAction);
        myMainContentPanel.removeAllChildren();
    }
}
public function isAuthorized():Boolean {
    return authorization != null && authorization.username != 'roleAnonymous';
}

Depending on the user that is logged on, we now have one or two buttons at the top of the screen. Users with the ROLE_ADMIN will see two buttons. One line of code I want to put under your attention is the one with an addEventListener. We will need this line when we start talking about he navigation menu component. Most important to know here is that we add a listener for our own event, just like we would for a click event to a button for instance. Let’s have a look at the important components.

Use user’s roles to hide some ui components

For the navigation we make use of a custom event when a button is clicked. This is used to determine the component to show in the main content panel when one of the buttons is clicked. If you look at the function initMyComponent you can see how we can determine whether we need to show the button for a new book. We make use of the globally available object Application.application which contains our object authorization. The function userIsAdmin just checks if the user has the role ADMIN. In the function clickEventHandler we create a new MainNavigationEvent which is catched by our Home.mxml component like I described.

    public class MainNavigationComponent extends HBox {
        public function MainNavigationComponent() {
            super();
            initMyComponent();
        }
        function initMyComponent():void {
            addChild(createNewButton('allbooks', 'All Books'));
            if (Application.application.isAuthorized() && Application.application.authorization.userIsAdmin()) {
                addChild(createNewButton('newbook', 'New Book'));
            }
        }
        private function clickEventHandler(event:Event):void {
            dispatchEvent(new MainNavigationEvent(MainNavigationEvent.SELECT_ITEM, event.currentTarget.id));
        }
        private function createNewButton(id:String, label:String):Button {
            var aButton:Button = new Button();
            aButton.id = id;
            aButton.label = label;
            aButton.addEventListener(MouseEvent.CLICK,clickEventHandler);
            return aButton;
        }
    }

For completeness I’ll also show the event stuff here. The next function is from the Home.mxml. It is called when the special event is catched. The event contains a method to create a new component that is displayed in the main content panel.

    private function eventAction(event:components.MainNavigationEvent):void {
        myMainContentPanel.removeAllChildren();
        myMainContentPanel.addChild(event.createRightUIComponent());
    }

The next block of code show our custom flex event component. The buttons pass the item that was clicked to the event and based on this value we created the appropriate component like FilteredBooks or BookForm.

    public class MainNavigationEvent extends Event {
        public static var SELECT_ITEM:String = 'selectitem';
        public var clickedItem:String;
        public function createRightUIComponent():UIComponent {
            var createdComponent:UIComponent;
            switch (clickedItem) {
                case 'allbooks' :
                    createdComponent = new FilteredBooks();
                    break;
                case 'newbook' :
                    createdComponent = new BookForm();
                    break;
                default:
                    var label:Label = new Label();
                    label.text = clickedItem;
                    createdComponent = label;
            }
            return createdComponent;
        }
        public function MainNavigationEvent(eventType:String,clickedItem:String) {
            super(eventType, false, false);
            this.clickedItem = clickedItem;
        }
    }

We are almost there. Now you cannot click on the new book button anymore. But it is possible we forget to secure something on the front-end. For the example I have forgotten to secure the update book screen. Now anybody can click on a book and go to the update screen. We need more security, therefore we implement method level security on the server side.

Configure the method level authorization in spring security

Implementing method level security using spring security is very easy, especially when you have done the steps we have done so far. We use aspectJ style pointcuts to select the object and methods that need a certain security role. In our case we select all objects with a name ending with Manager in the specified package. The methods starting with store need the role ROLE_ADMIN. The methods starting with obtain need to role ROLE_USER. To show that it works we open the list of books with the normal user, click on a book, make a change and get the message as shown in the following image. To my opinion this message is not nice, you should prevent the user from being able to do this as all. So do not present the update form but present the data in non updatable form instead.

    <security:global-method-security>
        <security:protect-pointcut 
            expression="execution(* nl.gridshore.samples.books.business.*Manager.store*(..))"
            access="ROLE_ADMIN"/>
        <security:protect-pointcut 
            expression="execution(* nl.gridshore.samples.books.business.*Manager.obtain*(..))"
            access="ROLE_USER"/>
    </security:global-method-security>
authorizationerrorspringsecurity.png

Future enhancements

I am having mostly problems with the session handling. You need to think hard about what to do when the flex app outlives the server session. I also had some problems with new sessions that got started when I did not expect it. This had to do with a remote call before trying to authenticate. What I would like to do is something like a re-authentication when the sessions has died automatically. You also need to think about the length of the session. What should happen if you remove a role from a certain user.

Conclusions

It turned out to become a long article. I hope you had the patience to read it all. I do not think it is very hard to integrate spring-security with flex. All the things I have done for normal web application I could do as well for the flex application. The spring security version 2 is a good enhancement, much easier configuration, but still the possibility to make it pretty complex. Convention over configuration is well used. As for flex, just a few remote calls like in our previous posts.

I hope you like the article, drop a comment if you have questions or if you have found this useful.

References

Tagged on:                         

26 thoughts on “Integrating flex 3 with spring security (formerly known as Acegi)

  • June 5, 2011 at 7:12 pm
    Permalink

    Hi,
    This is realy helpful example and easy to learn.
    I am getting following error whenever running mvn install command.

    1) com.asfusion:mate:swc:0.8.9

    Try downloading the file manually from the project website.

    Then, install it using the command:
    mvn install:install-file -DgroupId=com.asfusion -DartifactId=mate -Dversion=0.8.9 -Dpackaging=swc -Dfile=/path/to/file

    Can somebody help me.

    Thanks in advance.

    • June 7, 2011 at 12:28 pm
      Permalink

      This is a normal maven error message. No repository is available for the artifact you are looking for. Beware this is a very old post and a lot has happened since than. I cannot imagine that this artifact is still not available in any repository. Just google for it.

  • November 10, 2010 at 4:31 pm
    Permalink

    I dont know why, but by calling j_security_check i getting ioError 404 (login.jsp with works fine)

    • December 10, 2010 at 10:00 am
      Permalink

      j_security_check returns the default/welcome file that you have configured in your web.xml.

      If u have configured none it will return error 404 not found.

      I prefer u configure a default jsp page which returns an xml

      eg:

      Best Regards
      Sriram

  • March 11, 2010 at 12:19 pm
    Permalink

    Thanks a lot, this article saved me countless of hours.

  • February 8, 2010 at 2:16 pm
    Permalink

    Hi guys,

    Firstly I am very new to spring framework but have some idea about flex.In my project there are roles which are dynamic(i.e new roles can be added from a user interface and permissions to specific methods can be granted from there only).The below code to restrict methods to role is hardcoded in the xml files how do I dynamically fetch this from the database using spring instead of the xml files.

    Can some one help me out please.

    Thanks…

  • January 4, 2010 at 9:50 am
    Permalink

    good posting jettro,
    but i’m not understand the workflow, can you post download link source code…plz
    thx:)

  • August 26, 2009 at 5:28 pm
    Permalink

    A very good article.
    My next step is integrating it with Spring LDAP :) Any good tips?

  • August 6, 2009 at 8:39 am
    Permalink

    Hi Jettro,
    I try a example after read you article. However, I encounter a problem:
    the HttpService can’t get any response, neither result function nor fault function is called. The j_spring_security_check functions normally.
    If I use the default form-login of spring security. Every thing is ok.

    I’m wondering what I’m doing wrong? Did you ever encounter this problem?

  • July 3, 2009 at 7:34 am
    Permalink

    Hi Iure,
    thank you for your comment. If I am understanding your problem well, it could be due to the anonymous user that is logged in, or the fact that spring returns a message instead of an error when the user cannot log in. That is one of the problems with this approach. Therefore I think you should have a look at other ways of doing this. In the following blogpost I took a different approach using the excellent flex framework Mate. But the ideas can be reused in other solutions as well.

    http://www.gridshore.nl/2009/05/24/integrate-flex-security-in-mate-using-the-spring-blazeds-integration-project/

    Hope that helps

  • July 3, 2009 at 1:08 am
    Permalink

    Hi Jettro,

    Even when my authentication fails I’m getting a resultHandler event instead of a faultHandler… The spring security authenticates correctly since I got an error message on my app console.

    By the way, thank you for this excelent article

  • April 30, 2009 at 8:30 am
    Permalink

    Before login, I can get the result of remoting object.
    After login, I still want to get the result of remoting object.
    but here is error message from remoting object fault handler

    [FaultEvent fault=[RPC Fault faultString=”error” faultCode=”Channel.Call.Failed” faultDetail=”NetConnection.Call.Failed: HTTP: Status 500″]
    messageId=”B93CBB3F-659E-F4D1-6795-F5E9B5ECBDE9″ type=”fault” bubbles=false cancelable=true eventPhase=2]

    why?

    • April 30, 2009 at 8:37 am
      Permalink

      Do you see anything on the server log? Are you trying my sample, or your own app? Be sure to switch on BlazeDS log.

      It might be a session thing, but I cannot tell from this info only.

  • November 10, 2008 at 10:57 pm
    Permalink

    Exactly what I was searching for :) Thank you

  • July 18, 2008 at 12:38 pm
    Permalink

    Can you try to use /j_spring_security_check, so with the slash?

    You can also change the spring configuration, I got the following snippet from the reference manual:

    <bean id="authenticationProcessingFilter"
    class="org.springframework.security.ui.webapp.AuthenticationProcessingFilter">
    <property name="authenticationManager" ref="authenticationManager"/>
    <property name="authenticationFailureUrl" value="/login.jsp?login_error=1"/>
    <property name="defaultTargetUrl" value="/"/>
    <property name="filterProcessesUrl" value="/j_spring_security_check"/>
    </bean>
    

    maybe there is a global constant that you can set to change filterProcessesUrl, I do not know of it. Maybe you can use the spring forum.

    greetz Jettro

  • July 17, 2008 at 11:41 am
    Permalink

    my site is deployed in: http://sever:port/nameapp
    my appflex is placed in: http://sever:port/nameapp/nappappflex

    When i´m in authentification process, the app fails because it´s trying find the url “j_spring_security_check” in http://sever:port/nameapp/nappappflex and it´s placed in http://sever:port/nameapp.

    if i change url string

    <mx:HTTPService
    id=”loginService”
    url=”http://sever:port/nameapp/j_spring_security_check”
    showBusyCursor=”true”

    the app works !! but i don´t want put the complete url in field url. how can i obtain server:port + context in flex? or how can i config spring to find j_spring_security_check in other directory

    thanks !!

    {userName.text}
    {password.text}

  • Pingback: Gridshore » Blog Archive » Integration spring security (Acegi) and flex 3 the sequel

  • Pingback: Securing your Flex application with Spring Security and Active Directory | Mind the Flex

  • June 14, 2008 at 3:53 am
    Permalink

    Not enough information to create a working program.
    Not enough explaination on technologies used. (i.e I had no idea what a pom.xml file was.)

    Even after downloading the source from your site, installing maven (never used it), running mvn it downloaded a lot then errored out on the testing.

    Sorry I don’t have the time to learn another technolgy when I’m still trying to learn flex.

  • May 28, 2008 at 11:29 am
    Permalink

    Hi Jettro,

    I have seen this article before! Good one.

    Anyway, I am trying to find your email address and I can’t find it anywhere. A couple of things: 1) I have a book of yours; 2) you are now in Amsterdam, toch? Let’s have lunch or a drink.

    You know my email address, drop me a line. Also, this may be of interest to your group. Would be nice to collaborate again. Jamie.

    http://jamiedobson.co.uk/?q=node/54

  • May 26, 2008 at 3:51 pm
    Permalink

    I too have to say Very Cool Article!

    Looking forward to your next post.

  • May 24, 2008 at 2:29 pm
    Permalink

    Very cool article. I encountered some problem during Spring/Flex integration.

    Do you have a sample project about this article, so I can download and try it, please?

Comments are closed.