Platinum Partner
ria,blazeds,flex & air

Enterprise Security for Flex

The Spring BlazeDS Integration project combined with the new Flexible Chimp project for client-side filtering provides an ideal solution for fully securing enterprise Flex applications.

Though it is one of the most important aspects of enterprise applications, security can also be among the most difficult aspects of software development. For this reason, security should be considered early in the development of an application. When defining the security of an application, the AAA (authentication, authorization, and access control) paradigm is commonly used to categorize how each aspect of the application should be secured. Some security controls are purposely redundant to provide two layers of security.

When securing Flex applications, there are a variety of resources that need to be secured, including what data a user is able to see, what modules they can load, or what screens they can access. At a finer-grained level of security, you may need to limit a user to reading (but not writing) certain data or hide certain components in the user interface. In addition to providing integration between BlazeDS and a Java back end implemented with Spring, the Spring BlazeDS Integration project offers features to secure the Java services used by your Flex applications, providing an integrated solution with Spring Security. This solution enables you to define security at a service and method level of endpoints defined in BlazeDS and on Spring Beans.

Flexible Chimp is a new project, by Gorilla Logic, that provides permission-based filtering for Adobe Flex and AIR applications. Individual components can be secured based on the roles of a user. Chimp provides client-side security of the user interface through permission-based filtering of components. Applications implement Chimp by adding metadata within instances of the Flex UIComponent class. Based on the metadata, Chimp will remove components completely, enable them, disable them, or update their visibility. For more information, see the Flexible Chimp project website.

Note: This tutorial was co-authored with Ryan Knight, a Senior Software Architect at Gorilla Logic.

 

Requirements

In order to make the most of this article, you need the following software and files:

Flex Builder 3

 

Sample files:


Prerequisite knowledge

Familiarity with BlazeDS and Spring, as well as some knowledge of the Spring BlazeDS Integration project will be helpful.

Reviewing the three As of security

Enterprise developers should be familiar with the three As of security:

  • Authentication, or verifying the identity of a person, is usually done with a username and password on the Internet. It can also be done by retrieving the credentials from a single sign on (SSO) or other external system that is trusted.
  • Authorization is the process of determining what resources a person can access. This is most often done by defining the various roles in a system and then assigning the roles to different users and groups. This process is similar to checking tickets at a ski resort or seeing if a person is on the guest list of an exclusive party.
  • Access control refers to how the various resources of system are protected. It defines who is allowed to access which resources and the conditions for accessing the resources. It is analogous to seating in a plane, in which exit row seats are assigned only to those over a certain age and first class is reserved to those with special tickets.

Securing the server

This section provides a basic overview of configuring your Java server with the Spring BlazeDS Integration project. For an in depth reference, see the Spring BlazeDS Integration project page or DZone's Refcard.

Configuring server-side security in Spring

To secure communications with the server, the Spring BlazeDS Integration project uses an authentication and authorization process based on Spring Security. This process integrates Spring Security with the BlazeDS security process.

To configure the server side of the project, you'll need to edit your web.xml file. In this file, add an additional context configuration file for defining the Spring Security context:

 <!-- The front controller of this Spring Web application, responsible for handling all application requests -->
<servlet>
<servlet-name>sodablaze</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/config/security-context.xml
/WEB-INF/config/web-application-config.xml
</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>

Also, in web.xml, take note of the URL mapping to be sure it matches the channel definitions defined for BlazeDS. In this sample, map to the MessageBroker URL:

   <!-- Map all *.spring requests to the DispatcherServlet for handling -->
