Browse Source

SEC-965: Updated CAS Sample application for proxy authentication

* Configured for proxy authentication
* Cleaned up the jsps
* Changed the cas sample context root to cas-sample so the CAS Server's JSESSIONID cookie doesn't remove the cas samples
Rob Winch 14 years ago
parent
commit
f1c064b3b9

+ 1 - 1
samples/cas/Readme.txt

@@ -4,7 +4,7 @@ To run a CAS server and client application, just execute the command
 
 from the project root directory. You should then be able to point your browser at
 
-https://localhost:8443/cas/
+https://localhost:8443/cas-sample/
 
 to view the sample application. On attempting to access a secure page,
 you'll be redirected to the CAS server where you can log in with one of

+ 1 - 1
samples/cas/cas.gradle

@@ -31,7 +31,7 @@ dependencies {
 def keystore = "$rootDir/samples/certificates/server.jks"
 
 [jettyRun, jettyRunWar]*.configure {
-    contextPath = "/cas"
+    contextPath = "/cas-sample"
     def httpConnector = new org.mortbay.jetty.nio.SelectChannelConnector();
     httpConnector.port = 8080
     httpConnector.confidentialPort = 8443

+ 8 - 0
samples/cas/src/main/webapp/403.jsp

@@ -0,0 +1,8 @@
+<html>
+<head>
+<title>403 - Access Denied</title>
+</head>
+<body>
+<h1>403 - Access Denied</h1>
+</body>
+</html>

+ 107 - 109
samples/cas/src/main/webapp/WEB-INF/applicationContext-security.xml

@@ -1,111 +1,109 @@
 <?xml version="1.0" encoding="UTF-8"?>
-
-<beans xmlns="http://www.springframework.org/schema/beans"
-    xmlns:sec="http://www.springframework.org/schema/security"
+<b:beans xmlns:b="http://www.springframework.org/schema/beans"
+    xmlns="http://www.springframework.org/schema/security"
+    xmlns:p="http://www.springframework.org/schema/p"
     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.1.xsd">
-
-    <bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy">
-        <sec:filter-chain-map path-type="ant">
-            <sec:filter-chain pattern="/" filters="casValidationFilter, wrappingFilter" />
-            <sec:filter-chain pattern="/secure/receptor" filters="casValidationFilter" />
-            <sec:filter-chain pattern="/j_spring_security_logout" filters="logoutFilter,etf,fsi" />
-            <sec:filter-chain pattern="/**" filters="casAuthenticationFilter, casValidationFilter, wrappingFilter, sif,j2eePreAuthFilter,logoutFilter,etf,fsi"/>
-        </sec:filter-chain-map>
-    </bean>
-
-    <bean id="sif" class="org.springframework.security.web.context.SecurityContextPersistenceFilter"/>
-
-
-    <sec:authentication-manager alias="authenticationManager">
-        <sec:authentication-provider ref="preAuthAuthProvider"/>
-    </sec:authentication-manager>
-
-     <bean id="preAuthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
-        <property name="preAuthenticatedUserDetailsService">
-            <bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
-                <property name="userDetailsService" ref="userService"/>
-            </bean>
-        </property>
-    </bean>
-
-    <bean id="preAuthEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" />
-
-    <bean id="j2eePreAuthFilter" class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter">
-        <property name="authenticationManager" ref="authenticationManager"/>
-        <property name="authenticationDetailsSource">
-            <bean class="org.springframework.security.web.authentication.WebAuthenticationDetailsSource" />
-        </property>
-    </bean>
-
-    <bean id="logoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
-        <constructor-arg value="/"/>
-        <constructor-arg>
-            <list>
-                <bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
-            </list>
-        </constructor-arg>
-    </bean>
-
-    <bean id="servletContext" class="org.springframework.web.context.support.ServletContextFactoryBean"/>
-
-    <bean id="etf" class="org.springframework.security.web.access.ExceptionTranslationFilter">
-        <property name="authenticationEntryPoint" ref="preAuthEntryPoint"/>
-    </bean>
-
-    <bean id="httpRequestAccessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased">
-        <property name="allowIfAllAbstainDecisions" value="false"/>
-        <property name="decisionVoters">
-            <list>
-                <ref bean="roleVoter"/>
-            </list>
-        </property>
-    </bean>
-
-   <bean id="fsi" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
-        <property name="authenticationManager" ref="authenticationManager"/>
-        <property name="accessDecisionManager" ref="httpRequestAccessDecisionManager"/>
-        <property name="securityMetadataSource">
-            <sec:filter-invocation-definition-source>
-                <sec:intercept-url pattern="/secure/extreme/**" access="ROLE_SUPERVISOR"/>
-                <sec:intercept-url pattern="/secure/**" access="ROLE_USER"/>
-                <sec:intercept-url pattern="/**" access="ROLE_USER"/>
-            </sec:filter-invocation-definition-source>
-        </property>
-    </bean>
-
-    <bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter"/>
-
-    <bean id="securityContextHolderAwareRequestFilter" class="org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter"/>
-    
-    <bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator" id="ticketValidator">
-        <constructor-arg index="0" value="https://localhost:9443/cas" />
-        <property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" />
-        <property name="proxyCallbackUrl" value="https://localhost:8443/cas-sample/secure/receptor" />
-    </bean>
-
-    <bean id="proxyGrantingTicketStorage" class="org.jasig.cas.client.proxy.ProxyGrantingTicketStorageImpl" />
-
-    <sec:user-service id="userService">
-        <sec:user name="rod" password="rod" authorities="ROLE_SUPERVISOR,ROLE_USER" />
-        <sec:user name="dianne" password="dianne" authorities="ROLE_USER" />
-        <sec:user name="scott" password="scott" authorities="ROLE_USER" />
-    </sec:user-service>
-
-    <bean id="casAuthenticationFilter" class="org.jasig.cas.client.authentication.AuthenticationFilter">
-        <property name="casServerLoginUrl" value="https://localhost:9443/cas/login" />
-        <property name="serverName" value="https://localhost:8443" />
-    </bean>
-
-    <bean id="casValidationFilter" class="org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter">
-        <property name="serverName" value="https://localhost:8443" />
-        <property name="exceptionOnValidationFailure" value="true" />
-        <property name="proxyGrantingTicketStorage" ref="proxyGrantingTicketStorage" />
-        <property name="redirectAfterValidation" value="true" />
-        <property name="ticketValidator" ref="ticketValidator" />
-        <property name="proxyReceptorUrl" value="/secure/receptor" />
-    </bean>
-
-    <bean id="wrappingFilter" class="org.jasig.cas.client.util.HttpServletRequestWrapperFilter" />
-</beans>
+    xmlns:context="http://www.springframework.org/schema/context"
+    xmlns:util="http://www.springframework.org/schema/util"
+    xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
+		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
+		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
+
+    <http entry-point-ref="casEntryPoint" use-expressions="true">
+        <intercept-url pattern="/" access="permitAll"/>
+        <intercept-url pattern="/index.jsp" access="permitAll"/>
+        <intercept-url pattern="/cas-logout.jsp" access="permitAll"/>
+        <intercept-url pattern="/casfailed.jsp" access="permitAll"/>
+
+        <intercept-url pattern="/secure/extreme/**"
+            access="hasRole('ROLE_SUPERVISOR')" />
+        <intercept-url pattern="/secure/**" access="hasRole('ROLE_USER')" />
+        <intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
+        <custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER"/>
+        <custom-filter ref="singleLogoutFilter" before="CAS_FILTER"/>
+        <custom-filter ref="casFilter" position="CAS_FILTER" />
+        <logout logout-success-url="/cas-logout.jsp"/>
+    </http>
+
+    <authentication-manager alias="authManager">
+        <authentication-provider ref="casAuthProvider" />
+    </authentication-manager>
+
+    <user-service id="userService">
+        <user name="rod" password="rod" authorities="ROLE_SUPERVISOR,ROLE_USER" />
+        <user name="dianne" password="dianne" authorities="ROLE_USER" />
+        <user name="scott" password="scott" authorities="ROLE_USER" />
+    </user-service>
+
+    <!-- This filter handles a Single Logout Request from the CAS Server -->
+    <b:bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>
+    <!-- This filter redirects to the CAS Server to signal Single Logout should be performed -->
+    <b:bean id="requestSingleLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter"
+        p:filterProcessesUrl="/j_spring_cas_security_logout">
+        <b:constructor-arg value="https://${cas.server.host}/cas/logout"/>
+        <b:constructor-arg>
+            <b:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
+        </b:constructor-arg>
+    </b:bean>
+
+    <b:bean id="serviceProperties"
+        class="org.springframework.security.cas.ServiceProperties"
+        p:service="https://${cas.service.host}/cas-sample/j_spring_cas_security_check"
+        p:authenticateAllArtifacts="true"/>
+    <b:bean id="casEntryPoint"
+        class="org.springframework.security.cas.web.CasAuthenticationEntryPoint"
+        p:serviceProperties-ref="serviceProperties" p:loginUrl="https://${cas.server.host}/cas/login" />
+    <b:bean id="casFilter"
+        class="org.springframework.security.cas.web.CasAuthenticationFilter"
+        p:authenticationManager-ref="authManager"
+        p:serviceProperties-ref="serviceProperties">
+        <b:property name="authenticationDetailsSource">
+            <b:bean class="org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource"/>
+        </b:property>
+        <b:property name="authenticationFailureHandler">
+            <b:bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"
+                p:defaultFailureUrl="/casfailed.jsp"/>
+        </b:property>
+    </b:bean>
+    <b:bean id="casAuthProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider"
+        p:serviceProperties-ref="serviceProperties"
+        p:key="casAuthProviderKey">
+        <b:property name="authenticationUserDetailsService">
+            <b:bean
+                class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
+                <b:constructor-arg ref="userService" />
+            </b:bean>
+        </b:property>
+        <b:property name="ticketValidator">
+            <b:bean
+                class="org.jasig.cas.client.validation.Cas20ProxyTicketValidator"
+                p:acceptAnyProxy="true">
+                <b:constructor-arg value="https://${cas.server.host}/cas" />
+            </b:bean>
+        </b:property>
+        <b:property name="statelessTicketCache">
+            <b:bean class="org.springframework.security.cas.authentication.EhCacheBasedTicketCache">
+                <b:property name="cache">
+                    <b:bean class="net.sf.ehcache.Cache"
+                      init-method="initialise"
+                      destroy-method="dispose">
+                        <b:constructor-arg value="casTickets"/>
+                        <b:constructor-arg value="50"/>
+                        <b:constructor-arg value="true"/>
+                        <b:constructor-arg value="false"/>
+                        <b:constructor-arg value="3600"/>
+                        <b:constructor-arg value="900"/>
+                    </b:bean>
+                </b:property>
+            </b:bean>
+        </b:property>
+    </b:bean>
+
+    <!-- Configuration for the environment can be overriden by system properties -->
+    <context:property-placeholder system-properties-mode="OVERRIDE" properties-ref="environment"/>
+    <util:properties id="environment">
+        <b:prop key="cas.service.host">localhost:8443</b:prop>
+        <b:prop key="cas.server.host">localhost:9443</b:prop>
+    </util:properties>
+</b:beans>

+ 23 - 13
samples/cas/src/main/webapp/WEB-INF/web.xml

@@ -25,42 +25,52 @@
         <param-value>cas.root</param-value>
     </context-param>
 
+    <!--
+        Include the character encoding Filter as per JASIG recommenation when doing Single Sign Out
+        https://wiki.jasig.org/display/CASC/Configuring+Single+Sign+Out
+    -->
     <filter>
-       <filter-name>CAS Single Sign Out Filter</filter-name>
-       <filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
+        <filter-name>characterEncodingFilter</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>
         <filter-name>springSecurityFilterChain</filter-name>
         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
     </filter>
 
     <filter-mapping>
-       <filter-name>CAS Single Sign Out Filter</filter-name>
-       <url-pattern>/*</url-pattern>
+        <filter-name>characterEncodingFilter</filter-name>
+        <url-pattern>/*</url-pattern>
     </filter-mapping>
-
     <filter-mapping>
-      <filter-name>springSecurityFilterChain</filter-name>
-      <url-pattern>/*</url-pattern>
+        <filter-name>springSecurityFilterChain</filter-name>
+        <url-pattern>/*</url-pattern>
     </filter-mapping>
 
     <!--
-      - Loads the root application context of this web app at startup.
-      - The application context is then available via
-      - WebApplicationContextUtils.getWebApplicationContext(servletContext).
+        Included to support Single Logout. Note that the SingleSignOutFilter is included in the
+        springSecurityFilterChain. However, it could also be placed as the first filter-mapping
+        in the web.xml
     -->
     <listener>
         <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
     </listener>
 
+    <!--
+      - 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>
 
     <error-page>
         <error-code>403</error-code>
-        <location>/casfailed.jsp</location>
+        <location>/403.jsp</location>
     </error-page>
-
 </web-app>

+ 1 - 1
samples/cas/src/main/webapp/cas-logout.jsp

@@ -9,7 +9,7 @@
 
 <p>You have logged out of this application, but may still have an active single-sign on session with CAS.</p>
 
-<p><a href="https://localhost:9443/cas/logout">Logout of CAS</a></p>
+<p><a href="j_spring_cas_security_logout">Logout of CAS</a></p>
 
 </body>
 </html>

+ 9 - 1
samples/cas/src/main/webapp/casfailed.jsp

@@ -11,7 +11,15 @@
 
 <font color="red">
     Your CAS credentials were rejected.<br/><br/>
-    Reason: <%= ((AuthenticationException) session.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY)).getMessage() %>
+    Reason:
+<%
+    Exception error = ((AuthenticationException) session.getAttribute(AbstractAuthenticationProcessingFilter.SPRING_SECURITY_LAST_EXCEPTION_KEY));
+    if(error != null) {
+%>
+<%= error.getMessage() %>
+<%
+}
+%>
 </font>
 
 </body>