Making Spring Security Work with ZK

From Documentation
Revision as of 07:17, 8 December 2010 by Char (talk | contribs) (→‎Rewrite /login.jsp to /login.zul)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
DocumentationSmall Talks2010AprilMaking Spring Security Work with ZK
Making Spring Security Work with ZK

Author
Henri Chen, Principal Engineer, Potix Corporation
  • Ashish Dasnurkar, Engineer, Potix Corporation
Date
September 15, 2008
  • Updated April 13, 2010 to make it work with ZK Spring integration library 3.0RC
Version
Applicable to ZK 3.0.8 and later.
Applicable to ZK 3.5.0 and later.
Applicable to ZK 5.0. and later
Applicable to Spring Security 3.0 and later


Introduction

Spring Security is the next generation security system for the Spring Framework. It has added many new features since its predecessor Acegi Security System. There has been questions regarding how to make Spring Security work with ZK Ajax framework and here is an example that demonstrates how to make it work step-by-step.

Demo

The Example

To make things simple, I borrowed the tutorial sample(spring-security-3.0.2.RELEASE\dist\spring-security-samples-tutorial-3.0.2.RELEASE.war) provided by Spring Security 3.0 . I then rewrite the original pure Jsp pages to ZK pages and add necessary ZK libraries and configurations to show you how these two frameworks can work together seamlessly. The tutorial sample demonstrates many basic concepts of the security system including form-based authentication mechanism with remember-me and annotated method authorization, etc.. I will not go to details in Spring Security's mechanism in this article. Rather, I will focus on the steps to "make it work" and demonstrate the rewritten ZK pages. If you are interested in the behind-the-scene things, you can check them on Spring Security web site.


Deploy the war file

The easiest way to try the sample is to deploy the war file to your servlet container. In this article, I use Tomcat 5.5. It is simple. Just copy the file spring-security-samples-tutorial-3.0.2.RELEASE.war to the webapps folder of Tomcat server and restart Tomcat. The tutorial war file shall deploy and create a new folder spring-security-samples-tutorial-3.0.2.RELEASE (same name as the file) under folder webapps. Now visit http://localhost:8080/spring-security-samples-tutorial-3.0.2.RELEASE.war/ and you shall see following page.

/index.jsp'
Zkspringsec1-1.png


Configure the /WEB-INF/web.xml file

Now lets start walking through the configurations to see how to make Spring Security works with ZK web application. The /WEB-INF/web.xml is the major configuration file that tells Tomcat what to do. To make Tomcat work with Spring Security, you shall configure it as following. These shall be already specified in the tutorial sample codes, so basically you just don't have to change any thing.

