CAS Authentication
Overview
JA-SIG 生成一个企业范围的单点登录系统,称为 CAS。与其他计划不同,JA-SIG 的中央认证服务是开源的、被广泛使用、容易理解、与平台无关且支持代理功能。Spring Security 完全支持 CAS,并提供一条从 Spring Security 的单一应用程序部署到受企业级 CAS 服务器保护的多应用程序部署的轻松迁移路径。
JA-SIG produces an enterprise-wide single sign on system known as CAS. Unlike other initiatives, JA-SIG’s Central Authentication Service is open source, widely used, simple to understand, platform independent, and supports proxy capabilities. Spring Security fully supports CAS, and provides an easy migration path from single-application deployments of Spring Security through to multiple-application deployments secured by an enterprise-wide CAS server.
您可以在 [role="bare"][role="bare"]https://www.apereo.org 中了解有关 CAS 的更多信息。您还需要访问该网站来下载 CAS 服务器文件。
You can learn more about CAS at [role="bare"]https://www.apereo.org. You will also need to visit this site to download the CAS Server files.
How CAS Works
CAS 网站包含详细介绍 CAS 架构的文档,但我们在此 Spring Security 的上下文中再次介绍其概述。Spring Security 3.x 支持 CAS 3。撰写本文时,CAS 服务器的版本为 3.4。
Whilst the CAS web site contains documents that detail the architecture of CAS, we present the general overview again here within the context of Spring Security. Spring Security 3.x supports CAS 3. At the time of writing, the CAS server was at version 3.4.
您需要在企业中的某个位置设置 CAS 服务器。CAS 服务器只是一个标准 WAR 文件,因此设置服务器没有任何困难。在 WAR 文件内部,您可以自定义登录和其他显示给用户的单点登录页面。
Somewhere in your enterprise you will need to setup a CAS server. The CAS server is simply a standard WAR file, so there isn’t anything difficult about setting up your server. Inside the WAR file you will customise the login and other single sign on pages displayed to users.
部署 CAS 3.4 服务器时,您还需在 CAS 附带的 deployerConfigContext.xml
中指定一个 AuthenticationHandler
。AuthenticationHandler
有一个简单的方法,可返回布尔值来指示给定的一组凭据是否有效。您的 AuthenticationHandler
实现需要链接到某种后端身份验证信息库,例如 LDAP 服务器或数据库。CAS 本身包含很多开箱即用的 AuthenticationHandler
来帮助实现此操作。下载并部署服务器 war 文件后,会将其设置为成功验证输入的密码与相应用户名匹配的用户,这在进行测试时很有用。
When deploying a CAS 3.4 server, you will also need to specify an AuthenticationHandler
in the deployerConfigContext.xml
included with CAS.
The AuthenticationHandler
has a simple method that returns a boolean as to whether a given set of Credentials is valid.
Your AuthenticationHandler
implementation will need to link into some type of backend authentication repository, such as an LDAP server or database.
CAS itself includes numerous `AuthenticationHandler`s out of the box to assist with this.
When you download and deploy the server war file, it is set up to successfully authenticate users who enter a password matching their username, which is useful for testing.
除了 CAS 服务器本身,其他主要参与者当然是企业中部署的安全的 Web 应用程序。这些 Web 应用程序称为“服务”。服务有三种类型:身份验证服务票证、可获取代理票证以及身份验证代理票证。验证代理票证有所不同,因为必须验证代理列表,而且通常可以重复利用代理票证。
Apart from the CAS server itself, the other key players are of course the secure web applications deployed throughout your enterprise. These web applications are known as "services". There are three types of services. Those that authenticate service tickets, those that can obtain proxy tickets, and those that authenticate proxy tickets. Authenticating a proxy ticket differs because the list of proxies must be validated and often times a proxy ticket can be reused.
Spring Security and CAS Interaction Sequence
Web 浏览器、CAS 服务器和受 Spring Security 保护的服务之间的基本交互过程如下:
The basic interaction between a web browser, CAS server and a Spring Security-secured service is as follows:
-
The web user is browsing the service’s public pages. CAS or Spring Security is not involved.
-
The user eventually requests a page that is either secure or one of the beans it uses is secure. Spring Security’s
ExceptionTranslationFilter
will detect theAccessDeniedException
orAuthenticationException
. -
Because the user’s
Authentication
object (or lack thereof) caused anAuthenticationException
, theExceptionTranslationFilter
will call the configuredAuthenticationEntryPoint
. If using CAS, this will be theCasAuthenticationEntryPoint
class. -
The
CasAuthenticationEntryPoint
will redirect the user’s browser to the CAS server. It will also indicate aservice
parameter, which is the callback URL for the Spring Security service (your application). For example, the URL to which the browser is redirected might be [role="bare"]https://my.company.com/cas/login?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas. -
After the user’s browser redirects to CAS, they will be prompted for their username and password. If the user presents a session cookie which indicates they’ve previously logged on, they will not be prompted to login again (there is an exception to this procedure, which we’ll cover later). CAS will use the
PasswordHandler
(orAuthenticationHandler
if using CAS 3.0) discussed above to decide whether the username and password is valid. -
Upon successful login, CAS will redirect the user’s browser back to the original service. It will also include a
ticket
parameter, which is an opaque string representing the "service ticket". Continuing our earlier example, the URL the browser is redirected to might be [role="bare"]https://server3.company.com/webapp/login/cas?ticket=ST-0-ER94xMJmn6pha35CQRoZ. -
Back in the service web application, the
CasAuthenticationFilter
is always listening for requests to/login/cas
(this is configurable, but we’ll use the defaults in this introduction). The processing filter will construct aUsernamePasswordAuthenticationToken
representing the service ticket. The principal will be equal toCasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER
, whilst the credentials will be the service ticket opaque value. This authentication request will then be handed to the configuredAuthenticationManager
. -
The
AuthenticationManager
implementation will be theProviderManager
, which is in turn configured with theCasAuthenticationProvider
. TheCasAuthenticationProvider
only responds toUsernamePasswordAuthenticationToken`s containing the CAS-specific principal (such as `CasAuthenticationFilter.CAS_STATEFUL_IDENTIFIER
) and `CasAuthenticationToken`s (discussed later). -
CasAuthenticationProvider
will validate the service ticket using aTicketValidator
implementation. This will typically be aCas20ServiceTicketValidator
which is one of the classes included in the CAS client library. In the event the application needs to validate proxy tickets, theCas20ProxyTicketValidator
is used. TheTicketValidator
makes an HTTPS request to the CAS server in order to validate the service ticket. It may also include a proxy callback URL, which is included in this example: [role="bare"]https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Flogin/cas&ticket=ST-0-ER94xMJmn6pha35CQRoZ&pgtUrl=https://server3.company.com/webapp/login/cas/proxyreceptor. -
Back on the CAS server, the validation request will be received. If the presented service ticket matches the service URL the ticket was issued to, CAS will provide an affirmative response in XML indicating the username. If any proxy was involved in the authentication (discussed below), the list of proxies is also included in the XML response.
-
[OPTIONAL] If the request to the CAS validation service included the proxy callback URL (in the
pgtUrl
parameter), CAS will include apgtIou
string in the XML response. ThispgtIou
represents a proxy-granting ticket IOU. The CAS server will then create its own HTTPS connection back to thepgtUrl
. This is to mutually authenticate the CAS server and the claimed service URL. The HTTPS connection will be used to send a proxy granting ticket to the original web application. For example, [role="bare"]https://server3.company.com/webapp/login/cas/proxyreceptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH. -
The
Cas20TicketValidator
will parse the XML received from the CAS server. It will return to theCasAuthenticationProvider
aTicketResponse
, which includes the username (mandatory), proxy list (if any were involved), and proxy-granting ticket IOU (if the proxy callback was requested). -
Next
CasAuthenticationProvider
will call a configuredCasProxyDecider
. TheCasProxyDecider
indicates whether the proxy list in theTicketResponse
is acceptable to the service. Several implementations are provided with Spring Security:RejectProxyTickets
,AcceptAnyCasProxy
andNamedCasProxyDecider
. These names are largely self-explanatory, exceptNamedCasProxyDecider
which allows aList
of trusted proxies to be provided. -
CasAuthenticationProvider
will next request aAuthenticationUserDetailsService
to load theGrantedAuthority
objects that apply to the user contained in theAssertion
. -
If there were no problems,
CasAuthenticationProvider
constructs aCasAuthenticationToken
including the details contained in theTicketResponse
and the `GrantedAuthority`s. -
Control then returns to
CasAuthenticationFilter
, which places the createdCasAuthenticationToken
in the security context. -
The user’s browser is redirected to the original page that caused the
AuthenticationException
(or a custom destination depending on the configuration).
很高兴您还在关注!让我们现在了解如何进行此配置
It’s good that you’re still here! Let’s now look at how this is configured
Configuration of CAS Client
由于 Spring Security,CAS 的 Web 应用程序端变得简单。我们认为您已经知道如何使用 Spring Security 的基础知识,因此下面不再涉及这些知识。我们将假设使用基于命名空间的配置并在需要时添加 CAS Bean。每个部分都构建在前一部分的基础上。可在 Spring Security Samples中找到一个完整的 CAS 示例应用程序。
The web application side of CAS is made easy due to Spring Security. It is assumed you already know the basics of using Spring Security, so these are not covered again below. We’ll assume a namespace based configuration is being used and add in the CAS beans as required. Each section builds upon the previous section. A full CAS sample application can be found in the Spring Security Samples.
Service Ticket Authentication
本部分介绍如何设置 Spring Security 来验证服务票证。通常情况下,这正是 Web 应用程序的全部需求。您需要向应用程序上下文添加一个 ServiceProperties
bean。这表示您的 CAS 服务:
This section describes how to setup Spring Security to authenticate Service Tickets.
Often times this is all a web application requires.
You will need to add a ServiceProperties
bean to your application context.
This represents your CAS service:
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
<property name="service"
value="https://localhost:8443/cas-sample/login/cas"/>
<property name="sendRenew" value="false"/>
</bean>
service
必须等于 CasAuthenticationFilter
将要监视的 URL。sendRenew
的默认值为 false,但如果您的应用程序特别敏感,应将其设置为 true。该参数的作用是告诉 CAS 登录服务,单点登录是不可接受的。相反,用户需要重新输入其用户名和密码才能获得对该服务的访问权限。
The service
must equal a URL that will be monitored by the CasAuthenticationFilter
.
The sendRenew
defaults to false, but should be set to true if your application is particularly sensitive.
What this parameter does is tell the CAS login service that a single sign on login is unacceptable.
Instead, the user will need to re-enter their username and password in order to gain access to the service.
应配置以下 bean 以开始 CAS 身份验证流程(假设您使用的是名称空间配置):
The following beans should be configured to commence the CAS authentication process (assuming you’re using a namespace configuration):
<security:http entry-point-ref="casEntryPoint">
...
<security:custom-filter position="CAS_FILTER" ref="casFilter" />
</security:http>
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
<property name="authenticationManager" ref="authenticationManager"/>
</bean>
<bean id="casEntryPoint"
class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<property name="loginUrl" value="https://localhost:9443/cas/login"/>
<property name="serviceProperties" ref="serviceProperties"/>
</bean>
为使 CAS 运行,`ExceptionTranslationFilter`必须将其 `authenticationEntryPoint`属性设置为 `CasAuthenticationEntryPoint`Bean。可以使用 entry-point-ref轻松完成此操作,如下面的示例所示。`CasAuthenticationEntryPoint`必须引用 `ServiceProperties`Bean(如上所述),该 Bean 提供企业 CAS 登录服务器的 URL。这是用户浏览器将被重定向到的位置。
For CAS to operate, the ExceptionTranslationFilter
must have its authenticationEntryPoint
property set to the CasAuthenticationEntryPoint
bean.
This can easily be done using entry-point-ref as is done in the example above.
The CasAuthenticationEntryPoint
must refer to the ServiceProperties
bean (discussed above), which provides the URL to the enterprise’s CAS login server.
This is where the user’s browser will be redirected.
CasAuthenticationFilter
具有与 UsernamePasswordAuthenticationFilter
(用于基于表单的登录)非常相似的属性。您可以使用这些属性来自定义诸如身份验证成功和失败行为之类的功能。
The CasAuthenticationFilter
has very similar properties to the UsernamePasswordAuthenticationFilter
(used for form-based logins).
You can use these properties to customize things like behavior for authentication success and failure.
接下来,您需要添加一个 CasAuthenticationProvider
及其协作者:
Next you need to add a CasAuthenticationProvider
and its collaborators:
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="casAuthenticationProvider" />
</security:authentication-manager>
<bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<property name="authenticationUserDetailsService">
<bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<constructor-arg ref="userService" />
</bean>
</property>
<property name="serviceProperties" ref="serviceProperties" />
<property name="ticketValidator">
<bean class="org.apereo.cas.client.validation.Cas20ServiceTicketValidator">
<constructor-arg index="0" value="https://localhost:9443/cas" />
</bean>
</property>
<property name="key" value="an_id_for_this_auth_provider_only"/>
</bean>
<security:user-service id="userService">
<!-- Password is prefixed with {noop} to indicate to DelegatingPasswordEncoder that
NoOpPasswordEncoder should be used.
This is not safe for production, but makes reading
in samples easier.
Normally passwords should be hashed using BCrypt -->
<security:user name="joe" password="{noop}joe" authorities="ROLE_USER" />
...
</security:user-service>
CasAuthenticationProvider
会使用 UserDetailsService
实例为用户加载权限,一旦他们通过 CAS 验证后会。我们在此展示了一个简单的内存设置。请注意 CasAuthenticationProvider
实际上并不使用密码进行身份验证,但它确实会使用权限。
The CasAuthenticationProvider
uses a UserDetailsService
instance to load the authorities for a user, once they have been authenticated by CAS.
We’ve shown a simple in-memory setup here.
Note that the CasAuthenticationProvider
does not actually use the password for authentication, but it does use the authorities.
如果您参阅 How CAS Works 部分,您会发现所有的 bean 都解释得相当清楚。
The beans are all reasonably self-explanatory if you refer back to the cas-how-it-works section.
至此,CAS 的最基本配置已经完成。如果您没有犯任何错误,那么您的 Web 应用程序应该乐于在 CAS 单点登录的框架内工作。Spring Security 的其他部分都无需关注 CAS 已处理的身份验证。以下几部分,我们将讨论一些(可选的)更高级的配置。
This completes the most basic configuration for CAS. If you haven’t made any mistakes, your web application should happily work within the framework of CAS single sign on. No other parts of Spring Security need to be concerned about the fact CAS handled authentication. In the following sections we will discuss some (optional) more advanced configurations.
Single Logout
CAS 协议支持单点注销,而且很容易将其添加到您的 Spring Security 配置中。以下是处理单点注销的 Spring Security 配置更新:
The CAS protocol supports Single Logout and can be easily added to your Spring Security configuration. Below are updates to the Spring Security configuration that handle Single Logout
<security:http entry-point-ref="casEntryPoint">
...
<security:logout logout-success-url="/cas-logout.jsp"/>
<security:custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER"/>
<security:custom-filter ref="singleLogoutFilter" before="CAS_FILTER"/>
</security:http>
<!-- This filter handles a Single Logout Request from the CAS Server -->
<bean id="singleLogoutFilter" class="org.apereo.cas.client.session.SingleSignOutFilter"/>
<!-- This filter redirects to the CAS Server to signal Single Logout should be performed -->
<bean id="requestSingleLogoutFilter"
class="org.springframework.security.web.authentication.logout.LogoutFilter">
<constructor-arg value="https://localhost:9443/cas/logout"/>
<constructor-arg>
<bean class=
"org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</constructor-arg>
<property name="filterProcessesUrl" value="/logout/cas"/>
</bean>
logout
元素会使用户退出本地应用程序,但不会结束与 CAS 服务器或已登录的任何其他应用程序之间的会话。requestSingleLogoutFilter
过滤器将允许请求 /spring_security_cas_logout
的 URL,以将应用程序重定向到配置的 CAS 服务器注销 URL。然后 CAS 服务器会向所有已登录的服务发送单点注销请求。singleLogoutFilter
会通过在静态 Map
中查找 HttpSession
,然后使之无效,来处理单点注销请求。
The logout
element logs the user out of the local application, but does not end the session with the CAS server or any other applications that have been logged into.
The requestSingleLogoutFilter
filter will allow the URL of /spring_security_cas_logout
to be requested to redirect the application to the configured CAS Server logout URL.
Then the CAS Server will send a Single Logout request to all the services that were signed into.
The singleLogoutFilter
handles the Single Logout request by looking up the HttpSession
in a static Map
and then invalidating it.
您可能会困惑,为什么 logout
元素和 singleLogoutFilter
元素都是必需的。由于 SingleSignOutFilter
只是把 HttpSession
存储在一个静态 Map
中以便调用 invalidate,因此最好先在本地注销。通过上述配置,注销流程如下:
It might be confusing why both the logout
element and the singleLogoutFilter
are needed.
It is considered best practice to logout locally first since the SingleSignOutFilter
just stores the HttpSession
in a static Map
in order to call invalidate on it.
With the configuration above, the flow of logout would be:
-
The user requests
/logout
which would log the user out of the local application and send the user to the logout success page. -
The logout success page,
/cas-logout.jsp
, should instruct the user to click a link pointing to/logout/cas
in order to logout out of all applications. -
When the user clicks the link, the user is redirected to the CAS single logout URL ([role="bare"]https://localhost:9443/cas/logout).
-
On the CAS Server side, the CAS single logout URL then submits single logout requests to all the CAS Services. On the CAS Service side, Apereo’s
SingleSignOutFilter
processes the logout request by invalidating the original session.
下一步就是要将以下内容添加到您的 web.xml 中。
The next step is to add the following to your web.xml
<filter>
<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-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>
org.apereo.cas.client.session.SingleSignOutHttpSessionListener
</listener-class>
</listener>
在使用 SingleSignOutFilter 时, 您可能会遇到一些编码问题。因此, 建议添加 CharacterEncodingFilter
以确保在使用 SingleSignOutFilter
时字符编码正确。同样, 请参阅 Apereo CAS 的文档以获取详细信息。SingleSignOutHttpSessionListener
确保在 HttpSession
过期时, 用于单点注销的映射已删除。
When using the SingleSignOutFilter you might encounter some encoding issues.
Therefore it is recommended to add the CharacterEncodingFilter
to ensure that the character encoding is correct when using the SingleSignOutFilter
.
Again, refer to Apereo CAS’s documentation for details.
The SingleSignOutHttpSessionListener
ensures that when an HttpSession
expires, the mapping used for single logout is removed.
Authenticating to a Stateless Service with CAS
本节介绍如何使用 CAS 身份验证服务。换句话说, 本节讨论如何设置使用 CAS 身份验证服务的客户端。下一节介绍如何设置使用 CAS 身份验证的无状态服务。
This section describes how to authenticate to a service using CAS. In other words, this section discusses how to setup a client that uses a service that authenticates with CAS. The next section describes how to setup a stateless service to Authenticate using CAS.
Configuring CAS to Obtain Proxy Granting Tickets
为了向无状态服务进行身份验证,应用程序需要获取代理授予票证 (PGT)。本节介绍如何配置 Spring Security 以获取 PGT,它建立在 thencas-st[服务票证身份验证] 配置的基础之上。
In order to authenticate to a stateless service, the application needs to obtain a proxy granting ticket (PGT). This section describes how to configure Spring Security to obtain a PGT building upon thencas-st[Service Ticket Authentication] configuration.
第一步是在您的 Spring Security 配置中包含 ProxyGrantingTicketStorage
。这用于存储由 CasAuthenticationFilter
获得的 PGT, 以便它们可用于获取代理票证。示例配置如下所示
The first step is to include a ProxyGrantingTicketStorage
in your Spring Security configuration.
This is used to store PGT’s that are obtained by the CasAuthenticationFilter
so that they can be used to obtain proxy tickets.
An example configuration is shown below
<!--
NOTE: In a real application you should not use an in memory implementation.
You will also want to ensure to clean up expired tickets by calling
ProxyGrantingTicketStorage.cleanup()
-->
<bean id="pgtStorage" class="org.apereo.cas.client.proxy.ProxyGrantingTicketStorageImpl"/>
下一步是更新 CasAuthenticationProvider
以便能够获取代理票证。要执行此操作, 请用 Cas20ProxyTicketValidator
替换 Cas20ServiceTicketValidator
。proxyCallbackUrl
应设置为应用程序将在其中收到 PGT 的 URL。最后, 该配置还应引用 ProxyGrantingTicketStorage
, 这样它才能使用 PGT 来获取代理票证。您可以在下面找到应进行的配置更改示例。
The next step is to update the CasAuthenticationProvider
to be able to obtain proxy tickets.
To do this replace the Cas20ServiceTicketValidator
with a Cas20ProxyTicketValidator
.
The proxyCallbackUrl
should be set to a URL that the application will receive PGT’s at.
Last, the configuration should also reference the ProxyGrantingTicketStorage
so it can use a PGT to obtain proxy tickets.
You can find an example of the configuration changes that should be made below.
<bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
...
<property name="ticketValidator">
<bean class="org.apereo.cas.client.validation.Cas20ProxyTicketValidator">
<constructor-arg value="https://localhost:9443/cas"/>
<property name="proxyCallbackUrl"
value="https://localhost:8443/cas-sample/login/cas/proxyreceptor"/>
<property name="proxyGrantingTicketStorage" ref="pgtStorage"/>
</bean>
</property>
</bean>
最后一步是更新 CasAuthenticationFilter
以接受 PGT 并将其存储在 ProxyGrantingTicketStorage
中。proxyReceptorUrl
匹配 Cas20ProxyTicketValidator
的 proxyCallbackUrl
很重要。示例配置如下所示。
The last step is to update the CasAuthenticationFilter
to accept PGT and to store them in the ProxyGrantingTicketStorage
.
It is important the proxyReceptorUrl
matches the proxyCallbackUrl
of the Cas20ProxyTicketValidator
.
An example configuration is shown below.
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
...
<property name="proxyGrantingTicketStorage" ref="pgtStorage"/>
<property name="proxyReceptorUrl" value="/login/cas/proxyreceptor"/>
</bean>
Calling a Stateless Service Using a Proxy Ticket
现在,Spring Security 已获得 PGT,您可以使用它们来创建代理票证,这些票证可用于向无状态服务进行身份验证。CAS sample application包含 `ProxyTicketSampleServlet`中的一个工作示例。示例代码如下:
Now that Spring Security obtains PGTs, you can use them to create proxy tickets which can be used to authenticate to a stateless service.
The CAS sample application contains a working example in the ProxyTicketSampleServlet
.
Example code can be found below:
-
Java
-
Kotlin
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// NOTE: The CasAuthenticationToken can also be obtained using
// SecurityContextHolder.getContext().getAuthentication()
final CasAuthenticationToken token = (CasAuthenticationToken) request.getUserPrincipal();
// proxyTicket could be reused to make calls to the CAS service even if the
// target url differs
final String proxyTicket = token.getAssertion().getPrincipal().getProxyTicketFor(targetUrl);
// Make a remote call using the proxy ticket
final String serviceUrl = targetUrl+"?ticket="+URLEncoder.encode(proxyTicket, "UTF-8");
String proxyResponse = CommonUtils.getResponseFromServer(serviceUrl, "UTF-8");
...
}
protected fun doGet(request: HttpServletRequest, response: HttpServletResponse?) {
// NOTE: The CasAuthenticationToken can also be obtained using
// SecurityContextHolder.getContext().getAuthentication()
val token = request.userPrincipal as CasAuthenticationToken
// proxyTicket could be reused to make calls to the CAS service even if the
// target url differs
val proxyTicket = token.assertion.principal.getProxyTicketFor(targetUrl)
// Make a remote call using the proxy ticket
val serviceUrl: String = targetUrl + "?ticket=" + URLEncoder.encode(proxyTicket, "UTF-8")
val proxyResponse = CommonUtils.getResponseFromServer(serviceUrl, "UTF-8")
}
Proxy Ticket Authentication
CasAuthenticationProvider
区分有状态和无状态客户端。有状态客户端被认为是任何提交给 CasAuthenticationFilter
的 filterProcessesUrl
的客户端。无状态客户端是指在 CasAuthenticationFilter
上提交身份验证请求且 URL 并非 filterProcessesUrl
的任何客户端。
The CasAuthenticationProvider
distinguishes between stateful and stateless clients.
A stateful client is considered any that submits to the filterProcessesUrl
of the CasAuthenticationFilter
.
A stateless client is any that presents an authentication request to CasAuthenticationFilter
on a URL other than the filterProcessesUrl
.
因为远程调用协议无法在 HttpSession
的上下文中展示自身, 所以不可能依赖于在请求之间的会话中存储安全上下文的默认做法。此外, 由于 CAS 服务器在 TicketValidator
验证票证后会使其失效, 所以在后续请求中出示相同的代理票证不起作用。
Because remoting protocols have no way of presenting themselves within the context of an HttpSession
, it isn’t possible to rely on the default practice of storing the security context in the session between requests.
Furthermore, because the CAS server invalidates a ticket after it has been validated by the TicketValidator
, presenting the same proxy ticket on subsequent requests will not work.
一个显而易见的选项是根本不为远程调用协议客户端使用 CAS。但是, 这将消除 CAS 许多理想的功能。作为一个中间立场, CasAuthenticationProvider
使用 StatelessTicketCache
。这仅用于使用等于 CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER
的主体的无状态客户端。发生的是 CasAuthenticationProvider
将生成的 CasAuthenticationToken
存储在 StatelessTicketCache
中, 以代理票证为键。相应地, 远程调用协议客户端可以出示相同的代理票证, 而 CasAuthenticationProvider
无需联系 CAS 服务器进行验证(第一个请求除外)。经过身份验证后, 代理票证可用于原始目标服务之外的 URL。
One obvious option is to not use CAS at all for remoting protocol clients.
However, this would eliminate many of the desirable features of CAS.
As a middle-ground, the CasAuthenticationProvider
uses a StatelessTicketCache
.
This is used solely for stateless clients which use a principal equal to CasAuthenticationFilter.CAS_STATELESS_IDENTIFIER
.
What happens is the CasAuthenticationProvider
will store the resulting CasAuthenticationToken
in the StatelessTicketCache
, keyed on the proxy ticket.
Accordingly, remoting protocol clients can present the same proxy ticket and the CasAuthenticationProvider
will not need to contact the CAS server for validation (aside from the first request).
Once authenticated, the proxy ticket could be used for URLs other than the original target service.
本节以建立代理票证身份验证为基础。第一步是按照如下所示指定对所有构件进行身份验证。
This section builds upon the previous sections to accommodate proxy ticket authentication. The first step is to specify to authenticate all artifacts as shown below.
<bean id="serviceProperties"
class="org.springframework.security.cas.ServiceProperties">
...
<property name="authenticateAllArtifacts" value="true"/>
</bean>
下一步是为 CasAuthenticationFilter
指定 serviceProperties
和 authenticationDetailsSource
。serviceProperties
属性指示 CasAuthenticationFilter
尝试对所有构件进行身份验证, 而不只是 filterProcessesUrl
上存在的构件。ServiceAuthenticationDetailsSource
创建 ServiceAuthenticationDetails
, 该 ServiceAuthenticationDetails
确保在验证票证时, 基于 HttpServletRequest
的当前 URL 用作服务 URL。可以通过注入返回自定义 ServiceAuthenticationDetails
的自定义 AuthenticationDetailsSource
来自定义生成服务 URL 的方法。
The next step is to specify serviceProperties
and the authenticationDetailsSource
for the CasAuthenticationFilter
.
The serviceProperties
property instructs the CasAuthenticationFilter
to attempt to authenticate all artifacts instead of only ones present on the filterProcessesUrl
.
The ServiceAuthenticationDetailsSource
creates a ServiceAuthenticationDetails
that ensures the current URL, based upon the HttpServletRequest
, is used as the service URL when validating the ticket.
The method for generating the service URL can be customized by injecting a custom AuthenticationDetailsSource
that returns a custom ServiceAuthenticationDetails
.
<bean id="casFilter"
class="org.springframework.security.cas.web.CasAuthenticationFilter">
...
<property name="serviceProperties" ref="serviceProperties"/>
<property name="authenticationDetailsSource">
<bean class=
"org.springframework.security.cas.web.authentication.ServiceAuthenticationDetailsSource">
<constructor-arg ref="serviceProperties"/>
</bean>
</property>
</bean>
您还需要更新 CasAuthenticationProvider
以处理代理票证。要执行此操作, 请用 Cas20ProxyTicketValidator
替换 Cas20ServiceTicketValidator
。您需要配置 statelessTicketCache
以及您想要接受的代理。您可以在下面找到接受所有代理所需的更新示例。
You will also need to update the CasAuthenticationProvider
to handle proxy tickets.
To do this replace the Cas20ServiceTicketValidator
with a Cas20ProxyTicketValidator
.
You will need to configure the statelessTicketCache
and which proxies you want to accept.
You can find an example of the updates required to accept all proxies below.
<bean id="casAuthenticationProvider"
class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
...
<property name="ticketValidator">
<bean class="org.apereo.cas.client.validation.Cas20ProxyTicketValidator">
<constructor-arg value="https://localhost:9443/cas"/>
<property name="acceptAnyProxy" value="true"/>
</bean>
</property>
<property name="statelessTicketCache">
<bean class="org.springframework.security.cas.authentication.EhCacheBasedTicketCache">
<property name="cache">
<bean class="net.sf.ehcache.Cache"
init-method="initialise" destroy-method="dispose">
<constructor-arg value="casTickets"/>
<constructor-arg value="50"/>
<constructor-arg value="true"/>
<constructor-arg value="false"/>
<constructor-arg value="3600"/>
<constructor-arg value="900"/>
</bean>
</property>
</bean>
</property>
</bean>