Revision history [back]

click to hide/show revision 1
initial version

asked 2015-11-03 16:17:45 +0800

ifmis gravatar image ifmis

How to implement single sign on(SSO) using Apache Shiro on zk

Hello,

I am currently working on a project which uses Spring in backend and ZK on frontend and its security by Apache Shiro.

Now am in demand of implementing Single Sign On as it is composed of many modules each deployable independently. I tried to do a deep search on internet and I found some resources and articles showing how to achieve that. Unfortunately it didn't help me.

Below are the articles I used:

  1. #support.stormpath.com/hc/en-us/articles/203815036-Can-I-SSO-between-multiple-Wars-in-the-same-servlet-with-Stormpath-and-Apache-Shiro-#
  2. #shiro-user.582556.n2.nabble.com/Shiro-and-multiple-wars-within-the-same-Servlet-Container-td5560737.html#a5563334#

Below are my configurations. Please check if I am doing wrong somewhere.

I welcome any helpful suggestion.

Spring config

<beans xmlns="......&gt;&lt;/p&gt; &lt;pre&gt;&lt;code&gt;&lt;bean id=" myrealm"="" class="myRealmClass" &gt;="" &lt;property="" name="cachingEnabled" value="true" &gt;="" &lt;property="" name="authenticationCachingEnabled" value="true" &gt;="" &lt;!--="" &lt;property="" name="authenticationCacheName" value="authenticationCache" &gt;="" --&gt;="" &lt;property="" name="authorizationCachingEnabled" value="true" &gt;="" &lt;!--="" &lt;property="" name="authorizationCacheName" value="authorizationCache" &gt;="" --&gt;="" &lt;="" bean&gt;="" &lt;bean="" id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" &gt;="" &lt;property="" name="sessionMode" value="native" &gt;="" &lt;property="" name="realm" ref="myRealm" &gt;="" &lt;property="" name="sessionManager" ref="sessionManager" &gt;="" &lt;property="" name="cacheManager" ref="cacheManager" &gt;="" &lt;property="" name="rememberMeManager" ref="rememberMeManager" &gt;="" &lt;="" bean&gt;="" &lt;!--="" ehcache="" --&gt;="" &lt;bean="" id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager" &gt;="" &lt;property="" name="cacheManagerConfigFile" value="classpath:ehcache.xml" &gt;="" &lt;="" bean&gt;="" &lt;bean="" id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" &gt;="" &lt;!--="" cookie="" --&gt;="" &lt;bean="" id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie" &gt;="" &lt;constructor-arg="" value="sid" &gt;="" &lt;property="" name="httpOnly" value="true" &gt;="" &lt;property="" name="maxAge" value="180000" &gt;="" &lt;="" bean&gt;="" &lt;bean="" id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie" &gt;="" &lt;constructor-arg="" value="rememberMe" &gt;="" &lt;property="" name="httpOnly" value="true" &gt;="" &lt;property="" name="maxAge" value="2592000" &gt;&lt;!--="" 30天="" --&gt;="" &lt;="" bean&gt;="" &lt;bean="" id="cookie" class="org.apache.shiro.web.servlet.SimpleCookie" &gt;="" &lt;property="" name="name" value="SSOCookie" &gt;="" &lt;property="" name="path" value="/" &gt;="" &lt;property="" name="domain" value="localhost" &gt;="" &lt;="" bean&gt;="" &lt;!--="" rememberme="" --&gt;="" &lt;bean="" id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager" &gt;="" &lt;property="" name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}" &gt;="" &lt;property="" name="cookie" ref="rememberMeCookie" &gt;="" &lt;="" bean&gt;="" &lt;bean="" id="onlineSessionFactory" class="org.apache.shiro.session.mgt.SimpleSessionFactory" &gt;="" &lt;!--="" dao="" --&gt;="" &lt;bean="" id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO" &gt;="" &lt;property="" name="activeSessionsCacheName" value="shiro-activeSessionCache" &gt;="" &lt;property="" name="sessionIdGenerator" ref="sessionIdGenerator" &gt;="" &lt;="" bean&gt;="" &lt;bean="" id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler" &gt;="" &lt;property="" name="sessionValidationInterval" value="1800000" &gt;="" &lt;property="" name="sessionManager" ref="sessionManager" &gt;="" &lt;="" bean&gt;="" &lt;bean="" id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager" &gt;="" &lt;property="" name="globalSessionTimeout" value="1800000" &gt;="" &lt;property="" name="sessionFactory" ref="onlineSessionFactory" &gt;="" &lt;property="" name="deleteInvalidSessions" value="true" &gt;="" &lt;property="" name="sessionValidationSchedulerEnabled" value="true" &gt;="" &lt;property="" name="sessionValidationScheduler" ref="sessionValidationScheduler" &gt;="" &lt;property="" name="sessionDAO" ref="sessionDAO" &gt;="" &lt;property="" name="sessionIdCookieEnabled" value="true" &gt;="" &lt;property="" name="sessionIdCookie" ref="cookie" &gt;="" &lt;="" bean&gt;="" &lt;!--="" secure="" spring="" remoting:="" ensure="" any="" spring="" remoting="" method="" invocations="" --&gt;="" &lt;!--="" can="" be="" associated="" with="" a="" subject="" for="" security="" checks.="" --&gt;="" &lt;bean="" id="secureRemoteInvocationExecutor" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor" &gt;="" &lt;property="" name="securityManager" ref="securityManager" &gt;="" &lt;="" bean&gt;="" &lt;!--="" securityutils.setsecuritymanager(securitymanager)="" --&gt;="" &lt;bean="" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" &gt;="" &lt;property="" name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager" &gt;="" &lt;property="" name="arguments" ref="securityManager" &gt;="" &lt;="" bean&gt;="" &lt;bean="" id="casFilter" class="org.apache.shiro.cas.CasFilter" &gt;="" &lt;property="" name="failureUrl" value="/login.zul" &gt;="" &lt;="" bean&gt;="" &lt;!--="" shiro="" web="" --&gt;="" &lt;bean="" id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" &gt;="" &lt;property="" name="securityManager" ref="securityManager" &gt;="" &lt;property="" name="successUrl" value="/index.zul" &gt;="" &lt;="" bean&gt;="" &lt;!--="" shiro="" --&gt;="" &lt;bean="" id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" &gt;="" &lt;bean="" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" &gt;="" &lt;bean="" class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor" &gt;="" &lt;property="" name="securityManager" ref="securityManager" &gt;="" &lt;="" bean&gt;="" <="" code="">

