Acegi Security System provide a powerful, flexible security solution for enterprise web software. However, it is designed mostly with traditional form-based and page-based web applications in mind. When it is used with an Ajax framework like ZK, there will need some special treatment to access the authentication facility. In this article, we will show you how to configure the Acegi Security System with ZK.
There are majorly two issues regarding using Acegi with ZK.
- The Acegi carries its security context as a ThreadLocal variable so legacy single-thread web application can access it any time. However, ZK is a multi-threads system when processing ZK events. There will be problems for a new event thread to get the Acegi's ThreadLocal security context. This is the first issue we have to handle.
- The second issue comes from the Ajax applications' natural. An Ajax web program allows changing part of the web page without "refreshing" the whole one; thus end users get the same friendly feeling of using a desktop application. When an end user presses a button on the page and triggers some "operation" that needs special authority, the application cannot just "refresh" the whole page to a "login" page and request the end user to login. This would cause user panic since all information on the original page is lost in one click. This is the second issue we have to deal.
Solving the first issue is easy. We just write an EventThreadInit and EventThreadCleanup listener to copy the Acegi's ThreadLocal security context between the servlet and ZK event threads and then configure it in WEB-INF/zk.xml like following. The security context would then be carried around threads without problem.
<listener> <description>Acegi SecurityContext Handler</description> <listener-class>org.zkoss.zkplus.acegi.AcegiSecurityContextListener</listener-class> </listener>
The second issue is tougher. In ZK, except the loading of the ZK pages, all events triggered by end users are in fact Ajax XMLHttpRequests. When loading ZK's pages, it is the same as loading other legacy web applications' pages. We can just use the same way as taught by Acegi's tutorial to configure the "secured" and "public" pages based on the url patterns. However, for event triggered by end user, there might be some "operations" (secured methods) that needs special authorities. We cannot just let Acegi System redirect the ZK page to a login page and lost all information of the original page. A better behavior for ZK is to "pop" up a modal login window so end users can login on the way.
Following, we base on the tutorial example provided by Acegi to show the ZK's new feature. All pages would be changed to .zul and use zul components to demonstrate the possibility. We also add a special authorized Method on "Home Page" to show how the "pop" up modal login window is shown. You can download the test war file here. Just deploy it and you can start to try it.
web.xml ... <context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/applicationContext-acegi-security.xml </param-value> </context-param> <filter> <filter-name>Acegi Filter Chain Proxy</filter-name> <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class> <init-param> <param-name>targetBean</param-name> <param-value>filterChainProxy</param-value> </init-param> </filter> <filter-mapping> <filter-name>Acegi Filter Chain Proxy</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> ...
In applicationContext-acegi-security.xml the "page loading" authentication and "event handling" authentication is split into two parts by the url pattern. Note that all ZK's event request url (XMLHttpRequest) is in the pattern of "/zkau/**". Here the "zkau" is as defined in "update-uri" of the "zkLoader" in web.xml. The other defintion for "page loading" authentication is virtually the same as in the Acegi's sample tutorial (except the page is changed from .jsp to .zul).
For the "event handling" authentication, we have to define an extra "zkFilterChainProxy" bean and other supporting beans. They are named as "zkXxx" to help developers to distinguish them from Acegi's original ones. The zkFilterChainProxy would be used by ZK engine to do the event handling authentication.
applicationContext-acegi-security.xml ... <bean id="filterChainProxy" class="org.acegisecurity.util.FilterChainProxy"> <property name="filterInvocationDefinitionSource"> <value> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT /zkau/**=httpSessionContextIntegrationFilter, ... /**=httpSessionContextIntegrationFilter, ... </value> </property> </bean> ... <!-- Support ZK modal login window when access secured method call in event handling --> <bean id="zkFilterChainProxy" class="org.acegisecurity.util.FilterChainProxy"> <property name="filterInvocationDefinitionSource"> <value> CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON PATTERN_TYPE_APACHE_ANT /zkau/**=zkAuthenticationProcessingFilter, ... </value> </property> </bean> <bean id="zkAuthenticationProcessingFilter" class="..."> ... <!-- other zkXxx bean defintions --> ...
Something worth noting is that the way of collecting "username", "password", and "remember_me" in "event handling" authentication is different from the legacy "page loading" authentication. That is, you have to design a login page and an accessDenied page for each case.
Acegi security system is a powerful security system. I just scratch the surface of it. The current implementation might be improved further. However, I think it should fulfill most requirements now. The next step might be trying to merge the two different login windows into one and see if we can decrease some more zkXxx specific beans.
I hope you enjoy this ZK's new feature and feedback us your opinions so ZK can be further improved.
Download the example code here.
|Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.|