<servlet-mapping>
<servlet-name>sodablaze</servlet-name>
<url-pattern>/gorilla/*</url-pattern>
</servlet-mapping>

 

In the Flex configuration file, services.xml, make sure the URL definition also maps to the MessageBroker URL:

       <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">
<endpoint url="http://{server.name}:{server.port}/{context.root}/gorilla/messagebroker/amf"
class="flex.messaging.endpoints.AMFEndpoint"/>
</channel-definition>

<channel-definition id="my-secure-amf" class="mx.messaging.channels.SecureAMFChannel">
<endpoint url="https://{server.name}:{server.port}/{context.root}/gorillamessagebroker/amfsecure"
class="flex.messaging.endpoints.SecureAMFEndpoint"/>
<properties>
<add-no-cache-headers>false</add-no-cache-headers>
</properties>
</channel-definition>

Now that the channels are defined and the dispatch servlet is set up, you can define the security context, which was referred to in the web.xml file. The security-context.xml file defines the users and roles for the application. Here is an example configuration for an authentication provider:

<authentication-provider> 
<user-service>
<user name="ryan" password="utah" authorities="ROLE_USER, ROLE_ADMIN" />
<user name="jon" password="colorado" authorities="ROLE_USER" />
</user-service>
</authentication-provider>

Securing access to remote services

Remote services are declared as Spring Beans in the application context file, web-application-config.xml. The sample file defines the same class as two separate beans for example purposes. The first one is the sodaService and the second is securedSodaService. The second secures the remote service by defining what roles can access the service:

    <!-- A secured version of productService -->
<bean id="securedSodaService" class="com.gorillalogic.sodaBank.SodaService" >
<flex:remoting-destination />
<security:intercept-methods>
<security:protect method="get*" access="ROLE_USER" />
</security:intercept-methods>
</bean>

Security with Spring and BlazeDS can be as simple or as complex as your requirements dictate. You can secure entire Spring beans by role, or apply more fined-grained access control by defining which methods are exposed and who can access the methods.

With the new Spring BlazeDS Integration project, combining Spring and BlazeDS is easy and straightforward, making it easy to add security to your services with Spring Security.

Now that you have reviewed the Spring and BlazeDS integration, it is time to build on server-side security by protecting the client with the Flexible Chimp project.

Securing the client with Chimp

Before securing the Flex client with Chimp, you should secure the Java server. This article covers configuring your server security with Spring, but Chimp and the methods discussed in this section could be used with any secure server. Regardless of how you implement your server, the key is that you have truly secured your services and data on the server side, as that should be the heart of your security implementation. In this section I will review authenticating users in Flex through the ChannelSet, and then discuss filtering what users are able to see based on their roles or grants. Chimp is ideal for filtering user interface components on the client side, as it allows for protecting the view by simply adding metadata to your MXML and ActionScript source code. The Chimp homepage describes the project this way:

"Chimp is a permission based filtering component for Adobe Flex and AIR. Applications implement Chimp by adding metadata within the Flex UIComponents. Based on the metadata it will remove components completely, enable/disable, and update visibility."

User authentication

Before Chimp can be used to protect user interface components in Flex, the user must be authenticated. In Flex, the user can be authenticated through the ChannelSet for accessing BlazeDS services. In the Flex authentication code below a userService remote object is created. This assumes that userService has been configured in BlazeDS. In this case, it is done through the BlazeDS/Spring configuration. The example is very straightforward. The username and password parameters come from a login form and are passed to the authenticate function. On a successful login, the loginResultEvent handler function is called, and post login logic can be invoked.

<mx:AMFChannel id="myamf" uri="http://localhost:8080/spring/messagebroker/amf"/>
<mx:ChannelSet id="channelSet" channels="{[myamf]}"/>
<mx:RemoteObject id="userService" destination="userService" showBusyCursor="true"
channelSet="{channelSet}"/>
<mx:Script>
<![CDATA[
protected function authenticate(username:String, password:String) : void {
var token:AsyncToken = userService.channelSet.login(username, password);
token.addResponder(new ItemResponder(loginResultEvent, loginFaultEvent));
}

private function loginResultEvent(event:ResultEvent, token:AsyncToken):void {
//DO post login stuff
}
]]>
</mx:Script>

The post login logic is covered later in the Loading users and permissions section.

Adding Chimp to your project

Begin with Chimp by adding the SWC file to your Flex application. First, download the chimp.swc file from Google Code. In a standard Flex Builder project, follow these steps to add the file to your project library:

  1. Right click the project name in the Project Explorer view
  2. Select Properties
  3. Select Flex Build Path
  4. Select Library path
  5. Click Add SWC
  6. Browse to chimp.swc (see Figure 1)
  7. Click "Ok"

Adding the chimp.swc library to a Flex project

Figure 1: Adding the chimp.swc library to a Flex project

Next, you need to update your project to keep the metadata used by Chimp. In a standard Flex Builder project, follow these steps to tell the Flex compiler to keep the metadata:

  1. Right click the project name in the Project Explorer view
  2. Select Properties
  3. Select Flex Compiler
  4. Add the following to the Additional Compiler Arguments (See Figure 2):
    -keep-as3-metadata+=Protected
  5. Click OK

Adding the compiler argument

Figure 2: Adding the compiler argument

Loading Chimp in a Flex Application

Now that Chimp is installed in your Flex project, it is time to load the Chimp project inside your Flex application. The key is to load Chimp before your application components are added to the application, because the Flex application system manager's ADDED_TO_STAGE event is used by Chimp to flag components that are to be protected. You see similar approaches to using the system manager in other open source Flex libraries, such as the Swiz framework.

The simplest way to load Chimp before the user interface components is to use the Flex preinitialize event of the application. In production applications, rather than relying on the preinitialize event, it is likely that you will use some sort of view state to prevent components from being added until after the user is authenticated or roles are loaded.

Loading Chimp inside a Flex application is simple:

private function preintializeHandler(event:Event):void {
Chimp.load(null);
}

In the code above, Chimp is loaded in the preinitialize application event handler. A null is passed in for the roles, as they haven't been loaded yet in this example. Loading Chimp at this point allows it to find components annotated with Chimp metadata that require protecting.

Loading users and permissions

Chimp is now added and loaded into the Flex application. Next, the permissions that will be used to determine what the user can see need to be loaded from Spring. Chimp expects generic permissions strings. They could be roles, grants, or anything else that can be returned as strings. In this article, the Spring GrantedAuthorities object will be used to get the user's permissions for use in the Flex application. The code below defines the UserIdentity object, a simple Java class that will be used to return the security information.

public class UserIdentity {

private String username;
private List<String> roles;

public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public List<String> getRoles() {
return roles;
}
public void setRoles(List<String> roles) {
this.roles = roles;
}

}

Here, the UserIdentity object is assembled from the Spring SecurityContextHolder:

public UserIdentity getUserIdentity() { 
UserIdentity ui = new UserIdentity();

//set user name
ui.setUsername(userDao.getUser(SecurityContextHolder.getContext().getAuthentication().getName()));

//set string permissions
List<String> perms = new ArrayList<String>();
GrantedAuthority[] gas = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
for(int i=0; i < gas.length; i++) {
perms.add(gas[i].getAuthority());
}

ui.setRoles(perms);
//return user identity object
return ui;
}

In this example, the Flex application will call the getUserIdentity() method after successfully authenticating the user:

public var userService:RemoteObject; 

private function loginResultEvent(event:ResultEvent, token:AsyncToken):void {
var userIdentityToken:AsyncToken = userService.getUserIdentity();
userIdentityToken.addResponder(new ItemResponder(userIdentityEvent, faultEvent));
}

private function userIdentityEvent(event:ResultEvent, token:AsyncToken):void {
//set user permissions on Chimp
Chimp.updatePerms(event.result.roles);
}

After the user is successfully authenticated, the user identity information is loaded and the permissions are updated on the instance of the Chimp library. This information is used with the metadata to restrict what the user can see in the Flex user interface.

Adding metadata

At this point, Chimp is installed and loaded into the application, and roles have been provided to it by the server. Now, it is time to add metadata to the Flex code to restrict what users can see and do in the user interface. The following is an example of using the Chimp Protected metadata:

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="/2006/mxml">

<mx:Metadata>
[Protected(permissions="admin",notInPermissionAction="removeChild",componentId="box2")]
[Protected(permissions="admin",notInPermissionAction="removeFromLayout",componentId="p2")]
[Protected(permissions="admin",inPermissionAction="visible",componentId="adminButton")]
[Protected(permissions="user",inPermissionAction="enable",componentId="updateButton")]
</mx:Metadata>

<mx:Button id="adminButton" label="Admin Button" visible="false" />
<mx:Button id="updateButton" label="Update Button" enabled="false" />

<mx:HBox>
<mx:Panel id="p1" title="Panel 1" backgroundColor="#FF0000"/>
<mx:Panel id="p2" title="Panel 2" backgroundColor="#00FF00"/>
<mx:Panel id="p3" title="Panel 3" backgroundColor="#0000FF"/>
</mx:HBox>

<mx:TabNavigator id="tabNav" width="300" height="300">
<mx:VBox id="box1" width="100%" height="100%" label="Tab One">
<mx:Text text="first tab" />
</mx:VBox>
<mx:VBox id="box2" width="100%" height="100%" label="Tab Two">
<mx:Text text="second tab" />
</mx:VBox>

<mx:VBox id="box3" width="100%" height="100%" label="Tab Three">
<mx:Text text="third tab" />
</mx:VBox>

</mx:TabNavigator>

</mx:VBox>

Take a closer look at the Protected annotations.

The line below removes the second box in the tab navigator if the "admin" permission is not found. A removeChild is used because a removeFromLayout does not work with the TabNavigator component. The removeFromLayout option is preferred when it works, because it is less aggressive and has more predictable behavior if the "admin" permissions are provided at a later time.

[Protected(permissions="admin",notInPermissionAction="removeChild",componentId="box2")] 

With the following line, if the "admin" permission is not found, the second panel in the HBox is removed from the layout so that it is no longer visible:

[Protected(permissions="admin",notInPermissionAction="removeFromLayout",componentId="p2")]

Below, the adminButton is made visible if the user has the "admin" permission:

 [Protected(permissions="admin",inPermissionAction="visible",componentId="adminButton")]

Finally, the updateButton is enabled if the user has the "user" permission:

 [Protected(permissions="user",inPermissionAction="enable",componentId="updateButton")]

The protected annotation is fairly simple to use. It has the following properties:

  • permissions: The permissions property expects a comma delimited string of the string permissions to use for the protected operation.
  • componentId: This componentId is the string name of the component that is to be protected. This can be omitted or set to ‘this' for the current component. To protect a child, set the componentId to the ‘id' string of the component.
  • notInPermissionAction: The notInPermissionAction is invoked if the user does not have any of the permissions (use only this or inPermissionAction – not both).
  • inPermissionAction: The inPermissionAction is invoked if the user has any of the permissions (use only this or notInPermissionAction – not both).

The notInPermissionAction and inPermissionAction properties invoke actions on the target component. They can take the following values:

  • removeChild : Removes the component completely, by calling ‘comp.parent.removeChild().'
  • removeFromLayout : Use the includeInLayout property to remove components.
  • invisible: Sets the compl.visible property to false.
  • visible: Sets the comp.visible property to true.
  • disable: Sets the comp.enable property to false.
  • enable: Sets the comp.enable property to true.

As you can see, the Chimp library is straightforward to use inside of a Flex application. Once installed and loaded into the application, it provides a simple and elegant way to manage permissions of the view components.

Where to go from here

By using the combination of the Spring BlazeDS Integration and Flexible Chimp projects you can provide comprehensive security for your applications. The Spring BlazeDS project makes it easy to integrate Spring Security with BlazeDS Security, which provides flexibility in defining how users and roles are managed and how authentication is provided for an application. Using Flexible Chimp on the front end provides fine-grained security of the user interface. This combination of projects secures all aspects of authentication, authorization, and access control.

For more information on the Spring BlazeDS Integration Project see the project home page or DZone's Refcard demonstrating how to implement the project.

For more information on the Flexible Chimp project check out Jon Rose's blog (post 1 & post 2).

About the authors

Ryan Knight is a Senior Software Architect at Gorilla Logic where he does Flex and Java consulting. He also is the primary contributor to Anvil Flex, an open source project to help enterprises jump-start their Flex development. He has worked with Java for over 12 years in a variety of roles, from development to consulting.

Jon Rose is an enterprise software consultant and Flex Practice Director at Gorilla Logic, Inc. located in Boulder, Colorado. He is an editor and contributor to InfoQ.com, an enterprise software community. He is the co-host of DrunkOnSoftware.com, a videocast for those who like booze and bits. He has worked with clients large and small in both the private sector and government. His love of solving problems drives him to build quality software.

 

Published at DZone with permission of {{ articles[0].authors[0].realName }}, DZone MVB. (source)

Opinions expressed by DZone contributors are their own.

{{ tag }}, {{tag}},

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}
{{ parent.authors[0].realName || parent.author}}

{{ parent.authors[0].tagline || parent.tagline }}

{{ parent.views }} ViewsClicks
Tweet

{{parent.nComments}}