cas-auth-provider.xml 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  1. <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="cas"
  2. xmlns:xlink="http://www.w3.org/1999/xlink">
  3. <title>CAS Authentication</title>
  4. <section xml:id="cas-overview">
  5. <title>Overview</title>
  6. <para>JA-SIG produces an enterprise-wide single sign on system known
  7. as CAS. Unlike other initiatives, JA-SIG's Central Authentication
  8. Service is open source, widely used, simple to understand, platform
  9. independent, and supports proxy capabilities. Spring Security fully
  10. supports CAS, and provides an easy migration path from
  11. single-application deployments of Spring Security through to
  12. multiple-application deployments secured by an enterprise-wide CAS
  13. server.</para>
  14. <para>You can learn more about CAS at
  15. <literal>http://www.ja-sig.org/products/cas/</literal>. You will also need
  16. to visit this site to download the CAS Server files.</para>
  17. </section>
  18. <section xml:id="cas-how-it-works">
  19. <info><title>How CAS Works</title></info>
  20. <para>Whilst the CAS web site contains documents that detail
  21. the architecture of CAS, we present the general overview again here
  22. within the context of Spring Security. Spring Security 2.0 supports
  23. CAS 3. At the time of writing, the CAS server was at version 3.2.</para>
  24. <para>Somewhere in your enterprise you will need to setup a CAS
  25. server. The CAS server is simply a standard WAR file, so there isn't
  26. anything difficult about setting up your server. Inside the WAR file
  27. you will customise the login and other single sign on pages displayed
  28. to users.</para>
  29. <para>When deploying a CAS 3.2 server, you will also need to specify an
  30. <literal>AuthenticationHandler</literal> in the
  31. <filename>deployerConfigContext.xml</filename> included with CAS. The
  32. <literal>AuthenticationHandler</literal> has a simple method that
  33. returns a boolean as to whether a given set of Credentials is valid.
  34. Your <literal>AuthenticationHandler</literal> implementation will need
  35. to link into some type of backend authentication repository, such as
  36. an LDAP server or database. CAS itself includes numerous
  37. <literal>AuthenticationHandler</literal>s out of the box to assist
  38. with this. When you download and deploy the server war file, it is set up
  39. to successfully authenticate users who enter a password matching their
  40. username, which is useful for testing.</para>
  41. <para>Apart from the CAS server itself, the other key players are of
  42. course the secure web applications deployed throughout your
  43. enterprise. These web applications are known as "services". There are
  44. two types of services: standard services and proxy services. A proxy
  45. service is able to request resources from other services on behalf of
  46. the user. This will be explained more fully later.</para>
  47. <!--
  48. <section xml:id="cas-sequence">
  49. <title>Spring Security and CAS Interaction Sequence</title>
  50. TODO: Needs reviewed
  51. <para>The basic interaction between a web browser, CAS server and a
  52. Spring Security-secured service is as follows:</para>
  53. <orderedlist inheritnum="ignore" continuation="restarts">
  54. <listitem>
  55. <para>The web user is browsing the service's public pages. CAS or
  56. Spring Security is not involved.</para>
  57. </listitem>
  58. <listitem>
  59. <para>The user eventually requests a page that is either secure or
  60. one of the beans it uses is secure. Spring Security's
  61. <classname>ExceptionTranslationFilter</classname> will detect the
  62. <literal>AuthenticationException</literal>.</para>
  63. </listitem>
  64. <listitem>
  65. <para>Because the user's <interfacename>Authentication</interfacename> object
  66. (or lack thereof) caused an
  67. <literal>AuthenticationException</literal>, the
  68. <classname>ExceptionTranslationFilter</classname> will call the
  69. configured <interfacename>AuthenticationEntryPoint</interfacename>. If using
  70. CAS, this will be the
  71. <literal>CasProcessingFilterEntryPoint</literal> class.</para>
  72. </listitem>
  73. <listitem>
  74. <para>The <literal>CasProcessingFilterEntry</literal> point will
  75. redirect the user's browser to the CAS server. It will also
  76. indicate a <literal>service</literal> parameter, which is the
  77. callback URL for Spring Security service. For example, the URL to
  78. which the browser is redirected might be
  79. <literal>https://my.company.com/cas/login?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Fj_spring_cas_security_check</literal>.</para>
  80. </listitem>
  81. <listitem>
  82. <para>After the user's browser redirects to CAS, they will be
  83. prompted for their username and password. If the user presents a
  84. session cookie which indicates they've previously logged on, they
  85. will not be prompted to login again (there is an exception to this
  86. procedure, which we'll cover later). CAS will use the
  87. <literal>PasswordHandler</literal> (or
  88. <literal>AuthenticationHandler</literal> if using CAS 3.0)
  89. discussed above to decide whether the username and password is
  90. valid.</para>
  91. </listitem>
  92. <listitem>
  93. <para>Upon successful login, CAS will redirect the user's browser
  94. back to the original service. It will also include a
  95. <literal>ticket</literal> parameter, which is an opaque string
  96. representing the "service ticket". Continuing our earlier example,
  97. the URL the browser is redirected to might be
  98. <literal>https://server3.company.com/webapp/j_spring_cas_security_check?ticket=ST-0-ER94xMJmn6pha35CQRoZ</literal>.</para>
  99. </listitem>
  100. <listitem>
  101. <para>Back in the service web application, the
  102. <literal>CasProcessingFilter</literal> is always listening for
  103. requests to <literal>/j_spring_cas_security_check</literal> (this
  104. is configurable, but we'll use the defaults in this introduction).
  105. The processing filter will construct a
  106. <literal>UsernamePasswordAuthenticationToken</literal>
  107. representing the service ticket. The principal will be equal to
  108. <literal>CasProcessingFilter.CAS_STATEFUL_IDENTIFIER</literal>,
  109. whilst the credentials will be the service ticket opaque value.
  110. This authentication request will then be handed to the configured
  111. <interfacename>AuthenticationManager</interfacename>.</para>
  112. </listitem>
  113. <listitem>
  114. <para>The <interfacename>AuthenticationManager</interfacename> implementation
  115. will be the <literal>ProviderManager</literal>, which is in turn
  116. configured with the <literal>CasAuthenticationProvider</literal>.
  117. The <literal>CasAuthenticationProvider</literal> only responds to
  118. <literal>UsernamePasswordAuthenticationToken</literal>s containing
  119. the CAS-specific principal (such as
  120. <literal>CasProcessingFilter.CAS_STATEFUL_IDENTIFIER</literal>)
  121. and <literal>CasAuthenticationToken</literal>s (discussed
  122. later).</para>
  123. </listitem>
  124. <listitem>
  125. <para><literal>CasAuthenticationProvider</literal> will validate
  126. the service ticket using a <literal>TicketValidator</literal>
  127. implementation. Spring Security includes one implementation, the
  128. <literal>CasProxyTicketValidator</literal>. This implementation a
  129. ticket validation class included in the CAS client library. The
  130. <literal>CasProxyTicketValidator</literal> makes an HTTPS request
  131. to the CAS server in order to validate the service ticket. The
  132. <literal>CasProxyTicketValidator</literal> may also include a
  133. proxy callback URL, which is included in this example:
  134. <literal>https://my.company.com/cas/proxyValidate?service=https%3A%2F%2Fserver3.company.com%2Fwebapp%2Fj_spring_cas_security_check&amp;ticket=ST-0-ER94xMJmn6pha35CQRoZ&amp;pgtUrl=https://server3.company.com/webapp/casProxy/receptor</literal>.</para>
  135. </listitem>
  136. <listitem>
  137. <para>Back on the CAS server, the proxy validation request will be
  138. received. If the presented service ticket matches the service URL
  139. the ticket was issued to, CAS will provide an affirmative response
  140. in XML indicating the username. If any proxy was involved in the
  141. authentication (discussed below), the list of proxies is also
  142. included in the XML response.</para>
  143. </listitem>
  144. <listitem>
  145. <para>[OPTIONAL] If the request to the CAS validation service
  146. included the proxy callback URL (in the <literal>pgtUrl</literal>
  147. parameter), CAS will include a <literal>pgtIou</literal> string in
  148. the XML response. This <literal>pgtIou</literal> represents a
  149. proxy-granting ticket IOU. The CAS server will then create its own
  150. HTTPS connection back to the <literal>pgtUrl</literal>. This is to
  151. mutually authenticate the CAS server and the claimed service URL.
  152. The HTTPS connection will be used to send a proxy granting ticket
  153. to the original web application. For example,
  154. <literal>https://server3.company.com/webapp/casProxy/receptor?pgtIou=PGTIOU-0-R0zlgrl4pdAQwBvJWO3vnNpevwqStbSGcq3vKB2SqSFFRnjPHt&amp;pgtId=PGT-1-si9YkkHLrtACBo64rmsi3v2nf7cpCResXg5MpESZFArbaZiOKH</literal>.
  155. We suggest you use CAS' <literal>ProxyTicketReceptor</literal>
  156. servlet to receive these proxy-granting tickets, if they are
  157. required.</para>
  158. </listitem>
  159. <listitem>
  160. <para>The <literal>CasProxyTicketValidator</literal> will parse
  161. the XML received from the CAS server. It will return to the
  162. <literal>CasAuthenticationProvider</literal> a
  163. <literal>TicketResponse</literal>, which includes the username
  164. (mandatory), proxy list (if any were involved), and proxy-granting
  165. ticket IOU (if the proxy callback was requested).</para>
  166. </listitem>
  167. <listitem>
  168. <para>Next <literal>CasAuthenticationProvider</literal> will call
  169. a configured <literal>CasProxyDecider</literal>. The
  170. <literal>CasProxyDecider</literal> indicates whether the proxy
  171. list in the <literal>TicketResponse</literal> is acceptable to the
  172. service. Several implementations are provided with Spring
  173. Security: <literal>RejectProxyTickets</literal>,
  174. <literal>AcceptAnyCasProxy</literal> and
  175. <literal>NamedCasProxyDecider</literal>. These names are largely
  176. self-explanatory, except <literal>NamedCasProxyDecider</literal>
  177. which allows a <literal>List</literal> of trusted proxies to be
  178. provided.</para>
  179. </listitem>
  180. <listitem>
  181. <para><literal>CasAuthenticationProvider</literal> will next
  182. request a <literal>CasAuthoritiesPopulator</literal> to advise the
  183. <interfacename>GrantedAuthority</interfacename> objects that apply to the user
  184. contained in the <literal>TicketResponse</literal>. Spring
  185. Security includes a <literal>DaoCasAuthoritiesPopulator</literal>
  186. which simply uses the <interfacename>UserDetailsService</interfacename>
  187. infrastructure to find the <interfacename>UserDetails</interfacename> and
  188. their associated <interfacename>GrantedAuthority</interfacename>s. Note that
  189. the password and enabled/disabled status of
  190. <interfacename>UserDetails</interfacename> returned by the
  191. <interfacename>UserDetailsService</interfacename> are ignored, as the CAS
  192. server is responsible for authentication decisions.
  193. <literal>DaoCasAuthoritiesPopulator</literal> is only concerned
  194. with retrieving the <interfacename>GrantedAuthority</interfacename>s.</para>
  195. </listitem>
  196. <listitem>
  197. <para>If there were no problems,
  198. <literal>CasAuthenticationProvider</literal> constructs a
  199. <literal>CasAuthenticationToken</literal> including the details
  200. contained in the <literal>TicketResponse</literal> and the
  201. <interfacename>GrantedAuthority</interfacename>s. The
  202. <literal>CasAuthenticationToken</literal> contains the hash of a
  203. key, so that the <literal>CasAuthenticationProvider</literal>
  204. knows it created it.</para>
  205. </listitem>
  206. <listitem>
  207. <para>Control then returns to
  208. <literal>CasProcessingFilter</literal>, which places the created
  209. <literal>CasAuthenticationToken</literal> into the
  210. <literal>HttpSession</literal> attribute named
  211. <literal>HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY</literal>.</para>
  212. </listitem>
  213. <listitem>
  214. <para>The user's browser is redirected to the original page that
  215. caused the <literal>AuthenticationException</literal>.</para>
  216. </listitem>
  217. <listitem>
  218. <para>As the <interfacename>Authentication</interfacename> object is now in
  219. the well-known location, it is handled like any other
  220. authentication approach. Usually the
  221. <classname>HttpSessionContextIntegrationFilter</classname> will be
  222. used to associate the <interfacename>Authentication</interfacename> object
  223. with the <classname>SecurityContextHolder</classname> for the duration
  224. of each request.</para>
  225. </listitem>
  226. </orderedlist>
  227. <para>It's good that you're still here! It might sound involved, but
  228. you can relax as Spring Security classes hide much of the complexity.
  229. Let's now look at how this is configured</para>
  230. </section>
  231. -->
  232. </section>
  233. <section xml:id="cas-client">
  234. <info><title>Configuration of CAS Client</title></info>
  235. <para>The web application side of CAS is made easy due to Spring
  236. Security. It is assumed you already know the basics of using Spring
  237. Security, so these are not covered again below. We'll assume a namespace
  238. based configuration is being used and add in the CAS beans as required.
  239. </para>
  240. <para>You will need to add a <literal>ServiceProperties</literal> bean
  241. to your application context. This represents your service:</para>
  242. <para><programlisting><![CDATA[
  243. <bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
  244. <property name="service" value="https://localhost:8443/cas-sample/j_spring_cas_security_check"/>
  245. <property name="sendRenew" value="false"/>
  246. </bean>]]>
  247. </programlisting></para>
  248. <para>The <literal>service</literal> must equal a URL that will be
  249. monitored by the <literal>CasProcessingFilter</literal>. The
  250. <literal>sendRenew</literal> defaults to false, but should be set to
  251. true if your application is particularly sensitive. What this
  252. parameter does is tell the CAS login service that a single sign on
  253. login is unacceptable. Instead, the user will need to re-enter their
  254. username and password in order to gain access to the service.</para>
  255. <para>The following beans should be configured to commence the CAS
  256. authentication process:</para>
  257. <para><programlisting><![CDATA[
  258. <security:authentication-manager alias="authenticationManager"/>
  259. <bean id="casProcessingFilter" class="org.springframework.security.cas.web.CasProcessingFilter">
  260. <security:custom-filter after="CAS_PROCESSING_FILTER"/>
  261. <property name="authenticationManager" ref="authenticationManager"/>
  262. <property name="authenticationFailureUrl" value="/casfailed.jsp"/>
  263. <property name="defaultTargetUrl" value="/"/>
  264. </bean>
  265. <bean id="casProcessingFilterEntryPoint"
  266. class="org.springframework.security.cas.web.CasProcessingFilterEntryPoint">
  267. <property name="loginUrl" value="https://localhost:9443/cas/login"/>
  268. <property name="serviceProperties" ref="serviceProperties"/>
  269. </bean>
  270. ]]>
  271. </programlisting></para>
  272. <para>
  273. The <classname>CasProcessingFilterEntryPoint</classname> should be selected to
  274. drive authentication using <link xlink:href="ns-entry-point-ref"><literal>entry-point-ref</literal></link>.
  275. </para>
  276. <para>The <literal>CasProcessingFilter</literal> has very similar
  277. properties to the <literal>AuthenticationProcessingFilter</literal>
  278. (used for form-based logins). Each property is
  279. self-explanatory. Note that we've also used the namespace syntax
  280. for setting up an alias to the authentication mnager, since the
  281. <literal>CasProcessingFilter</literal> needs a reference to it.</para>
  282. <para>For CAS to operate, the
  283. <classname>ExceptionTranslationFilter</classname> must have its
  284. <literal>authenticationEntryPoint</literal> property set to the
  285. <literal>CasProcessingFilterEntryPoint</literal> bean.</para>
  286. <para>The <literal>CasProcessingFilterEntryPoint</literal> must refer
  287. to the <literal>ServiceProperties</literal> bean (discussed above),
  288. which provides the URL to the enterprise's CAS login server. This is
  289. where the user's browser will be redirected.</para>
  290. <para>Next you need to add a <literal>CasAuthenticationProvider</literal> and its
  291. collaborators:
  292. <programlisting><![CDATA[
  293. <bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
  294. <security:custom-authentication-provider />
  295. <property name="userDetailsService" ref="userService"/>
  296. <property name="serviceProperties" ref="serviceProperties" />
  297. <property name="ticketValidator">
  298. <bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
  299. <constructor-arg index="0" value="https://localhost:9443/cas" />
  300. </bean>
  301. </property>
  302. <property name="key" value="an_id_for_this_auth_provider_only"/>
  303. </bean>
  304. <security:user-service id="userService">
  305. <security:user name="joe" password="joe" authorities="ROLE_USER" />
  306. ...
  307. </security:user-service>]]>
  308. </programlisting>
  309. The <classname>CasAuthenticationProvider</classname> uses a <interfacename>UserDetailsService</interfacename>
  310. instance to load the authorities for a user, once they have been authentiated by CAS. We've shown a simple
  311. in-memory setup here.
  312. </para>
  313. <para>The beans are all reasonable self-explanatory if you refer back
  314. to the "How CAS Works" section.</para>
  315. </section>
  316. <!--
  317. <para>Note the <literal>CasProxyTicketValidator</literal> has a
  318. remarked out <literal>trustStore</literal> property. This property
  319. might be helpful if you experience HTTPS certificate issues. Also note
  320. the <literal>proxyCallbackUrl</literal> is set so the service can
  321. receive a proxy-granting ticket. As mentioned above, this is optional
  322. and unnecessary if you do not require proxy-granting tickets. If you
  323. do use this feature, you will need to configure a suitable servlet to
  324. receive the proxy-granting tickets. We suggest you use CAS'
  325. <literal>ProxyTicketReceptor</literal> by adding the following to your
  326. web application's <literal>web.xml</literal>:</para>
  327. <para><programlisting>
  328. &lt;servlet&gt;
  329. &lt;servlet-name&gt;casproxy&lt;/servlet-name&gt;
  330. &lt;servlet-class&gt;edu.yale.its.tp.cas.proxy.ProxyTicketReceptor&lt;/servlet-class&gt;
  331. &lt;/servlet&gt;
  332. &lt;servlet-mapping&gt;
  333. &lt;servlet-name&gt;casproxy&lt;/servlet-name&gt;
  334. &lt;url-pattern&gt;/casProxy/*&lt;/url-pattern&gt;
  335. &lt;/servlet-mapping&gt;
  336. </programlisting></para>
  337. <para>This completes the configuration of CAS. If you haven't made any
  338. mistakes, your web application should happily work within the
  339. framework of CAS single sign on. No other parts of Spring Security
  340. need to be concerned about the fact CAS handled authentication.</para>
  341. <para>There is also a <literal>contacts-cas.war</literal> file in the
  342. sample applications directory. This sample application uses the above
  343. settings and can be deployed to see CAS in operation</para>
  344. </section>
  345. <section xml:id="cas-advanced">
  346. <info><title>Advanced Issues</title></info>
  347. <para>The <literal>CasAuthenticationProvider</literal> distinguishes
  348. between stateful and stateless clients. A stateful client is
  349. considered any that originates via the
  350. <literal>CasProcessingFilter</literal>. A stateless client is any that
  351. presents an authentication request via the
  352. <literal>UsernamePasswordAuthenticationToken</literal> with a
  353. principal equal to
  354. <literal>CasProcessingFilter.CAS_STATELESS_IDENTIFIER</literal>.</para>
  355. <para>Stateless clients are likely to be via remoting protocols such
  356. as Hessian and Burlap. The <literal>BasicProcessingFilter</literal> is
  357. still used in this case, but the remoting protocol client is expected
  358. to present a username equal to the static string above, and a password
  359. equal to a CAS service ticket. Clients should acquire a CAS service
  360. ticket directly from the CAS server.</para>
  361. <para>Because remoting protocols have no way of presenting themselves
  362. within the context of an <literal>HttpSession</literal>, it isn't
  363. possible to rely on the <literal>HttpSession</literal>'s
  364. <literal>HttpSessionContextIntegrationFilter.SPRING_SECURITY_CONTEXT_KEY</literal>
  365. attribute to locate the <literal>CasAuthenticationToken</literal>.
  366. Furthermore, because the CAS server invalidates a service ticket after
  367. it has been validated by the <literal>TicketValidator</literal>,
  368. presenting the same service ticket on subsequent requests will not
  369. work. It is similarly very difficult to obtain a proxy-granting ticket
  370. for a remoting protocol client, as they are often deployed on client
  371. machines which rarely have HTTPS URLs that would be accessible to the
  372. CAS server.</para>
  373. <para>One obvious option is to not use CAS at all for remoting
  374. protocol clients. However, this would eliminate many of the desirable
  375. features of CAS.</para>
  376. <para>As a middle-ground, the
  377. <literal>CasAuthenticationProvider</literal> uses a
  378. <literal>StatelessTicketCache</literal>. This is used solely for
  379. requests with a principal equal to
  380. <literal>CasProcessingFilter.CAS_STATELESS_IDENTIFIER</literal>. What
  381. happens is the <literal>CasAuthenticationProvider</literal> will store
  382. the resulting <literal>CasAuthenticationToken</literal> in the
  383. <literal>StatelessTicketCache</literal>, keyed on the service ticket.
  384. Accordingly, remoting protocol clients can present the same service
  385. ticket and the <literal>CasAuthenticationProvider</literal> will not
  386. need to contact the CAS server for validation (aside from the first
  387. request).</para>
  388. <para>The other aspect of advanced CAS usage involves creating proxy
  389. tickets from the proxy-granting ticket. As indicated above, we
  390. recommend you use CAS' <literal>ProxyTicketReceptor</literal> to
  391. receive these tickets. The <literal>ProxyTicketReceptor</literal>
  392. provides a static method that enables you to obtain a proxy ticket by
  393. presenting the proxy-granting IOU ticket. You can obtain the
  394. proxy-granting IOU ticket by calling
  395. <literal>CasAuthenticationToken.getProxyGrantingTicketIou()</literal>.</para>
  396. <para>It is hoped you find CAS integration easy and useful with Spring
  397. Security classes. Welcome to enterprise-wide single sign on!</para>
  398. </section>
  399. -->
  400. </chapter>