</beans>

ehCache.xml

<ehcache xmlns:xsi="...." xsi:nonamespaceschemalocation="ehcache.xsd" updatecheck="true" monitoring="autodetect" dynamicconfig="true">

<diskStore path="java.io.tmpdir" />

<cacheManagerPeerProviderFactory
        class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
        properties="peerDiscovery=automatic,
                    multicastGroupAddress=230.0.0.1,
                    multicastGroupPort=4446, timeToLive=1"
        propertySeparator="," />

<cacheManagerPeerListenerFactory
        class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory" />

<cache name="shiro-activeSessionCache" maxElementsInMemory="600"
       eternal="true" overflowToDisk="true" memoryStoreEvictionPolicy="LFU">
    <cacheEventListenerFactory
            class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
</cache>

<defaultCache maxElementsInMemory="100" eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0"
              overflowToDisk="true" memoryStoreEvictionPolicy="LFU">
</defaultCache>

</ehcache>

web.xml

<web-app version="3.0" xmlns=".....">

<distributable />

<!-- SHIRO -->
<!-- <listener> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> 
    </listener> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class> 
    </filter> -->


<!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml -->
<filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<!-- ensure that Shiro works in subsequent filters in the filter chain: -->
<filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

<filter>
    <filter-name>encoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- spring-orm-hibernate4的OpenSessionInViewFilter -->
<filter>
    <filter-name>opensessioninview</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>opensessioninview</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/application-context.xml, /WEB-INF/shiro-context.xml </param-value>
</context-param>

