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
This commit is contained in:
Rob Winch 2011-04-03 21:41:26 -05:00
parent a76a947b12
commit f1c064b3b9
7 changed files with 145 additions and 121 deletions

View File

@ -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

View File

@ -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

View File

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

View File

@ -1,111 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<b:beans xmlns:b="http://www.springframework.org/schema/beans"
<beans xmlns="http://www.springframework.org/schema/beans" xmlns="http://www.springframework.org/schema/security"
xmlns:sec="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 xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> 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">
<bean id="springSecurityFilterChain" class="org.springframework.security.web.FilterChainProxy"> <http entry-point-ref="casEntryPoint" use-expressions="true">
<sec:filter-chain-map path-type="ant"> <intercept-url pattern="/" access="permitAll"/>
<sec:filter-chain pattern="/" filters="casValidationFilter, wrappingFilter" /> <intercept-url pattern="/index.jsp" access="permitAll"/>
<sec:filter-chain pattern="/secure/receptor" filters="casValidationFilter" /> <intercept-url pattern="/cas-logout.jsp" access="permitAll"/>
<sec:filter-chain pattern="/j_spring_security_logout" filters="logoutFilter,etf,fsi" /> <intercept-url pattern="/casfailed.jsp" access="permitAll"/>
<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"/> <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>
<sec:authentication-manager alias="authenticationManager"> <user-service id="userService">
<sec:authentication-provider ref="preAuthAuthProvider"/> <user name="rod" password="rod" authorities="ROLE_SUPERVISOR,ROLE_USER" />
</sec:authentication-manager> <user name="dianne" password="dianne" authorities="ROLE_USER" />
<user name="scott" password="scott" authorities="ROLE_USER" />
</user-service>
<bean id="preAuthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider"> <!-- This filter handles a Single Logout Request from the CAS Server -->
<property name="preAuthenticatedUserDetailsService"> <b:bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>
<bean id="userDetailsServiceWrapper" class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper"> <!-- This filter redirects to the CAS Server to signal Single Logout should be performed -->
<property name="userDetailsService" ref="userService"/> <b:bean id="requestSingleLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter"
</bean> p:filterProcessesUrl="/j_spring_cas_security_logout">
</property> <b:constructor-arg value="https://${cas.server.host}/cas/logout"/>
</bean> <b:constructor-arg>
<b:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</b:constructor-arg>
</b:bean>
<bean id="preAuthEntryPoint" class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" /> <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>
<bean id="j2eePreAuthFilter" class="org.springframework.security.web.authentication.preauth.j2ee.J2eePreAuthenticatedProcessingFilter"> <!-- Configuration for the environment can be overriden by system properties -->
<property name="authenticationManager" ref="authenticationManager"/> <context:property-placeholder system-properties-mode="OVERRIDE" properties-ref="environment"/>
<property name="authenticationDetailsSource"> <util:properties id="environment">
<bean class="org.springframework.security.web.authentication.WebAuthenticationDetailsSource" /> <b:prop key="cas.service.host">localhost:8443</b:prop>
</property> <b:prop key="cas.server.host">localhost:9443</b:prop>
</bean> </util:properties>
</b:beans>
<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>

View File

@ -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-name>characterEncodingFilter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class> <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> <filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern> <url-pattern>/*</url-pattern>
</filter-mapping> </filter-mapping>
<filter-mapping> <filter-mapping>
<filter-name>springSecurityFilterChain</filter-name> <filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern> <url-pattern>/*</url-pattern>
</filter-mapping> </filter-mapping>
<!--
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. - Loads the root application context of this web app at startup.
- The application context is then available via - The application context is then available via
- WebApplicationContextUtils.getWebApplicationContext(servletContext). - WebApplicationContextUtils.getWebApplicationContext(servletContext).
--> -->
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<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>

View File

@ -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>

View File

@ -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>