Because Sébastien Arbogast’s series of articles explains how to configure Flex, BlazeDS, and Spring to work together, I’ll only touch on it briefly here. The first thing to configure is 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>
This part of the web.xml file shows the configuration of the Spring security filter that intercepts all URLs. The web.xml file also configures the BlazeDS service and the Spring context. Refer to the code sample for these sections.
The next step is to configure the URLs and the methods that are secured. The following Spring configuration is part of the Spring-security.xml file that you can also find in the sample code.
<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:intercept-url pattern="/**" filters="none"/>
</security:http>
<security:global-method-security>
<security:protect-pointcut access="ROLE_ADMIN"
expression="execution(* nl.gridshore.samples.books.business.*Manager.store*(..))"/>
<security:protect-pointcut access="ROLE_USER"
expression="execution(* nl.gridshore.samples.books.business.*Manager.obtain*(..))"/>
</security:global-method-security>
<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>
The configuration shows three parts. The first part, security:http, configures the URL-based access control. Spring security has improved tremendously in version 2. Namespace support was introduced along with many sensible defaults. As you can see from the configuration (<security:intercept-url pattern="/**/*.swf" filters="none"/>), I have chosen not to secure the Flex component, so every visitor can download the component. This is the most logical way to set up the login within your Flex application.
The second part configures method level security. You can configure which methods to secure by using aspects and the pointcut expression language. (A detailed description of the expression language is beyond the scope of this article.) If you have a close look, you can see I have secured all methods of objects ending with “Manager” that start with “store”. Only admins can call these methods. All “obtain” methods of the same objects require the user role.
The third part is the authentication provider. For simplicity, I am using the provided in-memory storage. As you can see, there are two users defined, the user and the admin. Admin has two roles, while the user only has the ROLE_USER role. Only the admin can create a new book by calling one of the store methods.
The connection between your Flex client and BlazeDS is specified in two configuration files. The first file is services-config.xml, which contains the configuration of the channels and the factories to create the proxies to the remote objects. I use the same Spring factory described in the Arbogast articles. Using this factory, we have access to the Spring framework configured beans. The services-config.xml file also includes a reference to the other config file, remoting-config.xml. This configuration file contains the destinations, or the actual remote beans, to call. The following code shows the destinations I use in the sample:
<destination id="bookManager">
<properties>
<factory>Spring</factory>
<source>bookManager</source>
</properties>
</destination>
<destination id="authenticationHelper">
<properties>
<source>nl.gridshore.samples.books.web.security.AuthenticationHelper </source>
</properties>
</destination>
The bookManager destination is a Spring bean that exposes the methods the user can call to obtain books and to create new books. As you can see, I use the Spring factory to have access to this destination. The authenticationHelper destination is not a Spring bean, though It does provide a hook into the framework. This bean is used to authenticate a user and obtain the roles of the authenticated user. The next block of code shows the method that accepts the username and password and then asks the authentication manager to authenticate a principal with these credentials.
public AuthorizationData authenticatePrincipal(String usr, String pwd) {
ApplicationContext appContext =WebApplicationContextUtils.getWebApplicationContext(
FlexContext.getServletConfig().getServletContext());
AuthenticationManager manager =
(AuthenticationManager)appContext.getBean("_authenticationManager");
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
new UsernamePasswordAuthenticationToken(username,password);
Authentication authentication = manager.authenticate(usernamePasswordAuthenticationToken);
SecurityContextHolder.getContext().setAuthentication(authentication);
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 name = SecurityContextHolder.getContext().getAuthentication().getName();
return new AuthorizationData(grantedRoles,name);
}
Because this is the most important part to understand of the integration with Spring security, I’m going to break up the code to explain what is happening.
WebApplicationContextUtils.getWebApplicationContext(
FlexContext.getServletConfig().getServletContext());
Using the FlexContext class we can access the current ServletContext, which provides access to the Spring framework application context. The sample uses the namespace support of the Spring Security configuration. Using convention over configuration, an authenticationManager bean is registered in the Spring context using the name _authenticationManager.
AuthenticationManager manager =
(AuthenticationManager)appContext.getBean("_authenticationManager");
The next step is to create an authentication token based on the provided username and password. This token is used to authenticate the principal by calling the authenticate method on the authentication manager. The returned authentication is added to the session to be remembered and used when the next call is made.
Authentication authentication = manager.authenticate(usernamePasswordAuthenticationToken); SecurityContextHolder.getContext().setAuthentication(authentication);
In the next step the Flex client is provided with the roles for which the authenticated user is authorized. After obtaining the roles and the actual username, the application creates an AuthorizationData object that is then returned to the caller and to the Flex client using BlazeDS.
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 name = SecurityContextHolder.getContext().getAuthentication().getName();
return new AuthorizationData(grantedRoles,name);