<!-- Loads the Spring web application context -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- RequestContextHolder.currentRequestAttributes() -->
<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

<!-- ZK -->
<listener>
    <description>ZK listener for session cleanup</description>
    <listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class>
</listener>

<servlet>
    <description>ZK loader for ZUML pages</description>
    <servlet-name>zkLoader</servlet-name>
    <servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>

    <!-- Must. Specifies URI of the update engine (DHtmlUpdateServlet). It 
        must be the same as <url-pattern> for the update engine. -->
    <init-param>
        <param-name>update-uri</param-name>
        <param-value>/zkau</param-value>
    </init-param>


    <load-on-startup>1</load-on-startup><!-- Must -->
    <async-supported>true</async-supported>
</servlet>
<servlet-mapping>
    <servlet-name>zkLoader</servlet-name>
    <url-pattern>*.zul</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>zkLoader</servlet-name>
    <url-pattern>*.zhtml</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>


    <load-on-startup>1</load-on-startup><!-- Must -->
    <async-supported>true</async-supported>
</servlet>
<servlet-mapping>
    <servlet-name>auEngine</servlet-name>
    <url-pattern>/zkau/*</url-pattern>
</servlet-mapping>


<welcome-file-list>
    <welcome-file>login.zul</welcome-file>
</welcome-file-list>

</web-app>

With kind regards,

Emma

How to implement single sign on(SSO) using Apache Shiro on zk

Hello,

I am currently working on a project which uses Spring in backend and ZK on frontend and its security by Apache Shiro.

Now am in demand of implementing Single Sign On as it is composed of many modules each deployable independently. I tried to do a deep search on internet and I found some resources and articles showing how to achieve that. Unfortunately it didn't help me.

Below are the articles I used:

  1. #support.stormpath.com/hc/en-us/articles/203815036-Can-I-SSO-between-multiple-Wars-in-the-same-servlet-with-Stormpath-and-Apache-Shiro-#
  2. #shiro-user.582556.n2.nabble.com/Shiro-and-multiple-wars-within-the-same-Servlet-Container-td5560737.html#a5563334#

Below are my configurations. Please check if I am doing wrong somewhere.

I welcome any helpful suggestion.

Spring config

<beans xmlns="......&gt;&lt;/p&gt; &lt;pre&gt;&lt;code&gt;&lt;bean id=" myrealm"="" class="myRealmClass" &gt;="" &lt;property="" xmlns="......">

<bean id="myRealm" class="myRealmClass">
    <property name="cachingEnabled" value="true" &gt;="" &lt;property="" />
    <property name="authenticationCachingEnabled" value="true" &gt;="" &lt;!--="" &lt;property="" />
    <!-- <property name="authenticationCacheName" value="authenticationCache" &gt;="" --&gt;="" &lt;property="" 
        /> -->
    <property name="authorizationCachingEnabled" value="true" &gt;="" &lt;!--="" &lt;property="" />
    <!-- <property name="authorizationCacheName" value="authorizationCache" &gt;="" --&gt;="" &lt;="" bean&gt;="" &lt;bean="" 
        /> -->
</bean>

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" &gt;="" &lt;property="" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="sessionMode" value="native" &gt;="" &lt;property="" />
    <property name="realm" ref="myRealm" &gt;="" &lt;property="" />
    <property name="sessionManager" ref="sessionManager" &gt;="" &lt;property="" />
    <property name="cacheManager" ref="cacheManager" &gt;="" &lt;property="" />
    <property name="rememberMeManager" ref="rememberMeManager" &gt;="" &lt;="" bean&gt;="" &lt;!--="" ehcache="" --&gt;="" &lt;bean="" />
</bean>

<!-- Ehcache -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager" &gt;="" &lt;property="" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    <property name="cacheManagerConfigFile" value="classpath:ehcache.xml" &gt;="" &lt;="" bean&gt;="" &lt;bean="" id="sessionIdGenerator" />
</bean>

<bean id="sessionIdGenerator"
    class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" &gt;="" &lt;!--="" cookie="" --&gt;="" &lt;bean="" />

<!-- Cookie -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie" &gt;="" &lt;constructor-arg="" class="org.apache.shiro.web.servlet.SimpleCookie">
    <constructor-arg value="sid" &gt;="" &lt;property="" />
    <property name="httpOnly" value="true" &gt;="" &lt;property="" />
    <property name="maxAge" value="180000" &gt;="" &lt;="" bean&gt;="" &lt;bean="" />
</bean>

<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie" &gt;="" &lt;constructor-arg="" class="org.apache.shiro.web.servlet.SimpleCookie">
    <constructor-arg value="rememberMe" &gt;="" &lt;property="" />
    <property name="httpOnly" value="true" &gt;="" &lt;property="" />
    <property name="maxAge" value="2592000" &gt;&lt;!--="" 30天="" --&gt;="" &lt;="" bean&gt;="" &lt;bean="" /><!-- 30天 -->
</bean>

<bean id="cookie" class="org.apache.shiro.web.servlet.SimpleCookie" &gt;="" &lt;property="" class="org.apache.shiro.web.servlet.SimpleCookie">
    <property name="name" value="SSOCookie" &gt;="" &lt;property="" />
    <property name="path" value="/" &gt;="" &lt;property="" />
    <property name="domain" value="localhost" &gt;="" &lt;="" bean&gt;="" &lt;!--="" rememberme="" --&gt;="" &lt;bean="" />

</bean>

<!-- rememberMe -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager" &gt;="" &lt;property="" name="cipherKey" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
    <property name="cipherKey"
        value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}" &gt;="" &lt;property="" />
    <property name="cookie" ref="rememberMeCookie" &gt;="" &lt;="" bean&gt;="" &lt;bean="" />
</bean>

<bean id="onlineSessionFactory" class="org.apache.shiro.session.mgt.SimpleSessionFactory" &gt;="" &lt;!--="" dao="" --&gt;="" &lt;bean="" id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO" &gt;="" &lt;property="" />

<!-- DAO -->
<bean id="sessionDAO"
    class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
    <property name="activeSessionsCacheName" value="shiro-activeSessionCache" &gt;="" &lt;property="" />
    <property name="sessionIdGenerator" ref="sessionIdGenerator" &gt;="" &lt;="" bean&gt;="" &lt;bean="" id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler" &gt;="" &lt;property="" />
</bean>


<bean id="sessionValidationScheduler"
    class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">
    <property name="sessionValidationInterval" value="1800000" &gt;="" &lt;property="" />
    <property name="sessionManager" ref="sessionManager" &gt;="" &lt;="" bean&gt;="" &lt;bean="" id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager" &gt;="" &lt;property="" />
</bean>


<bean id="sessionManager"
    class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    <property name="globalSessionTimeout" value="1800000" &gt;="" &lt;property="" />
    <property name="sessionFactory" ref="onlineSessionFactory" &gt;="" &lt;property="" />
    <property name="deleteInvalidSessions" value="true" &gt;="" &lt;property="" />
    <property name="sessionValidationSchedulerEnabled" value="true" &gt;="" &lt;property="" />
    <property name="sessionValidationScheduler" ref="sessionValidationScheduler" &gt;="" &lt;property="" />
    <property name="sessionDAO" ref="sessionDAO" &gt;="" &lt;property="" />
    <property name="sessionIdCookieEnabled" value="true" &gt;="" &lt;property="" />
    <property name="sessionIdCookie" ref="cookie" &gt;="" &lt;="" bean&gt;="" &lt;!--="" secure="" spring="" remoting:="" ensure="" any="" spring="" remoting="" method="" invocations="" --&gt;="" &lt;!--="" can="" be="" associated="" with="" a="" subject="" for="" security="" checks.="" --&gt;="" &lt;bean="" id="secureRemoteInvocationExecutor" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor" &gt;="" &lt;property="" />
</bean>

<!-- Secure Spring remoting: Ensure any Spring Remoting method invocations -->
<!-- can be associated with a Subject for security checks. -->
<bean id="secureRemoteInvocationExecutor"
    class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">
    <property name="securityManager" ref="securityManager" &gt;="" &lt;="" bean&gt;="" &lt;!--="" securityutils.setsecuritymanager(securitymanager)="" --&gt;="" &lt;bean="" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean" &gt;="" &lt;property="" name="staticMethod" />
</bean>

<!-- SecurityUtils.setSecurityManager(securityManager) -->
<bean
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="staticMethod"
        value="org.apache.shiro.SecurityUtils.setSecurityManager" &gt;="" &lt;property="" />
    <property name="arguments" ref="securityManager" &gt;="" &lt;="" bean&gt;="" &lt;bean="" />
</bean>

<bean id="casFilter" class="org.apache.shiro.cas.CasFilter" &gt;="" &lt;property="" class="org.apache.shiro.cas.CasFilter">
    <property name="failureUrl" value="/login.zul" &gt;="" &lt;="" bean&gt;="" &lt;!--="" shiro="" web="" --&gt;="" &lt;bean="" />
</bean>

<!-- Shiro Web -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" &gt;="" &lt;property="" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager" &gt;="" &lt;property="" />
    <property name="successUrl" value="/index.zul" &gt;="" &lt;="" bean&gt;="" &lt;!--="" shiro="" --&gt;="" &lt;bean="" />
</bean>

<!-- Shiro -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" &gt;="" &lt;bean="" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" />

<bean
    class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
    depends-on="lifecycleBeanPostProcessor" &gt;="" &lt;bean="" class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor" &gt;="" &lt;property="" />
<bean
    class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
    <property name="securityManager" ref="securityManager" &gt;="" &lt;="" bean&gt;="" <="" code="">

/> </bean>

</beans>

ehCache.xml

<ehcache xmlns:xsi="...." xsi:nonamespaceschemalocation="ehcache.xsd" updatecheck="true" monitoring="autodetect" dynamicconfig="true">

<diskStore path="java.io.tmpdir" />

<cacheManagerPeerProviderFactory
        class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
        properties="peerDiscovery=automatic,
                    multicastGroupAddress=230.0.0.1,
                    multicastGroupPort=4446, timeToLive=1"
        propertySeparator="," />

<cacheManagerPeerListenerFactory
        class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory" />

<cache name="shiro-activeSessionCache" maxElementsInMemory="600"
       eternal="true" overflowToDisk="true" memoryStoreEvictionPolicy="LFU">
    <cacheEventListenerFactory
            class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
</cache>

<defaultCache maxElementsInMemory="100" eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0"
              overflowToDisk="true" memoryStoreEvictionPolicy="LFU">
</defaultCache>

</ehcache>

web.xml

<web-app version="3.0" xmlns=".....">

<distributable />

<!-- SHIRO -->
<!-- <listener> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> 
    </listener> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class> 
    </filter> -->


<!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml -->
<filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<!-- ensure that Shiro works in subsequent filters in the filter chain: -->
<filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

<filter>
    <filter-name>encoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- spring-orm-hibernate4的OpenSessionInViewFilter -->
<filter>
    <filter-name>opensessioninview</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>opensessioninview</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/application-context.xml, /WEB-INF/shiro-context.xml </param-value>
</context-param>

<!-- Loads the Spring web application context -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- RequestContextHolder.currentRequestAttributes() -->
<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

<!-- ZK -->
<listener>
    <description>ZK listener for session cleanup</description>
    <listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class>
</listener>

<servlet>
    <description>ZK loader for ZUML pages</description>
    <servlet-name>zkLoader</servlet-name>
    <servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>

    <!-- Must. Specifies URI of the update engine (DHtmlUpdateServlet). It 
        must be the same as <url-pattern> for the update engine. -->
    <init-param>
        <param-name>update-uri</param-name>
        <param-value>/zkau</param-value>
    </init-param>


    <load-on-startup>1</load-on-startup><!-- Must -->
    <async-supported>true</async-supported>
</servlet>
<servlet-mapping>
    <servlet-name>zkLoader</servlet-name>
    <url-pattern>*.zul</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>zkLoader</servlet-name>
    <url-pattern>*.zhtml</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>


    <load-on-startup>1</load-on-startup><!-- Must -->
    <async-supported>true</async-supported>
</servlet>
<servlet-mapping>
    <servlet-name>auEngine</servlet-name>
    <url-pattern>/zkau/*</url-pattern>
</servlet-mapping>


<welcome-file-list>
    <welcome-file>login.zul</welcome-file>
</welcome-file-list>

</web-app>

With kind regards,

Emma

How to implement single sign on(SSO) using Apache Shiro on zk

Hello,

I am currently working on a project which uses Spring in backend and ZK on frontend and its security by Apache Shiro.

Now am in demand of implementing Single Sign On as it is composed of many modules each deployable independently. I tried to do a deep search on internet and I found some resources and articles showing how to achieve that. Unfortunately it didn't help me.

Below are the articles I used:

  1. #support.stormpath.com/hc/en-us/articles/203815036-Can-I-SSO-between-multiple-Wars-in-the-same-servlet-with-Stormpath-and-Apache-Shiro-#
  2. #shiro-user.582556.n2.nabble.com/Shiro-and-multiple-wars-within-the-same-Servlet-Container-td5560737.html#a5563334#

Below are my configurations. Please check if I am doing wrong somewhere.

I welcome any helpful suggestion.

Spring config

<beans xmlns="......">

<bean id="myRealm" class="myRealmClass">
    <property name="cachingEnabled" value="true" />
    <property name="authenticationCachingEnabled" value="true" />
    <!-- <property name="authenticationCacheName" value="authenticationCache" 
        /> -->
    <property name="authorizationCachingEnabled" value="true" />
    <!-- <property name="authorizationCacheName" value="authorizationCache" 
        /> -->
</bean>

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="sessionMode" value="native" />
    <property name="realm" ref="myRealm" />
    <property name="sessionManager" ref="sessionManager" />
    <property name="cacheManager" ref="cacheManager" />
    <property name="rememberMeManager" ref="rememberMeManager" />
</bean>

<!-- Ehcache -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
    <property name="cacheManagerConfigFile" value="classpath:ehcache.xml" />
</bean>

<bean id="sessionIdGenerator"
    class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" />

<!-- Cookie -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
    <constructor-arg value="sid" />
    <property name="httpOnly" value="true" />
    <property name="maxAge" value="180000" />
</bean>

<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
    <constructor-arg value="rememberMe" />
    <property name="httpOnly" value="true" />
    <property name="maxAge" value="2592000" /><!-- 30天 -->
</bean>

<bean id="cookie" class="org.apache.shiro.web.servlet.SimpleCookie">
    <property name="name" value="SSOCookie" />
    <property name="path" value="/" />
    <property name="domain" value="localhost" />

</bean>

<!-- rememberMe -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
    <property name="cipherKey"
        value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}" />
    <property name="cookie" ref="rememberMeCookie" />
</bean>

<bean id="onlineSessionFactory" class="org.apache.shiro.session.mgt.SimpleSessionFactory" />

<!-- DAO -->
<bean id="sessionDAO"
    class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
    <property name="activeSessionsCacheName" value="shiro-activeSessionCache" />
    <property name="sessionIdGenerator" ref="sessionIdGenerator" />
</bean>


<bean id="sessionValidationScheduler"
    class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">
    <property name="sessionValidationInterval" value="1800000" />
    <property name="sessionManager" ref="sessionManager" />
</bean>


<bean id="sessionManager"
    class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
    <property name="globalSessionTimeout" value="1800000" />
    <property name="sessionFactory" ref="onlineSessionFactory" />
    <property name="deleteInvalidSessions" value="true" />
    <property name="sessionValidationSchedulerEnabled" value="true" />
    <property name="sessionValidationScheduler" ref="sessionValidationScheduler" />
    <property name="sessionDAO" ref="sessionDAO" />
    <property name="sessionIdCookieEnabled" value="true" />
    <property name="sessionIdCookie" ref="cookie" />
</bean>

<!-- Secure Spring remoting: Ensure any Spring Remoting method invocations -->
<!-- can be associated with a Subject for security checks. -->
<bean id="secureRemoteInvocationExecutor"
    class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">
    <property name="securityManager" ref="securityManager" />
</bean>

<!-- SecurityUtils.setSecurityManager(securityManager) -->
<bean
    class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
    <property name="staticMethod"
        value="org.apache.shiro.SecurityUtils.setSecurityManager" />
    <property name="arguments" ref="securityManager" />
</bean>

<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
    <property name="failureUrl" value="/login.zul" />
</bean>

<!-- Shiro Web -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager" />
    <property name="successUrl" value="/index.zul" />
</bean>

<!-- Shiro -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

<bean
    class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
    depends-on="lifecycleBeanPostProcessor" />
<bean
    class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
    <property name="securityManager" ref="securityManager" />
</bean>

</beans>

ehCache.xml

<ehcache xmlns:xsi="...." xsi:nonamespaceschemalocation="ehcache.xsd" updatecheck="true" monitoring="autodetect" dynamicconfig="true">

<diskStore path="java.io.tmpdir" />

<cacheManagerPeerProviderFactory
        class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
        properties="peerDiscovery=automatic,
                    multicastGroupAddress=230.0.0.1,
                    multicastGroupPort=4446, timeToLive=1"
        propertySeparator="," />

<cacheManagerPeerListenerFactory
        class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory" />

<cache name="shiro-activeSessionCache" maxElementsInMemory="600"
       eternal="true" overflowToDisk="true" memoryStoreEvictionPolicy="LFU">
    <cacheEventListenerFactory
            class="net.sf.ehcache.distribution.RMICacheReplicatorFactory" />
</cache>

<defaultCache maxElementsInMemory="100" eternal="true" timeToIdleSeconds="0" timeToLiveSeconds="0"
              overflowToDisk="true" memoryStoreEvictionPolicy="LFU">
</defaultCache>

</ehcache>

web.xml

<web-app version="3.0" xmlns=".....">

<distributable />

<!-- SHIRO -->
<!-- <listener> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> 
    </listener> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class> 
    </filter> -->


<!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml -->
<filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
        <param-name>targetFilterLifecycle</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>

<!-- ensure that Shiro works in subsequent filters in the filter chain: -->
<filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>

<filter>
    <filter-name>encoding</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
        <param-name>encoding</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>encoding</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>
<!-- spring-orm-hibernate4的OpenSessionInViewFilter -->
<filter>
    <filter-name>opensessioninview</filter-name>
    <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>opensessioninview</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/application-context.xml, /WEB-INF/shiro-context.xml </param-value>
</context-param>

<!-- Loads the Spring web application context -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

<!-- RequestContextHolder.currentRequestAttributes() -->
<listener>
    <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>

<!-- ZK -->
<listener>
    <description>ZK listener for session cleanup</description>
    <listener-class>org.zkoss.zk.ui.http.HttpSessionListener</listener-class>
</listener>

<servlet>
    <description>ZK loader for ZUML pages</description>
    <servlet-name>zkLoader</servlet-name>
    <servlet-class>org.zkoss.zk.ui.http.DHtmlLayoutServlet</servlet-class>

    <!-- Must. Specifies URI of the update engine (DHtmlUpdateServlet). It 
        must be the same as <url-pattern> for the update engine. -->
    <init-param>
        <param-name>update-uri</param-name>
        <param-value>/zkau</param-value>
    </init-param>


    <load-on-startup>1</load-on-startup><!-- Must -->
    <async-supported>true</async-supported>
</servlet>
<servlet-mapping>
    <servlet-name>zkLoader</servlet-name>
    <url-pattern>*.zul</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>zkLoader</servlet-name>
    <url-pattern>*.zhtml</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>


    <load-on-startup>1</load-on-startup><!-- Must -->
    <async-supported>true</async-supported>
</servlet>
<servlet-mapping>
    <servlet-name>auEngine</servlet-name>
    <url-pattern>/zkau/*</url-pattern>
</servlet-mapping>


<welcome-file-list>
    <welcome-file>login.zul</welcome-file>
</welcome-file-list>

</web-app>

With kind regards,

Emma

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More