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
 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,
 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
 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"
 def keystore = "$rootDir/samples/certificates/server.jks"
 
 
 [jettyRun, jettyRunWar]*.configure {
 [jettyRun, jettyRunWar]*.configure {
-    contextPath = "/cas"
+    contextPath = "/cas-sample"
     def httpConnector = new org.mortbay.jetty.nio.SelectChannelConnector();
     def httpConnector = new org.mortbay.jetty.nio.SelectChannelConnector();
     httpConnector.port = 8080
     httpConnector.port = 8080
     httpConnector.confidentialPort = 8443
     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"?>
 <?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"
     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>
         <param-value>cas.root</param-value>
     </context-param>
     </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>
-       <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>
     <filter>
         <filter-name>springSecurityFilterChain</filter-name>
         <filter-name>springSecurityFilterChain</filter-name>
         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
     </filter>
     </filter>
 
 
     <filter-mapping>
     <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-mapping>
     <filter-mapping>
-      <filter-name>springSecurityFilterChain</filter-name>
-      <url-pattern>/*</url-pattern>
+        <filter-name>springSecurityFilterChain</filter-name>
+        <url-pattern>/*</url-pattern>
     </filter-mapping>
     </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>
         <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
         <listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
     </listener>
     </listener>
 
 
+    <!--
+      - Loads the root application context of this web app at startup.
+      - The application context is then available via
+      - WebApplicationContextUtils.getWebApplicationContext(servletContext).
+    -->
     <listener>
     <listener>
         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
     </listener>
     </listener>
 
 
     <error-page>
     <error-page>
         <error-code>403</error-code>
         <error-code>403</error-code>
-        <location>/casfailed.jsp</location>
+        <location>/403.jsp</location>
     </error-page>
     </error-page>
-
 </web-app>
 </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>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>
 </body>
 </html>
 </html>

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

@@ -11,7 +11,15 @@
 
 
 <font color="red">
 <font color="red">
     Your CAS credentials were rejected.<br/><br/>
     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>
 </font>
 
 
 </body>
 </body>