/WEB-INF/web.xml

    ...
    <!--
      - Location of the XML file that defines the root application context
      - Applied by ContextLoaderListener.
      -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            ...
            /WEB-INF/applicationContext-security.xml
        </param-value>
    </context-param>

    <!--
      - Loads the root application context of this web app at startup.
      - The application context is then available via
      - WebApplicationContextUtils.getWebApplicationContext(servletContext).
      -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!--
      - Spring Security Filter Chains
      -->
    <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>

    ...
    <!--
      - ZK configurations
      -->
    <listener>
        <description>Used to cleanup when a session is destroyed</description>
        <display-name>ZK Session Cleaner</display-name>
        <listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class>
    </listener>
    <servlet>
        <description>ZK loader for evaluating ZK pages</description>
        <servlet-name>zkLoader</servlet-name>
        <servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>
        <init-param>
            <param-name>update-uri</param-name>
            <param-value>/zkau</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>zkLoader</servlet-name>
        <url-pattern>*.zul</url-pattern>
    </servlet-mapping>
    <servlet>
        <description>The asynchronous update engine for ZK</description>
        <servlet-name>auEngine</servlet-name>
        <servlet-class>org.zkoss.zk.au.http.DHtmlUpdateServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>auEngine</servlet-name>
        <url-pattern>/zkau/*</url-pattern>
    </servlet-mapping>
    ...
    <welcome-file-list>
        index.zul
    </welcome-file-list>


  • Spring Security configuration
  1. The <context-param> tells Spring Framework context loader where to find the context parameter files.
  2. The <listener> ContextLoaderListener defines the Spring Framework context loader that will load and parse the context parameter files defined in the parts.
  3. The <filter> springSecurityFilterChain defines the entry servlet filter for Spring Security filter chains.
  4. The <filter-mapping> tells what pages (via URL pattern) shall go through and checked by the Spring Security filter chains.

The configurations specific to Spring Security is actually the last two items(item 3 and 4). The filter name springSecurityFilterChain is important. You shall just copy them as is. The item 1 and 2 are generic configuration to make Spring Framework work. Note that the /WEB-INF/applicationContext-security.xml defined in item 1 is the Spring Security specific configuration file and you can include other business specific spring configuration files here, too. I will explain it later.


  • ZK Ajax framework configuration
  1. The <listener> HttpSessionListener is used to cleanup the session when it is destroyed.
  2. The <servlet> zkLoader servlet is used to load a ZK page.
  3. The <servlet> auEngine servlet is used to update a ZK page (Ajax update).
  4. And you can see the <servlet-mapping> for zkLoader is specific to *.zul pages and all Ajax XMLHttpRequest url starts with the /zkau/* pattern.


Copy library jar files to /WEB-INF/lib

After done with the /WEB-INF/web.xml, now is the turn for required library jars. For Spring Security to work, we shall copy following jars to /WEB-INF/lib.

-Spring Security library jar files

aopalliance-1.0.jar
aspectjweaver-1.6.8.jar
commons-codec-1.3.jar
commons-collections-3.2.jar
commons-lang.jar
commons-logging-1.1.1.jar
jstl-1.1.2.jar
log4j-1.2.14.jar
spring-security-acl-3.0.2.RELEASE.jar
spring-security-config-3.0.2.RELEASE.jar
spring-security-core-3.0.2.RELEASE.jar
spring-security-taglibs-3.0.2.RELEASE.jar
org.springframework.aop-3.0.2.RELEASE.jar
org.springframework.asm-3.0.2.RELEASE.jar
org.springframework.beans-3.0.2.RELEASE.jar
org.springframework.context-3.0.2.RELEASE.jar
org.springframework.context.support-3.0.2.RELEASE.jar
org.springframework.core-3.0.2.RELEASE.jar
org.springframework.expression-3.0.2.RELEASE.jar
org.springframework.transaction-3.0.2.RELEASE.jar
org.springframework.web-3.0.2.RELEASE.jar
org.springframework.web.servlet-3.0.2.RELEASE.jar
standard-1.1.2.jar

And the following is for ZK framework. Basically, just follow the ZK Quick Start Guide. Copy all /dist/lib/*.jar, /dist/lib/ext/*.jar, /dist/lib/zkforge/*.jar to /WEB-INF/lib

ZK library jar files

bsh.jar
commons-collections.jar
commons-fileupload.jar
commons-io.jar
commons-logging.jar
fckez.jar
Filters.jar
gmapsz.jar
groovy.jar
itext.jar
jasperreports.jar
jcommon.jar
jfreechart.jar
jruby.jar
js.jar
jxl.jar
jython.jar
mvel.jar
ognl.jar
poi.jar
timelinez.jar
zcommon.jar
zcommons-el.jar
zhtml.jar
zk.jar
zkex.jar
zkmax.jar
zkplus.jar
zml.jar
zul.jar
*zuljsp.jar
zweb.jar

*This is ZK JSP Tags libraries. We will use it in the sample codes.

Configure the /WEB-INF/zk.xml file: the ThreadLocal issue (IMPORTANT!)

The Spring Security engine holds in the servlet thread a ThreadLocal variable contextHolder for each request so the engine can refer it from time to time. This ThreadLocal variable contains important security related information and shall be accessible any time. However, ZK by default spawns a new event thread for each event handling job. That is, the ZK event thread will not have such important contextHolder ThreadLocal variable and the original assumption is broken.

There are two ways to solve this issue. You can choose either one and configure it in the /WEB-INF/zk.xml file.

1. Disable the ZK event thread mechanism entirely. This tells the ZK framework NOT to spawn a new event thread for event handling and everything back to normal.
<system-config>
    <disable-event-thread/>
</system-config>

Note: ZK 5.0 and later disables event thread by default.

2. Use ZK provided ThreadLocalListener utitlity to copy the contextHolder ThreadLocal variable over from servlet thread to ZK event thread and vice versa.
<listener>
    <description>ThreadLocal Synchronization Listener</description>
    <listener-class>org.zkoss.zkplus.util.ThreadLocalListener</listener-class>
</listener>

<preference>
    <name>ThreadLocal</name>
    <value>
         org.springframework.security.context.ThreadLocalSecurityContextHolderStrategy=contextHolder
    </value>
</preference>

Note that the ZK event thread mechanism is the base of the ZK modal window such as Messagebox. That is, if you disabled the event thread mechanism as said in item 1, you could not use ZK modal window, either. Choose either solution per your requirements.

Configure the /WEB-INF/applicationContext-security.xml

This file tells Spring Security engine what to do. This might be the most important file for Spring Security system. The file uses the new simplified namespace-based configuration syntax and shrinks used to be hundreds of lines of old configuration codes into just less than 10 lines.

/WEB-INF/applicationContext-security.xml

<beans:beans xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:zksp="http://www.zkoss.org/2008/zkspring/security"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd">

	<global-method-security pre-post-annotations="enabled">
		<!-- AspectJ pointcut expression that locates our "post" method and applies security that way
		<protect-pointcut expression="execution(* bigbank.*Service.post*(..))" access="ROLE_TELLER"/>
		-->
	</global-method-security>

    <http auto-config="true" use-expressions="true">
        <intercept-url pattern="/secure/extreme/**" access="hasRole('ROLE_SUPERVISOR')"/>
        <intercept-url pattern="/secure/**" access="isAuthenticated()" />
        <intercept-url pattern="/**" access="permitAll" />
        <!--  Use a custom login page -->
 		<form-login login-page="/login.zul" authentication-failure-url="/login.zul?login_error=1"/>
     </http>

    <!--
    Usernames/Passwords are
        rod/koala
        dianne/emu
        scott/wombat
        peter/opal
    -->
    <authentication-manager>
    <authentication-provider>
        <password-encoder hash="md5"/>
        <user-service>
            <user name="rod" password="a564de63c2d0da68cf47586ee05984d7" authorities="ROLE_SUPERVISOR, ROLE_USER, ROLE_TELLER" />
	        <user name="dianne" password="65d15fe9156f9c4bbffd98085992a44e" authorities="ROLE_USER,ROLE_TELLER" />
            <user name="scott" password="2b58af6dddbd072ed27ffc86725d7d3a" authorities="ROLE_USER" />
            <user name="peter" password="22b5c9accc6e1ba628cedc63a72d57f8" authorities="ROLE_USER" />
	    </user-service>
	</authentication-provider>
	</authentication-manager>

</beans:beans>


1. <global-method-security pre-post-annotations="enabled"> tells the Spring Security engine that we will use Spring Security's pre and post invocation Java annotations (@PreFilter, @PreAuthorize, @PostFilter, @PostAuthorize) to secure service layer methods.
2. <http auto-config="true"> tells the Spring Security engine to use the default configured security filter chains and services. This single line covers 90% of the configurations.
  • <http use-expressions="true"> enables the use of expressions in the 'access' attributes in elements rather than the traditional list of configuration attributes. Defaults to 'false'. If enabled, each attribute should contain a single boolean expression. If the expression evaluates to 'true', access will be granted.
  • The <intercept-url pattern="..." access="..."> Specifies the access attributes and/or filter list for a particular set of URLs. Access configuration attribute may specify expression that evaluates to a boolean and/or specific authority roles. The most specific pattern of URL shall be put at the top since Spring Security engine checks one by one until the URL is matched with the pattern.
  • The <form-login login-page="/login.zul"/> here tells that we want to use the specified /login.zul page as the user login form page. If you did not specify this, the security system will use its internal one automatically.
3. The <authentication-provider> gives an in-memory user/password list. This is generally used for testing and simple cases. You can implement your own user/password provider mechanism per your requirement in different conditions (e.g. use database, etc.). Note that the long integer password="xxxxxxxxxxx..." is the md5 result of the password string that avoids storing plain text in the configuration file. Note that in Spring Security 3.0 namespace definition <authentication-provider /> element is now child element of < authentication-manager /> element.

Until here, it is the end of the configuration. In following case, I will rewrite original JSP pages to ZK pages and show you how ZK and Spring Security work together.

bean configuration file bank-servlet.xml and definition

-- bank-servlet.xml --
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

	<context:component-scan base-package="bigbank.web"/>
    <bean name="/listAccounts.html" class="bigbank.web.ListAccounts">
        <constructor-arg ref="bankService"/>
    </bean>

<!--     <bean name="/post.html" class="bigbank.web.PostAccounts">
        <constructor-arg ref="bankService"/>
    </bean>
 -->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".zul"/>
    </bean>

</beans>

Here I have modified bank-servlet.xml to use Spring 3.0 introduced Java annotations to define PostAccounts Spring bean instead of defining it here in xml form. But for Spring to detect this bean first I need to enable component scan mechanism.

  • First specify Spring context namespace schema in the namespace declaration at the top by refering to spring-context.xsd
  • Second define PostAccounts Spring bean with @Controller, @RequestMapping Java annotations as shown below.
-- PostAccounts.java
@Controller
public class PostAccounts  {
    private BankService bankService;

    @Autowired
    public PostAccounts(BankService bankService) {
        Assert.notNull(bankService);
        this.bankService = bankService;
    }
    @RequestMapping(value="/post.html", method=RequestMethod.GET)
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // Actual business logic
        Long id = ServletRequestUtils.getRequiredLongParameter(request, "id");
        Double amount = ServletRequestUtils.getRequiredDoubleParameter(request, "amount");
        Account a = bankService.readAccount(id);
        bankService.post(a, amount);

        return new ModelAndView("redirect:listAccounts.html");
    }
}
  • @Controller annotation at the top makes PostAccounts a controller bean
  • I mark PostAccounts constrctor with @Autowired annotation to inject BankService bean
  • Finally I annotate handleRequest() method with @RequestMapping annotation to define URL pattern that will be governed by this controller.

Rewrite /index.jsp to /index.zul

This is easy. I lay out the screen with <grid> components and use <button href="..."> for hyperlinking to other pages. Compare it with original index.jsp shown above.

/index.zul
Zkspringsec1-2.png
/index.zul

...
<grid>
    ...
    <rows>
        <row>
            Any one can list accounts.<button label="Go!" href="listAccounts.html"/>
        </row>
        <row>
            Your principal object is ...:<label value="${desktop.execution.userPrincipal.name}"/>
        </row>
        <row>
            Secure page<button label="Go!" href="secure/secure.jsp"/>
        </row>
        <row>
            Extremely secure page<button label="Go!" href="secure/extreme/extreme.jsp"/>
        </row>
    </rows>
</grid>
...

This page is the entry page for this sample example. The button in first row will list all accounts. The second show the currently login user name(empty if not login yet). Press the button in third row will access a secure page whilst press the button in last row will access an extreme secure page(need ROLE_SUPERVISOR permission).


Rewrite /login.jsp to /login.zul

This is the customized login page. Spring Security will show this login page when it is necessary. Again, I lay out the screen with grid and mix html <h:form> , <h:input ...> and ZK components together. This is a typical practice to mix ZK components with legacy servlet and form-based page. For details, you can refer this article. A normal login page will definitely not have the "Valid users" part. This is a tutorial example... In this example, the user rod is the one with ROLE_SUPERVISOR permission, dianne is the one with ROLE_TELLER permission, and the other two are with ROLE_USER permission. You can check /WEB-INF/applicationContext-security.xml for details. Test the example to see how each user can access each page.

/login.zul
Zkspringsec1-3.png
/login.zul

...
<h:form id="f" name="f" action="j_spring_security_check" method="POST"
    xmlns:h="http://www.w3.org/1999/xhtml">
    <grid>
        <rows>
            <row>User: <textbox id="u" name="j_username"/></row>
            <row>Password: <textbox id="p" type="password" name="j_password"/></row>
            <row>
                <checkbox id="r" name="_spring_security_remember_me"/>
                Don't ask for my password for two weeks
            </row>
            <row spans="2"><hbox>
                <h:input type="submit" value="Submit Query"/>
                <h:input type="reset" value="Reset"/>
            </hbox></row>
        </rows>
    </grid>
</h:form>
...

Rewrite /WEB-INF/jsp/listAccounts.jsp to /WEB-INF/jsp/listAccounts.zul

This page is used to list all accounts. It is shown when the user press the first button in the home page(/index.zul). If you check carefully, you will find it actually visits /listAccounts.html. Why visiting an .html page at root turn out responding with a .zul page inside /WEB-INF/jsp/. This has something to do with the forwarding mechanism embedded in Spring MVC. If you are interested, please check the /WEB-INF/bank-servlet.xml, /src/bigbank/web/ListAccounts.java, and /src/bigbank/BankService.java source files. This is not directly related to the Spring Security so I will just brief a little bit.

  1. The request for /listAccounts.html
  2. Per the difinition in /WEB-INF/bank-servlet.xml, the handleRequest method of the ListAccounts controller is called.
  3. And inside that method it calls bankService.findAccounts() to populate a variable accounts.
  4. At bankService.findAccounts(), we can use Spring Security annotation @Secured to protect the calling of that method. Here we are not so any one can access this method.
  5. Then the url is forwarded to /WEB-INF/jsp/listAccounts.zul per the pattern definition in /WEB-INF/bank-servlet.xml

As for the listAccounts.zul, you can see that we then iterate the accounts collection to show each Account as a <row> in the <grid>.

/WEB-INF/jsp/listAccounts.zul
Zkspringsec1-4.png
/WEB-INF/jsp/listAccounts.zul

...
<grid>
    <rows>
        <row forEach="${accounts}">
            <label value="${each.id}"/>
            <label value="${each.holder}"/>
            <label value="${each.balance}"/>
            <button label="-$20" href="/post.html?id=${each.id}&amount=-20.00"/> 
            <button label="-$5" href="/post.html?id=${each.id}&amount=-5.00"/> 
            <button label="+$5" href="/post.html?id=${each.id}&amount=5.00"/> 
            <button label="+$20" href="/post.html?id=${each.id}&amount=20.00"/> 
        </row>
    </rows>
</grid>
...

In this page, end users can press the "-$20", "-$5", "+$5", "+$20" button to add/minus the total amount of each Account and the updated value would be refreshed after. How does this work? Take a look of the code <button ... href="post.html?id=..."/>. This is another place that Spring MVC get involved. Check the /WEB-INF/bank-servlet.xml, /src/bigbank/web/PostAccounts.java, and /src/bigbank/BankService.java source files for details if you are interested.

  1. The request for "/post.html?id=..." when the button is clicked.
  2. Per the definition of PostAccounts Spring bean , the handleRequest method of the PostAccounts controller is called.
  3. And inside that method it calls bankService.readAccount() and bankService.post() to modify the account amount.
  4. At bankService.readAccount() and bankServer.post(), we use Spring Security annotation @PreAuthorize to protect the calling of post(). Here the bankServer.post() is protected by ROLE_SUPERVISOR, ROLE_TELLER and (#account.balance + #amount >= -#account.overdraft) expression. That is, only user with either ROLE_SUPERVISOR or ROLE_TELLER permission "and" if balance + amount >= -overdraft expression holds true then post() is allowed to be executed.
  5. Then the url is redirect back to /listAccounts.html as required in the handleRequest method of the PostAccounts controller.
  6. The /listAccount.html is then refreshed as we have described.

Rewrite /secure/index.jsp

/secure/index.jsp
Zkspringsec1-5.png
/secure/index.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ taglib prefix="z" uri="http://www.zkoss.org/jsp/zul"  %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<html>
<body>
<z:page>
<z:window title="Secure Page" border="normal" width="500px">
<p>
This is a protected page. You can get to me if you've been remembered,
or if you've authenticated this session.
</p>

<sec:authorize ifAllGranted="ROLE_SUPERVISOR">
    You are a supervisor! You can therefore see the <a href="extreme/index.jsp">extremely secure page</a>.<br/><br/>
</sec:authorize>

<h4>Properties obtained using <sec:authentication /> tag</h4>
<z:grid>
    <z:columns>
        <z:column label="Tag"/>
        <z:column label="Value" width="50px"/>
    </z:columns>
    <z:rows>
        <z:row><z:label value="<sec:authentication property='name' />"/><sec:authentication property="name"/></z:row>
        <z:row><z:label value="<sec:authentication property='principal.username' />"/><sec:authentication property="principal.username"/></z:row>
        <z:row><z:label value="<sec:authentication property='principal.enabled' />"/><sec:authentication property="principal.enabled"/></z:row>
        <z:row><z:label value="<sec:authentication property='principal.accountNonLocked' />"/><sec:authentication property="principal.accountNonLocked"/></z:row>
    </z:rows>
</z:grid>
<z:separator bar="true"></z:separator>
<z:button label="Home" href="../"/>
<z:button label="Logout" href="../j_spring_security_logout"/>
</z:window>
</z:page>
</body>
</html>

This page is a little bit special. The original JSP uses some Spring Security <sec:...> tags to control the visibilities of some parts of this page and fetch security related information. I have to preserve these <sec:...> functions whilst still using ZK components. How do I make it? I use the ZK JSP Tags to handle this case. ZK JSP Tags provides a straightforward way of enriching legacy JSP pages and can be integrated seamlessly with other JSP tags and solutions.

  1. The <!DOCTYPE ...> is important for Internet Explorer browser. Just copy as is.
  2. The <%@ taglib prefix="z" uri="http://www.zkoss.org/jsp/zul" %> is the declaration for ZK JSP Tags. I generally prefix it with "z".
  3. All other ZK <z:...> component tags used must be enclosed in a <z:page> tags.
  4. And you can mix other JSP tags and HTML tags inside without problems.

As you can see, this is probably the most easy way to enrich JSP pages.

Back to the Spring Security itself. The <sec:authorize ifAllGranted="ROLE_SUPERVISOR"> tag tells the Spring Security engine that until the user is granted with ROLE_SUPERVISOR permission, the enclosed content "You are a supervisor! ..." is not rendered. And the <sec:authentication property="principal.username"> would fetch the username of currently login principal, etc. There are other useful security tags. Check the Spring Security web site for details.


Rewrite /secure/extreme/index.jsp

/secure/extreme/index.jsp
Zkspringsec1-6.png

This page is protected and only user with ROLE_SUPERVISOR permission is allowed to access it. It like the /secure/index.jsp uses some Spring Security <sec:...> tags. Again, I use the ZK JSP Tags to enrich it with ZK components.

/secure/extreme/index.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ taglib prefix="z" uri="http://www.zkoss.org/jsp/zul"  %>
<%@ taglib prefix="authz" uri="http://www.springframework.org/security/tags" %>
<html>
<body>
<z:page>
    <z:window title="VERY Secure Page" border="normal" width="500px">
    This is a protected page. You can only see me if you are a supervisor.

    <authz:authorize ifAllGranted="ROLE_SUPERVISOR">
       You have "ROLE_SUPERVISOR" (this text is surrounded by <authz:authorize> tags).
    </authz:authorize>
    <z:separator bar="true" spacing="10px"/>
    <z:hbox>
    <z:button label="Home" href="../../"/>
    <z:button label="Logout" href="../../j_spring_security_logout"/>
    </z:hbox>
    </z:window>
</z:page>
</body>
</html>


Summary

Spring Security is a powerful security system for Web applications. It secures the URL pages and service layer method calls with very simple configurations and annotations. ZK pages can be easily protected by the Spring Security system and ZK JSP Tags provides a straightforward way for you to mix ZK tags and Spring Security tags together seamlessly.

In this article we only discuss about traditional page-based Web applications. That might not mean anything if we cannot deal with Ajax kind of applications. For example, in the middle of a working page, if an end user is requested to login half way, it is better to pop up a login window rather than show author login page and force the end user to leave the current working one. To achieve such interactive and responsive way of handling authentications and securities, the ZK framework and Spring Security system would need more co-operations. I will talk about that in the next article regarding this topic.

Download

  • Download the ZK Spring Integration Library 1.1.0 example codes(.war file).
  • Download the ZK Spring Integration Library 3.0RCexample codes(.war file)




Copyright © Potix Corporation. This article is licensed under GNU Free Documentation License.