index.xml 75 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
  3. "../lib/docbook-dtd/docbookx.dtd">
  4. <book>
  5. <bookinfo>
  6. <title>Acegi Security System for Spring</title>
  7. <subtitle>Reference Documentation</subtitle>
  8. <releaseinfo>0.3</releaseinfo>
  9. <authorgroup>
  10. <author>
  11. <firstname>Ben</firstname>
  12. <surname>Alex</surname>
  13. </author>
  14. </authorgroup>
  15. </bookinfo>
  16. <toc></toc>
  17. <preface id="preface">
  18. <title>Preface</title>
  19. <para>This document provides a reference guide to the Acegi Security
  20. System for Spring, which is a series of classes that deliver
  21. authentication and authorization services within the Spring Framework.
  22. Whilst the Acegi Security System for Spring is not officially part of
  23. Spring, it is hoped this implementation will further discussion concerning
  24. the implementation of security capabilities within Spring itself.</para>
  25. <para>I would like to acknowledge this reference was prepared using the
  26. DocBook configuration included with the Spring Framework. The Spring team
  27. in turn acknowledge Chris Bauer (Hibernate) for his assistance with their
  28. DocBook.</para>
  29. </preface>
  30. <chapter id="security">
  31. <title>Security</title>
  32. <sect1 id="security-introduction">
  33. <title>Introduction</title>
  34. <para>The Acegi Security System for Spring provides authentication and
  35. authorization capabilities for Spring-powered projects, with full
  36. integration with popular web containers. The security architecture was
  37. designed from the ground up using "The Spring Way" of development, which
  38. includes using bean contexts, interceptors and interface-driven
  39. programming. As a consequence, the Acegi Security System for Spring is
  40. useful out-of-the-box for those seeking to secure their Spring-based
  41. applications, and can be easily adapted to complex customized
  42. requirements.</para>
  43. <para>Security involves two distinct operations, authentication and
  44. authorization. The former relates to resolving whether or not a caller
  45. is who they claim to be. Authorization on the other hand relates to
  46. determining whether or not an authenticated caller is permitted to
  47. perform a given operation.</para>
  48. <para>Throughout the Acegi Security System for Spring, the user, system
  49. or agent that needs to be authenticated is referred to as a "principal".
  50. The security architecture does not have a notion of roles or groups,
  51. which you may be familiar with from other security
  52. implementations.</para>
  53. </sect1>
  54. <sect1 id="security-request-contexts">
  55. <title>Request Contexts</title>
  56. <sect2 id="security-contexts">
  57. <title>Contexts</title>
  58. <para>Many applications require a way of sharing objects between
  59. classes, but without resorting to passing them in method signatures.
  60. This is commonly achieved by using a <literal>ThreadLocal</literal>.
  61. The Acegi Security System for Spring uses
  62. <literal>ThreadLocal</literal> functionality and introduces the
  63. concept of "request contexts".</para>
  64. <para>By placing an object into a request context, that object becomes
  65. available to any other object on the current thread of execution. The
  66. request context is not passed around as a method parameter, but is
  67. held in a <literal>ThreadLocal</literal>. The Acegi Security System
  68. for Spring uses the request context to pass around the authentication
  69. request and response.</para>
  70. <para>A request context is a concrete implementation of the
  71. <literal>Context</literal> interface, which exposes a single
  72. method:</para>
  73. <programlisting>public void validate() throws ContextInvalidException;</programlisting>
  74. <para>This <literal>validate()</literal> method is called to confirm
  75. the <literal>Context</literal> is properly setup. An implementation
  76. will typically use this method to check that the objects it holds are
  77. properly setup.</para>
  78. <para>The <literal>ContextHolder</literal> class makes the
  79. <literal>Context</literal> available to the current thread of
  80. execution using a <literal>ThreadLocal</literal>. A
  81. <literal>ContextInterceptor</literal> is also provided, which is
  82. intended to be chained into the bean context using
  83. <literal>ProxyFactoryBean</literal>. The
  84. <literal>ContextInterceptor</literal> simply calls
  85. <literal>Context.validate()</literal>, which guarantees to business
  86. methods that a valid <literal>Context</literal> is available from the
  87. <literal>ContextHolder</literal>.</para>
  88. </sect2>
  89. <sect2 id="security-contexts-secure-contexts">
  90. <title>Secure Contexts</title>
  91. <para>The Acegi Security System for Spring requires the
  92. <literal>ContextHolder</literal> to contain a request context that
  93. implements the <literal>SecureContext</literal> interface. An
  94. implementation is provided named <literal>SecureContextImpl</literal>.
  95. The <literal>SecureContext</literal> simply extends the
  96. <literal>Context</literal> discussed above and adds a holder and
  97. validation for an <literal>Authentication</literal> object.</para>
  98. </sect2>
  99. <sect2 id="security-contexts-custom-contexts">
  100. <title>Custom Contexts</title>
  101. <para>Developers can create their own request context classes to store
  102. application-specific objects. Such request context classes will need
  103. to implement the <literal>Context</literal> interface. If the Acegi
  104. Security System for Spring is to be used, developers must ensure any
  105. custom request contexts implement the <literal>SecureContext</literal>
  106. interface.</para>
  107. </sect2>
  108. <sect2 id="security-contexts-future-work">
  109. <title>Future Work</title>
  110. <para>Over time it is hoped that the Spring remoting classes can be
  111. extended to support propagation of the <literal>Context</literal>
  112. between <literal>ContextHolder</literal>s on the client and
  113. server.</para>
  114. </sect2>
  115. </sect1>
  116. <sect1 id="security-interception">
  117. <title>Security Interception</title>
  118. <sect2 id="security-interception-configuration">
  119. <title>Configuration</title>
  120. <para>The security architecture is implemented by placing a properly
  121. configured <literal>SecurityInterceptor</literal> into the bean
  122. context, and then chaining that <literal>SecurityInterceptor</literal>
  123. into a business object. This chaining is accomplished using Spring’s
  124. <literal>ProxyFactoryBean</literal>, as commonly used by many other
  125. parts of Spring (refer to the security test cases and sample
  126. application for examples). The <literal>SecurityInterceptor</literal>
  127. is configured as follows:</para>
  128. <para><programlisting>&lt;bean id="bankManagerSecurity" class="net.sf.acegisecurity.SecurityInterceptor"&gt;
  129. &lt;property name="validateConfigAttributes"&gt;&lt;value&gt;true&lt;/value&gt;&lt;/property&gt;
  130. &lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
  131. &lt;property name="accessDecisionManager"&gt;&lt;ref bean="accessDecisionManager"/&gt;&lt;/property&gt;
  132. &lt;property name="runAsManager"&gt;&lt;ref bean="runAsManager"/&gt;&lt;/property&gt;
  133. &lt;property name="methodDefinitionSource"&gt;
  134. &lt;value&gt;
  135. net.sf.acegisecurity.context.BankManager.delete*=ROLE_SUPERVISOR,RUN_AS_SERVER
  136. net.sf.acegisecurity.context.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR,BANKSECURITY_CUSTOMER,RUN_AS_SERVER
  137. &lt;/value&gt;
  138. &lt;/property&gt;
  139. &lt;/bean&gt;</programlisting></para>
  140. <para>As shown above, the <literal>SecurityInterceptor</literal> is
  141. configured with a reference to an
  142. <literal>AuthenticationManager</literal>,
  143. <literal>AccessDecisionManager</literal> and
  144. <literal>RunAsManager</literal>, which are each discussed in separate
  145. sections below. The <literal>SecurityInterceptor</literal> is also
  146. configured with "configuration attributes" that apply to different
  147. method signatures. A configuration attribute is simply a
  148. <literal>ConfigAttribute</literal> instance that has special meaning
  149. to an <literal>AccessDecisionManager</literal> and/or
  150. <literal>RunAsManager</literal>.</para>
  151. <para>The <literal>SecurityInterceptor</literal> can be configured
  152. with configuration attributes in three ways. The first is via a
  153. property editor and the bean context, which is shown above. The second
  154. is via defining the configuration attributes in your source code using
  155. Commons Attributes. The third is via writing your own
  156. <literal>MethodDefinitionSource</literal>, although this is beyond the
  157. scope of this document. Irrespective of the approach used, the
  158. <literal>MethodDefinitionSource</literal> is responsible for returning
  159. a <literal>ConfigAttributeDefinition</literal> object that contains
  160. all of the configuration attributes associated with a single secure
  161. method.</para>
  162. <para>If using the property editor approach (as shown above), commas
  163. are used to delimit the different configuration attributes that apply
  164. to a given method pattern. Each configuration attribute is assigned
  165. into its own <literal>SecurityConfig</literal> object.
  166. <literal>SecurityConfig</literal> is a concrete implementation of
  167. <literal>ConfigAttribute</literal>, and simply stores the
  168. configuration attribute as a <literal>String</literal>.</para>
  169. <para>If using the Commons Attributes approach, your bean context will
  170. be configured differently:</para>
  171. <para><programlisting>&lt;bean id="attributes" class="org.springframework.metadata.commons.CommonsAttributes"/&gt;
  172. &lt;bean id="methodDefinitionSource" class="net.sf.acegisecurity.MethodDefinitionAttributes"&gt;
  173. &lt;property name="attributes"&gt;&lt;ref local="attributes"/&gt;&lt;/property&gt;
  174. &lt;/bean&gt;
  175. &lt;bean id="bankManagerSecurity" class="net.sf.acegisecurity.SecurityInterceptor"&gt;
  176. &lt;property name="validateConfigAttributes"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;
  177. &lt;property name="authenticationManager"&gt;&lt;ref bean="authenticationManager"/&gt;&lt;/property&gt;
  178. &lt;property name="accessDecisionManager"&gt;&lt;ref bean="accessDecisionManager"/&gt;&lt;/property&gt;
  179. &lt;property name="runAsManager"&gt;&lt;ref bean="runAsManager"/&gt;&lt;/property&gt;
  180. &lt;property name="methodDefinitionSource"&gt;&lt;ref bean="methodDefinitionSource"/&gt;&lt;/property&gt;
  181. &lt;/bean&gt;</programlisting></para>
  182. <para>In addition, your source code will contain Commons Attributes
  183. tags that refer to a concrete implementation of
  184. <literal>ConfigAttribute</literal>. The following example uses the
  185. <literal>SecurityConfig</literal> implementation to represent the
  186. configuration attributes, and results in the same security
  187. configuration as provided by the property editor approach
  188. above:</para>
  189. <para><programlisting>public interface BankManager {
  190. /**
  191. * @@SecurityConfig("ROLE_SUPERVISOR")
  192. * @@SecurityConfig("RUN_AS_SERVER")
  193. */
  194. public void deleteSomething(int id);
  195. /**
  196. * @@SecurityConfig("ROLE_SUPERVISOR")
  197. * @@SecurityConfig("RUN_AS_SERVER")
  198. */
  199. public void deleteAnother(int id);
  200. /**
  201. * @@SecurityConfig("ROLE_TELLER")
  202. * @@SecurityConfig("ROLE_SUPERVISOR")
  203. * @@SecurityConfig("BANKSECURITY_CUSTOMER")
  204. * @@SecurityConfig("RUN_AS_SERVER")
  205. */
  206. public float getBalance(int id);
  207. }</programlisting></para>
  208. <para>You might have noticed the
  209. <literal>validateConfigAttributes</literal> property in the above
  210. <literal>SecurityInterceptor</literal> examples. When set to
  211. <literal>true</literal> (the default), at startup time the
  212. <literal>SecurityInterceptor</literal> will evaluate if the provided
  213. configuration attributes are valid. It does this by checking each
  214. configuration attribute can be processed by either the
  215. <literal>AccessDecisionManager</literal> or the
  216. <literal>RunAsManager</literal>. If neither of these can process a
  217. given configuration attribute, an exception is thrown. If using the
  218. Commons Attributes method of configuration, you should set
  219. <literal>validateConfigAttributes</literal> to
  220. <literal>false</literal>.</para>
  221. </sect2>
  222. <sect2 id="security-interception-runtime-processing">
  223. <title>Runtime Processing</title>
  224. <para>At runtime the <literal>SecurityInterceptor</literal> has three
  225. basic tasks: authenticate, authorize and perform any run-as
  226. authentication replacement. It assesses the method pattern being
  227. invoked to determine whether or not it is secure. A secure method
  228. matches a method pattern defined with configuration attributes in the
  229. bean context, whilst a public method is not defined in the bean
  230. context.</para>
  231. <para>If a public method is called,
  232. <literal>SecurityInterceptor</literal> will make no effort to
  233. authenticate, authorize or perform any run-as authentication
  234. replacement for the request. However, should there be an
  235. <literal>Authentication</literal> object in the
  236. <literal>ContextHolder</literal>, it will have its authenticated
  237. property set to <literal>false</literal>. Once this is handled,
  238. invocation of the public method will proceed as normal.</para>
  239. <para>If a secure method is called,
  240. <literal>SecurityInterceptor</literal> will need to extract an
  241. <literal>Authentication</literal> object from the request context. As
  242. discussed above, the <literal>SecurityInterceptor</literal> requires
  243. the <literal>SecureContext</literal> interface be implemented on the
  244. object contained in the <literal>ContextHolder</literal>. Once the
  245. <literal>Authentication</literal> object is extracted from the
  246. <literal>SecureContext</literal>, it will be passed to the
  247. <literal>SecurityInterceptor</literal>’s
  248. <literal>AuthenticationManager</literal>.</para>
  249. <para>The <literal>AuthenticationManager</literal> will perform
  250. authentication, throwing an <literal>AuthenticationException</literal>
  251. if there is a problem. If successful, the
  252. <literal>AuthenticationManager</literal> will return a populated
  253. <literal>Authentication</literal> object, including the authorities
  254. granted to the principal. <literal>SecurityInterceptor</literal> will
  255. then call its <literal>AccessDecisionManager</literal>.</para>
  256. <para>When the <literal>AccessDecisionManager</literal> is invoked by
  257. the <literal>SecurityInterceptor</literal>, it will be passed
  258. important information it may require to make an authorization
  259. decision. This includes details of the secure method that is being
  260. invoked, the authenticated principal, and the
  261. <literal>ConfigAttributeDefinition</literal> (the collection of
  262. configuration attributes associated with the secure method). If
  263. authorization fails, the <literal>AccessDecisionManager</literal> will
  264. throw an <literal>AccessDeniedException</literal>. If successful, the
  265. <literal>SecurityInterceptor</literal> will then call the
  266. <literal>RunAsManager</literal>.</para>
  267. <para>Like the <literal>AccessDecisionManager</literal>, the
  268. <literal>RunAsManager</literal> is called with details of the secure
  269. method being invoked, the authenticated principal, and the
  270. <literal>ConfigAttributeDefinition</literal>. The
  271. <literal>RunAsManager</literal> can then choose to return a
  272. replacement <literal>Authentication</literal> object that should be
  273. used for the request. If a replacement
  274. <literal>Authentication</literal> object is returned, the
  275. <literal>SecurityInterceptor</literal> will update the
  276. <literal>ContextHolder</literal> for the duration of the method
  277. invocation, returning to the original
  278. <literal>Authentication</literal> object after the method has been
  279. invoked.</para>
  280. </sect2>
  281. <sect2>
  282. <title>Putting it into Context</title>
  283. <para>The above briefly outlines that the
  284. <literal>AuthenticationManager</literal>,
  285. <literal>AccessDecisionManager</literal> and
  286. <literal>RunAsManager</literal> perform the bulk of the security
  287. decision making. The <literal>SecurityInterceptor</literal> simply
  288. coordinates the method invocation and stores the configuration
  289. attributes that are relevant to different methods. It also coordinates
  290. the temporary replacement of the <literal>Authentication</literal>
  291. object as a consequence of <literal>RunAsManager</literal> responses.
  292. The way <literal>AuthenticationManager</literal>,
  293. <literal>AccessDecisionManager</literal> and
  294. <literal>RunAsManager</literal> operate is discussed in detail
  295. below.</para>
  296. </sect2>
  297. </sect1>
  298. <sect1 id="security-authentication">
  299. <title>Authentication</title>
  300. <sect2 id="security-authentication-requests">
  301. <title>Authentication Requests</title>
  302. <para>Authentication requires a way for client code to present its
  303. security identification to the Acegi Security System for Spring. This
  304. is the role of the <literal>Authentication</literal> interface. The
  305. <literal>Authentication</literal> interface holds three important
  306. objects: the principal (the identity of the caller), the credentials
  307. (the proof of the identity of the caller, such as a password), and the
  308. authorities that have been granted to the principal. The principal and
  309. its credentials are populated by the client code, whilst the granted
  310. authorities are populated by the
  311. <literal>AuthenticationManager</literal>. The Acegi Security System
  312. for Spring includes several concrete Authentication
  313. implementations:</para>
  314. <itemizedlist spacing="compact">
  315. <listitem>
  316. <para><literal>UsernamePasswordAuthenticationToken</literal>
  317. allows a username and password to be presented as the principal
  318. and credentials respectively.</para>
  319. </listitem>
  320. <listitem>
  321. <para><literal>TestingAuthenticationToken</literal> facilitates
  322. unit testing by automatically being considered an authenticated
  323. object by its associated
  324. <literal>AuthenticationProvider</literal>.</para>
  325. </listitem>
  326. <listitem>
  327. <para><literal>RunAsUserToken</literal> is used by the default
  328. run-as authentication replacement implementation. This is
  329. discussed further in the Run-As Authentication Replacement
  330. section.</para>
  331. </listitem>
  332. <listitem>
  333. <para><literal>PrincipalAcegiUserToken</literal> and
  334. <literal>JettyAcegiUserToken</literal> implement
  335. <literal>AuthByAdapter</literal> (a subclass of
  336. <literal>Authentication</literal>) and are used whenever
  337. authentication is completed by Acegi Security System for Spring
  338. container adapters. This is discussed further in the Container
  339. Adapters section.</para>
  340. </listitem>
  341. </itemizedlist>
  342. <para>The authorities granted to a principal are represented by the
  343. <literal>GrantedAuthority</literal> interface. The
  344. <literal>GrantedAuthority</literal> interface is discussed at length
  345. in the Authorization section.</para>
  346. </sect2>
  347. <sect2 id="security-authentication-manager">
  348. <title>Authentication Manager</title>
  349. <para>As discussed in the Security Interception section, the
  350. <literal>SecurityInterceptor</literal> extracts the
  351. <literal>Authentication</literal> object from the
  352. <literal>SecureContext</literal>. This is then passed to an
  353. <literal>AuthenticationManager</literal>. The
  354. <literal>AuthenticationManager</literal> interface is very
  355. simple:</para>
  356. <programlisting>public Authentication authenticate(Authentication authentication) throws AuthenticationException;</programlisting>
  357. <para>Implementations of <literal>AuthenticationManager</literal> are
  358. required to throw an <literal>AuthenticationException</literal> should
  359. authentication fail, or return a fully populated
  360. <literal>Authentication</literal> object. In particular, the returned
  361. <literal>Authentication</literal> object should contain an array of
  362. <literal>GrantedAuthority</literal> objects. The
  363. <literal>SecurityInterceptor</literal> places the populated
  364. <literal>Authentication</literal> object back in the
  365. <literal>SecureContext</literal>, overwriting the original
  366. <literal>Authentication</literal> object.</para>
  367. <para>The <literal>AuthenticationException</literal> has a number of
  368. subclasses. The most important are
  369. <literal>BadCredentialsException</literal> (an incorrect principal or
  370. credentials), <literal>DisabledException</literal> and
  371. <literal>LockedException</literal>. The latter two exceptions indicate
  372. the principal was found, but the credentials were not checked and
  373. authentication is denied. An
  374. <literal>AuthenticationServiceException</literal> is also provided,
  375. which indicates the authentication system could not process the
  376. request (eg a database was unavailable).</para>
  377. </sect2>
  378. <sect2>
  379. <title>Provider-Based Authentication</title>
  380. <para>Whilst the basic <literal>Authentication</literal> and
  381. <literal>AuthenticationManager</literal> interfaces enable users to
  382. develop their own authentication systems, users should consider using
  383. the provider-based authentication packages provided in the Acegi
  384. Security System for Spring. The key class,
  385. <literal>ProviderManager</literal>, is configured via the bean context
  386. with a list of <literal>AuthenticationProvider</literal>s:</para>
  387. <para><programlisting>&lt;bean id="authenticationManager" class="net.sf.acegisecurity.providers.ProviderManager"&gt;
  388. &lt;property name="providers"&gt;
  389. &lt;list&gt;
  390. &lt;ref bean="daoAuthenticationProvider"/&gt;
  391. &lt;/list&gt;
  392. &lt;/property&gt;
  393. &lt;/bean&gt;</programlisting></para>
  394. <para><literal>ProviderManager</literal> calls a series of registered
  395. <literal>AuthenticationProvider</literal> implementations, until one
  396. is found that indicates it is able to authenticate a given
  397. <literal>Authentication</literal> class. When the first compatible
  398. <literal>AuthenticationProvider</literal> is located, it is passed the
  399. authentication request. The <literal>AuthenticationProvider</literal>
  400. will then either throw an <literal>AuthenticationException</literal>
  401. or return a fully populated <literal>Authentication</literal>
  402. object.</para>
  403. <para>Note the <literal>ProviderManager</literal> may throw a
  404. <literal>ProviderNotFoundException</literal> (subclass of
  405. <literal>AuthenticationException</literal>) if it none of the
  406. registered <literal>AuthenticationProviders</literal> can validate the
  407. <literal>Authentication</literal> object.</para>
  408. <para>Several <literal>AuthenticationProvider</literal>
  409. implementations are provided with the Acegi Security System for
  410. Spring:</para>
  411. <para><itemizedlist spacing="compact">
  412. <listitem>
  413. <para><literal>TestingAuthenticationProvider</literal> is able
  414. to authenticate a <literal>TestingAuthenticationToken</literal>.
  415. The limit of its authentication is simply to treat whatever is
  416. contained in the <literal>TestingAuthenticationToken</literal>
  417. as valid. This makes it ideal for use during unit testing, as
  418. you can create an <literal>Authentication</literal> object with
  419. precisely the <literal>GrantedAuthority</literal> objects
  420. required for calling a given method.</para>
  421. </listitem>
  422. <listitem>
  423. <para><literal>DaoAuthenticationProvider</literal> is able to
  424. authenticate a
  425. <literal>UsernamePasswordAuthenticationToken</literal> by
  426. accessing an authentication respository via a data access
  427. object. This is discussed further below.</para>
  428. </listitem>
  429. <listitem>
  430. <para><literal>RunAsImplAuthenticationToken</literal> is able to
  431. authenticate a <literal>RunAsUserToken</literal>. This is
  432. discussed further in the Run-As Authentication Replacement
  433. section.</para>
  434. </listitem>
  435. <listitem>
  436. <para><literal>AuthByAdapterProvider</literal> is able to
  437. authenticate any <literal>AuthByAdapter</literal> (a subclass of
  438. <literal>Authentication</literal> used with container adapters).
  439. This is discussed further in the Container Adapters
  440. section.</para>
  441. </listitem>
  442. </itemizedlist></para>
  443. </sect2>
  444. <sect2>
  445. <title>Data Access Object Authentication Provider</title>
  446. <para>The Acegi Security System for Spring includes a
  447. production-quality <literal>AuthenticationProvider</literal>
  448. implementation called <literal>DaoAuthenticationProvider</literal>.
  449. This authentication provider is able to authenticate a
  450. <literal>UsernamePasswordAuthenticationToken</literal> by obtaining
  451. authentication details from a data access object configured at bean
  452. creation time:</para>
  453. <para><programlisting>&lt;bean id="daoAuthenticationProvider" class="net.sf.acegisecurity.providers.dao.DaoAuthenticationProvider"&gt;
  454. &lt;property name="authenticationDao"&gt;&lt;ref bean="inMemoryDaoImpl"/&gt;&lt;/property&gt;
  455. &lt;property name="ignorePasswordCase"&gt;&lt;value&gt;false&lt;/value&gt;&lt;/property&gt;
  456. &lt;property name="ignoreUsernameCase"&gt;&lt;value&gt;true&lt;/value&gt;&lt;/property&gt;
  457. &lt;/bean&gt;</programlisting></para>
  458. <para>By default the <literal>DaoAuthenticationProvider</literal> does
  459. not require an exact match on usernames, but it does require an exact
  460. match on passwords. This behavior can be configured with the optional
  461. properties shown above.</para>
  462. <para>For a class to be able to provide the
  463. <literal>DaoAuthenticationProvider</literal> with access to an
  464. authentication repository, it must implement the
  465. <literal>AuthenticationDao</literal> interface:</para>
  466. <para><programlisting>public User loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException;</programlisting></para>
  467. <para>The <literal>User</literal> object holds basic information such
  468. as the username, password, granted authorities and whether the user is
  469. enabled or disabled.</para>
  470. <para>Given <literal>AuthenticationDao</literal> is so simple to
  471. implement, it should be easy for users to retrieve authentication
  472. information using a persistence strategy of their choice.</para>
  473. <para>A design decision was made not to support account locking in the
  474. <literal>DaoAuthenticationProvider</literal>, as doing so would have
  475. increased the complexity of the <literal>AuthenticationDao</literal>
  476. interface. Such functionality could be easily provided in a new
  477. <literal>AuthenticationManager</literal> or
  478. <literal>AuthenticationProvider</literal> implementation.</para>
  479. </sect2>
  480. <sect2>
  481. <title>In-Memory Authentication</title>
  482. <para>Whilst it is easy to use the
  483. <literal>DaoAuthenticationProvider</literal> and create a custom
  484. <literal>AuthenticationDao</literal> implementation that extracts
  485. information from a persistence engine of choice, many applications do
  486. not require such complexity. One alternative is to configure an
  487. authentication repository in the bean context itself using the
  488. <literal>InMemoryDaoImpl</literal>:</para>
  489. <para><programlisting>&lt;bean id="inMemoryDaoImpl" class="net.sf.acegisecurity.providers.dao.memory.InMemoryDaoImpl"&gt;
  490. &lt;property name="userMap"&gt;
  491. &lt;value&gt;
  492. marissa=koala,ROLE_TELLER,ROLE_SUPERVISOR
  493. dianne=emu,ROLE_TELLER
  494. scott=wombat,ROLE_TELLER
  495. peter=opal,disabled,ROLE_TELLER
  496. &lt;/value&gt;
  497. &lt;/property&gt;
  498. &lt;/bean&gt;</programlisting></para>
  499. <para>The <literal>userMap</literal> property contains each of the
  500. usernames, passwords, a list of granted authorities and an optional
  501. enabled/disabled keyword. Commas delimit each token. The username must
  502. appear to the left of the equals sign, and the password must be the
  503. first token to the right of the equals sign. The
  504. <literal>enabled</literal> and <literal>disabled</literal> keywords
  505. (case insensitive) may appear in the second or any subsequent token.
  506. Any remaining tokens are treated as granted authorities, which are
  507. created as <literal>GrantedAuthorityImpl</literal> objects (refer to
  508. the Authorization section for further discussion on granted
  509. authorities). Note that if a user has no password or no granted
  510. authorities, the user will not be created in the in-memory
  511. authentication repository.</para>
  512. </sect2>
  513. <sect2>
  514. <title>JDBC Authentication</title>
  515. <para>The Acegi Security System for Spring also includes an
  516. authentication provider that can obtain authentication information
  517. from a JDBC data source. The typical configuration for the
  518. <literal>JdbcDaoImpl</literal> is shown below:</para>
  519. <para><programlisting>&lt;bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"&gt;
  520. &lt;property name="driverClassName"&gt;&lt;value&gt;org.hsqldb.jdbcDriver&lt;/value&gt;&lt;/property&gt;
  521. &lt;property name="url"&gt;&lt;value&gt;jdbc:hsqldb:hsql://localhost:9001&lt;/value&gt;&lt;/property&gt;
  522. &lt;property name="username"&gt;&lt;value&gt;sa&lt;/value&gt;&lt;/property&gt;
  523. &lt;property name="password"&gt;&lt;value&gt;&lt;/value&gt;&lt;/property&gt;
  524. &lt;/bean&gt;
  525. &lt;!-- Data access object which stores authentication information --&gt;
  526. &lt;bean id="jdbcDaoImpl" class="net.sf.acegisecurity.providers.dao.jdbc.JdbcDaoImpl"&gt;
  527. &lt;property name="dataSource"&gt;&lt;ref bean="dataSource"/&gt;&lt;/property&gt;
  528. &lt;/bean&gt;</programlisting></para>
  529. <para>You can use different relational database management systems by
  530. modifying the <literal>DriverManagerDataSource</literal> shown above.
  531. Irrespective of the database used, a standard schema must be used as
  532. indicated in <literal>dbinit.txt</literal>.</para>
  533. <para>The Acegi Security System for Spring ships with a Hypersonic SQL
  534. instance that has the required authentication information and sample
  535. data already populated. To use this server, simply execute the
  536. <literal>server.bat</literal> or <literal>server.sh</literal> script
  537. included in the distribution. This will load a new database server
  538. instance that will service requests made to the URL indicated in the
  539. bean context configuration shown above.</para>
  540. <para>As discussed further in the Container Adapters section, most
  541. authentication providers that perform actual authentication are
  542. configured within a container adapter bean context typically called
  543. <literal>acegisecurity.xml</literal>. This file by default uses the
  544. in-memory DAO authentication provider. The Acegi Security System for
  545. Spring includes an alternative configuration file named
  546. <literal>acegisecurity-jdbc.xml</literal>, which uses the JDBC DAO
  547. authentication provider. To use a JDBC authentication repository,
  548. simply copy this file over the existing
  549. <literal>acegisecurity.xml</literal> (or other name) being used by
  550. your container. Alternatively, leave the name as
  551. <literal>acegisecurity-jdbc.xml</literal> and modify your container
  552. configuration file to refer to
  553. <literal>acegisecurity-jdbc.xml</literal>. You will also need to copy
  554. the relevant JDBC driver library to your container's
  555. <literal>lib</literal> directory. If you are using Hypersonic SQL,
  556. copy the <literal>hsqldb.jar</literal> file.</para>
  557. </sect2>
  558. <sect2>
  559. <title>Authentication Recommendations</title>
  560. <para>With the heavy use of interfaces throughout the authentication
  561. system (<literal>Authentication</literal>,
  562. <literal>AuthenticationManager</literal>,
  563. <literal>AuthenticationProvider</literal> and
  564. <literal>AuthenticationDao</literal>) it might be confusing to a new
  565. user to know which part of the authentication system to customize. In
  566. general, the following is recommended:</para>
  567. <itemizedlist>
  568. <listitem>
  569. <para>Use the
  570. <literal>UsernamePasswordAuthenticationToken</literal> or an
  571. <literal>AuthByContainer</literal> implementation where
  572. possible.</para>
  573. </listitem>
  574. <listitem>
  575. <para>If you simply need to implement a new authentication
  576. repository (eg to obtain user details from your application’s
  577. existing database), use the
  578. <literal>DaoAuthenticationProvider</literal> along with the
  579. <literal>AuthenticationDao</literal>. It is the fastest and safest
  580. way to integrate an external database.</para>
  581. </listitem>
  582. <listitem>
  583. <para>Never enable the
  584. <literal>TestingAuthenticationProvider</literal> on a production
  585. system. Doing so will allow any client to simply present a
  586. <literal>TestingAuthenticationToken</literal> and obtain whatever
  587. access they request.</para>
  588. </listitem>
  589. <listitem>
  590. <para>Adding a new <literal>AuthenticationProvider</literal> is
  591. sufficient to support most custom authentication requirements.
  592. Only unusual requirements would require the
  593. <literal>ProviderManager</literal> to be replaced with a different
  594. <literal>AuthenticationManager</literal>.</para>
  595. </listitem>
  596. </itemizedlist>
  597. </sect2>
  598. </sect1>
  599. <sect1 id="security-authorization">
  600. <title>Authorization</title>
  601. <sect2>
  602. <title>Granted Authorities</title>
  603. <para>As briefly mentioned in the <literal>Authentication</literal>
  604. section, all <literal>Authentication</literal> implementations are
  605. required to store an array of <literal>GrantedAuthority</literal>
  606. objects. These represent the authorities that have been granted to the
  607. principal. The <literal>GrantedAuthority</literal> objects are
  608. inserted into the <literal>Authentication</literal> object by the
  609. <literal>AuthenticationManager</literal> and are later read by
  610. <literal>AccessDecisionManager</literal>s when making authorization
  611. decisions.</para>
  612. <para><literal>GrantedAuthority</literal> is an interface with only
  613. one method:</para>
  614. <para><programlisting>public String getAuthority();</programlisting></para>
  615. <para>This method allows <literal>AccessDecisionManager</literal>s to
  616. obtain a precise <literal>String</literal> representation of the
  617. <literal>GrantedAuthority</literal>. By returning a representation as
  618. a <literal>String</literal>, a <literal>GrantedAuthority</literal> can
  619. be easily "read" by most <literal>AccessDecisionManager</literal>s. If
  620. a <literal>GrantedAuthority</literal> cannot be precisely represented
  621. as a <literal>String</literal>, the
  622. <literal>GrantedAuthority</literal> is considered "complex" and
  623. <literal>getAuthority()</literal> must return
  624. <literal>null</literal>.</para>
  625. <para>An example of a "complex" <literal>GrantedAuthority</literal>
  626. would be an implementation that stores a list of operations and
  627. authority thresholds that apply to different customer account numbers.
  628. Representing this complex <literal>GrantedAuthority</literal> as a
  629. <literal>String</literal> would be quite complex, and as a result the
  630. <literal>getAuthority()</literal> method should return
  631. <literal>null</literal>. This will indicate to any
  632. <literal>AccessDecisionManager</literal> that it will need to
  633. specifically support the <literal>GrantedAuthority</literal>
  634. implementation in order to understand its contents.</para>
  635. <para>The Acegi Security System for Spring includes one concrete
  636. <literal>GrantedAuthority</literal> implementation,
  637. <literal>GrantedAuthorityImpl</literal>. This allows any
  638. user-specified <literal>String</literal> to be converted into a
  639. <literal>GrantedAuthority</literal>. All
  640. <literal>AuthenticationProvider</literal>s included with the security
  641. architecture used <literal>GrantedAuthorityImpl</literal> to populate
  642. the <literal>Authentication</literal> object.</para>
  643. </sect2>
  644. <sect2>
  645. <title>Access Decision Managers</title>
  646. <para>The <literal>AccessDecisionManager</literal> is called by the
  647. <literal>SecurityInterceptor</literal> and is responsible for making
  648. final access control decisions. The
  649. <literal>AccessDecisionManager</literal> interface contains two
  650. methods:</para>
  651. <para><programlisting>public void decide(Authentication authentication, MethodInvocation invocation, ConfigAttributeDefinition config) throws AccessDeniedException;
  652. public boolean supports(ConfigAttribute attribute);</programlisting></para>
  653. <para>As can be seen from the first method, the
  654. <literal>AccessDecisionManager</literal> is passed via method
  655. parameters all information that is likely to be of value in assessing
  656. an authorization decision. In particular, passing the
  657. <literal>MethodInvocation</literal> enables those arguments contained
  658. in the intercepted method call to be inspected. For example, if a
  659. <literal>Customer</literal> argument was passed in the intercepted
  660. method call, this could be extracted from the
  661. <literal>MethodInvocation</literal> and used in making an access
  662. control decision. Implementations are expected to throw an
  663. <literal>AccessDeniedException</literal> if access is denied.</para>
  664. <para>The <literal>supports(ConfigAttribute)</literal> method is
  665. called by the <literal>SecurtyInterceptor</literal> at startup time to
  666. determine if the <literal>AccessDecisionManager</literal> can process
  667. the passed <literal>ConfigAttribute</literal>.</para>
  668. </sect2>
  669. <sect2>
  670. <title>Voting Decision Manager</title>
  671. <para>Whilst users can implement their own
  672. <literal>AccessDecisionManager</literal> to control all aspects of
  673. authorization, the Acegi Security System for Spring includes an
  674. <literal>AccessDecisionManager</literal> implementation that is based
  675. on voting. Using this approach, a series of
  676. <literal>AccessDecisionVoter</literal> implementations are polled on
  677. an authorization decision. The
  678. <literal>AccessDecisionManager</literal> then decides whether or not
  679. to throw an <literal>AccessDeniedException</literal> based on its
  680. assessment of the votes.</para>
  681. <para>The <literal>AccessDecisionVoter</literal> interface has two
  682. methods:</para>
  683. <para><programlisting>public int vote(Authentication authentication, MethodInvocation invocation, ConfigAttributeDefinition config);
  684. public boolean supports(ConfigAttribute attribute);</programlisting></para>
  685. <para>Concrete implementations return an int, with possible values
  686. being reflected in the <literal>AccessDecisionVoter</literal> static
  687. fields <literal>ACCESS_ABSTAIN</literal>,
  688. <literal>ACCESS_DENIED</literal> and
  689. <literal>ACCESS_GRANTED</literal>. A voting implementation will return
  690. <literal>ACCESS_ABSTAIN</literal> if it has no opinion on an
  691. authorization decision. If it does have an opinion, it must return
  692. either <literal>ACCESS_DENIED</literal> or
  693. <literal>ACCESS_GRANTED</literal>.</para>
  694. <para>There are three <literal>AccessDecisionManager</literal>s
  695. provided with the Acegi Security System for Spring that tally the
  696. votes. The <literal>ConsensusBased</literal> implementation will grant
  697. or deny access based on the consensus of non-abstain votes. Properties
  698. are provided to control behavior in the event of an equality of votes
  699. or if all votes are abstain. The <literal>AffirmativeBased</literal>
  700. implementation will grant access if one or more
  701. <literal>ACCESS_GRANTED</literal> votes were received (ie a deny vote
  702. will be ignored, provided there was at least one grant vote). Like the
  703. <literal>ConsensusBased</literal> implementation, there is a parameter
  704. that controls the behavior if all voters abstain. The
  705. <literal>UnanimousBased</literal> provider will deny access if there
  706. was any <literal>ACCESS_DENIED</literal> result. Like the other
  707. implementations, there is a parameter that controls the behaviour if
  708. all voters abstain.</para>
  709. <para>It is possible to implement a custom
  710. <literal>AccessDecisionManager</literal> that tallies votes
  711. differently. For example, votes from a particular
  712. <literal>AccessDecisionVoter</literal> might receive additional
  713. weighting, whilst a deny vote from a particular voter would have a
  714. veto effect.</para>
  715. <para>There is one concrete <literal>AccessDecisionVoter</literal>
  716. implementation provided with the Acegi Security System for Spring. The
  717. <literal>RoleVoter</literal> class will vote if any ConfigAttribute
  718. begins with <literal>ROLE_</literal>. It will vote to grant access if
  719. there is a <literal>GrantedAuthority</literal> which returns a
  720. <literal>String</literal> representation (via the
  721. <literal>getAuthority()</literal> method) exactly equal to one or more
  722. <literal>ConfigAttributes</literal> starting with
  723. <literal>ROLE_</literal>. If there is no exact match of any
  724. <literal>ConfigAttribute</literal> starting with
  725. <literal>ROLE_</literal>, the <literal>RoleVoter</literal> will vote
  726. to deny access. If no <literal>ConfigAttribute</literal> begins with
  727. <literal>ROLE_</literal>, the voter will abstain.
  728. <literal>RoleVoter</literal> is case sensitive on comparisons as well
  729. as the <literal>ROLE_</literal> prefix.</para>
  730. <para>It is possible to implement a custom
  731. <literal>AccessDecisionVoter</literal>. Several examples are provided
  732. in the Acegi Security System for Spring unit tests, including
  733. <literal>BankSecurityVoter</literal> and <literal>XVoter</literal>.
  734. The <literal>BankSecurityVoter</literal> abstains from voting
  735. decisions where the <literal>BANKSECURITY_CUSTOMER</literal>
  736. <literal>ConfigAttribute</literal> is not found. If voting, it queries
  737. the <literal>MethodInvocation</literal> to extract the account number
  738. subject of the method call. It votes to grant access if the account
  739. number matches a <literal>GrantedAuthority.getAuthority()</literal> of
  740. <literal>ACCOUNT_xxxx</literal> where <literal>xxxx</literal> is the
  741. account number subject of the method call. All of this is achieved
  742. with relatively few lines of code and demonstrates the flexibility of
  743. the authorization model.</para>
  744. <para>Note that an <literal>AccessDecisionManager</literal> or
  745. <literal>AccessDecisionVoter</literal> can also support complex
  746. <literal>GrantedAuthority</literal> implementations that cannot
  747. represent themselves as a <literal>String</literal> via the
  748. <literal>getAuthority()</literal> method. In our
  749. <literal>BankSecurityVoter</literal> example, we could have it ignore
  750. the <literal>String</literal> representations of
  751. <literal>GrantedAuthority</literal> objects but instead processed any
  752. <literal>AccountHolderGrantedAuthority</literal> objects. This complex
  753. granted authority could have conveyed more information than simply an
  754. account number, such as the maximum amount the principal is permitted
  755. to deposit. The <literal>BankSecurityVoter</literal> could then detect
  756. a deposit value via the <literal>MethodInvocation</literal> and grant
  757. or deny access accordingly.</para>
  758. </sect2>
  759. <sect2>
  760. <title>Authorization Recommendations</title>
  761. <para>Given there are several ways to achieve similar authorization
  762. outcomes in the Acegi Security System for Spring, the following
  763. general recommendations are made:</para>
  764. <itemizedlist>
  765. <listitem>
  766. <para>Grant authorities using
  767. <literal>GrantedAuthorityImpl</literal> where possible. Because it
  768. is already supported by the Acegi Security System for Spring, you
  769. avoid the need to create custom
  770. <literal>AuthenticationManager</literal> or
  771. <literal>AuthenticationProvider</literal> implementations simply
  772. to populate the <literal>Authentication</literal> object with a
  773. custom <literal>GrantedAuthority</literal>.</para>
  774. </listitem>
  775. <listitem>
  776. <para>Most authorization decision rules can be easily satisfied by
  777. writing an <literal>AccessDecisionVoter</literal> implementation
  778. and using either <literal>ConsensusBased</literal> or
  779. <literal>AffirmativeBased</literal> as the
  780. <literal>AccessDecisionManager</literal>.</para>
  781. </listitem>
  782. </itemizedlist>
  783. </sect2>
  784. <sect2>
  785. <title>Authorization Tag Library</title>
  786. <para>The Acegi Security System for Spring comes bundled with a
  787. JSP tag library that eases JSP writing.</para>
  788. <sect3>
  789. <title>Installation</title>
  790. </sect3>
  791. <sect3>
  792. <title>Usage</title>
  793. <para>The following JSP fragment illustrates how to use the
  794. authz taglib:</para>
  795. <para><programlisting>&lt;authz:authorize ifAllGranted="ROLE_SUPERVISOR"&gt;
  796. &lt;td&gt;
  797. &lt;A HREF="del.htm?id=&lt;c:out value="${contact.id}"/&gt;"&gt;Del&lt;/A&gt;
  798. &lt;/td&gt;
  799. &lt;/authz:authorize&gt;</programlisting></para>
  800. <para>What this code says is: if the pricipal has been granted
  801. ROLE_SUPERVISOR, allow the tag's body to be output.</para>
  802. </sect3>
  803. </sect2>
  804. </sect1>
  805. <sect1>
  806. <title>Run-As Authentication Replacement</title>
  807. <sect2>
  808. <title>Purpose</title>
  809. <para>The SecurityInterceptor is able to temporarily replace the
  810. <literal>Authentication</literal> object in the
  811. <literal>ContextHolder</literal> during a method invocation. This only
  812. occurs if the original <literal>Authentication</literal> object was
  813. successfully processed by the <literal>AuthenticationManager</literal>
  814. and <literal>AccessDecisionManager</literal>. The
  815. <literal>RunAsManager</literal> will indicate the replacement
  816. <literal>Authentication</literal> object (if any) that should be used
  817. during the method invocation.</para>
  818. <para>By temporarily replacing the <literal>Authentication</literal>
  819. object during a method invocation, the method invocation will be able
  820. to call other objects which require different authentication and
  821. authorization credentials. It will also be able to perform any
  822. internal security checks for specific
  823. <literal>GrantedAuthority</literal> objects.</para>
  824. </sect2>
  825. <sect2>
  826. <title>Usage</title>
  827. <para>A <literal>RunAsManager</literal> interface is provided by the
  828. Acegi Security System for Spring:</para>
  829. <para><programlisting>public Authentication buildRunAs(Authentication authentication, MethodInvocation invocation, ConfigAttributeDefinition config);
  830. public boolean supports(ConfigAttribute attribute);</programlisting></para>
  831. <para>The first method returns the <literal>Authentication</literal>
  832. object that should replace the existing
  833. <literal>Authentication</literal> object for the duration of the
  834. method invocation. If the method returns <literal>null</literal>, it
  835. indicates no replacement should be made. The second method is used by
  836. the <literal>SecurityInterceptor</literal> as part of its startup
  837. validation of configuration attributes.</para>
  838. <para>One concrete implementation of a <literal>RunAsManager</literal>
  839. is provided with the Acegi Security System for Spring. The
  840. <literal>RunAsManagerImpl</literal> class returns a replacement
  841. <literal>RunAsUserToken</literal> if any
  842. <literal>ConfigAttribute</literal> starts with
  843. <literal>RUN_AS_</literal>. If any <literal>such
  844. ConfigAttribute</literal> is found, the replacement
  845. <literal>RunAsUserToken</literal> will contain the same principal,
  846. credentials and granted authorities as the original
  847. <literal>Authentication</literal> object, along with a new
  848. <literal>GrantedAuthorityImpl</literal> for each
  849. <literal>RUN_AS_</literal> <literal>ConfigAttribute</literal>. Each
  850. new <literal>GrantedAuthorityImpl</literal> will be prefixed with
  851. <literal>ROLE_</literal>, followed by the <literal>RUN_AS</literal>
  852. <literal>ConfigAttribute</literal>. For example, a
  853. <literal>RUN_AS_SERVER</literal> will result in the replacement
  854. <literal>RunAsUserToken</literal> containing a
  855. <literal>ROLE_RUN_AS_SERVER</literal> granted authority.</para>
  856. <para>The replacement <literal>RunAsUserToken</literal> is just like
  857. any other <literal>Authentication</literal> object. It needs to be
  858. authenticated by the <literal>AuthenticationManager</literal>,
  859. probably via delegation to <literal>a suitable
  860. AuthenticationProvider</literal>. The
  861. <literal>RunAsImplAuthenticationProvider</literal> performs such
  862. authentication. It simply accepts as valid whatever
  863. <literal>RunAsUserToken</literal> is presented.</para>
  864. <para>To ensure malicious code does not create a
  865. <literal>RunAsUserToken</literal> and presents it for guaranteed
  866. acceptance by the <literal>RunAsImplAuthenticationProvider</literal>,
  867. the hash of a key is stored in all generated tokens. The
  868. <literal>RunAsManagerImpl</literal> and
  869. <literal>RunAsImplAuthenticationProvider</literal> is created in the
  870. bean context with the same key:</para>
  871. <para><programlisting>&lt;bean id="runAsManager" class="net.sf.acegisecurity.runas.RunAsManagerImpl"&gt;
  872. &lt;property name="key"&gt;&lt;value&gt;my_run_as_password&lt;/value&gt;&lt;/property&gt;
  873. &lt;/bean&gt;</programlisting><programlisting>&lt;bean id="runAsAuthenticationProvider" class="net.sf.acegisecurity.runas.RunAsImplAuthenticationProvider"&gt;
  874. &lt;property name="key"&gt;&lt;value&gt;my_run_as_password&lt;/value&gt;&lt;/property&gt;
  875. &lt;/bean&gt;</programlisting></para>
  876. <para>By using the same key, each <literal>RunAsUserToken</literal>
  877. can be validated it was created by an approved
  878. <literal>RunAsManagerImpl</literal>. The
  879. <literal>RunAsUserToken</literal> is immutable after creation for
  880. security reasons.</para>
  881. </sect2>
  882. </sect1>
  883. <sect1 id="security-container-adapters">
  884. <title>Container Adapters</title>
  885. <sect2>
  886. <title>Overview</title>
  887. <para>A very large proportion of Spring applications are web-based.
  888. The Acegi Security System for Spring supports integration with
  889. containers that host such applications. This integration means that
  890. applications can continue to leverage the authentication and
  891. authorization capabilities built into containers (such as
  892. <literal>isUserInRole()</literal> and form-based or basic
  893. authentication), whilst benefiting from the enhanced bean-level
  894. security capabilities provided by the Acegi Security System for
  895. Spring.</para>
  896. <para>The integration between a container and the Acegi Security
  897. System for Spring is achieved through an adapter. The adapter provides
  898. a container-compatible user authentication provider, and often needs
  899. to return a container-compatible user object.</para>
  900. <para>The adapter is instantiated by the container and is defined in a
  901. container-specific configuration file. The adapter then loads a Spring
  902. bean context which defines the normal authentication manager settings,
  903. such as the authentication providers that can be used to authenticate
  904. the request. The bean context is usually named
  905. <literal>acegisecurity.xml</literal> and is placed in a
  906. container-specific location.</para>
  907. <para>The Acegi Security System for Spring currently supports Jetty,
  908. Catalina (Tomcat), JBoss and Resin. Additional container adapters can
  909. easily be written.</para>
  910. </sect2>
  911. <sect2 id="security-container-adapters-configuration">
  912. <title>Filter Integration</title>
  913. <para>Web applications wishing to use container adapters should define
  914. the standard <literal>&lt;security-constraint&gt;</literal> and
  915. <literal>&lt;login-config&gt;</literal> entries in their
  916. <literal>web.xml</literal> file. These will cause the container
  917. authentication to occur, which will delegate to the Acegi Security
  918. System for Spring provided adapter.</para>
  919. <para>The adapter will return a container-compatible user object that
  920. also implements the <literal>Authentication</literal> interface. The
  921. container then makes this returned user object available from a
  922. container-specific well-known location.</para>
  923. <para>The <literal>AbstractIntegrationFilter</literal> and its
  924. subclasses finalise the adapter integration. These classes are
  925. standard filters, and at the start of each request they will attempt
  926. to extract the <literal>Authentication</literal> object from the
  927. container's well-known location. The <literal>Authentication</literal>
  928. object will then be associated with the
  929. <literal>ContextHolder</literal> for the duration of the request, and
  930. be removed when the request is finished. Three concrete subclasses of
  931. <literal>AbstractIntegrationFilter</literal> are provided with the
  932. Acegi Security System for Spring:</para>
  933. <para><itemizedlist>
  934. <listitem>
  935. <para><literal>HttpRequestIntegrationFilter</literal> is used
  936. with Catalina, Jetty and Resin. It extracts the authentication
  937. information from
  938. <literal>HttpServletRequest.getUserPrincipal()</literal>.</para>
  939. </listitem>
  940. <listitem>
  941. <para><literal>JbossIntegrationFilter</literal> is used with
  942. JBoss. It extracts the authentication from
  943. <literal>java:comp/env/security/subject</literal>.</para>
  944. </listitem>
  945. <listitem>
  946. <para><literal>AutoIntegrationFilter</literal> automatically
  947. determines which filter to use. This makes a web application WAR
  948. file more portable, as the <literal>web.xml</literal> is not
  949. hard-coded to a container-specific
  950. <literal>AbstractIntegrationFilter</literal>.</para>
  951. </listitem>
  952. </itemizedlist></para>
  953. <para>Once in the <literal>ContextHolder</literal>, the standard Acegi
  954. Security System for Spring classes can be used. Because
  955. <literal>ContextHolder</literal> is a standard object which is
  956. populated using a filter at the container level, JSPs and Servlets do
  957. not need to use Spring's MVC packages. This enables those applications
  958. that use other MVC frameworks to still leverage Spring's other
  959. capabilities, with full authentication and authorization support. The
  960. <literal>debug.jsp</literal> page provided with the sample application
  961. demonstrates accessing the <literal>ContextHolder</literal>
  962. independent of Spring's MVC packages.</para>
  963. </sect2>
  964. <sect2 id="security-container-adapters-provider">
  965. <title>Adapter Authentication Provider</title>
  966. <para>As is always the case, the container adapter generated
  967. <literal>Authentication</literal> object still needs to be
  968. authenticated by an <literal>AuthenticationManager</literal> when
  969. requested to do so by the <literal>SecurityInterceptor</literal>. The
  970. <literal>AuthenticationManager</literal> needs to be certain the
  971. adapter-provided <literal>Authentication</literal> object is valid and
  972. was actually authenticated by a trusted adapter.</para>
  973. <para>Adapters create <literal>Authentication</literal> objects which
  974. are immutable and implement the <literal>AuthByAdapter</literal>
  975. interface. These objects store the hash of a key that is defined by
  976. the adapter. This allows the <literal>Authentication</literal> object
  977. to be validated by the <literal>AuthByAdapterProvider</literal>. This
  978. authentication provider is defined as follows:</para>
  979. <para><programlisting>&lt;bean id="authByAdapterProvider" class="net.sf.acegisecurity.adapters.AuthByAdapterProvider"&gt;
  980. &lt;property name="key"&gt;&lt;value&gt;my_password&lt;/value&gt;&lt;/property&gt;
  981. &lt;/bean&gt;</programlisting></para>
  982. <para>The key must match the key that is defined in the
  983. container-specific configuration file that starts the adapter. The
  984. <literal>AuthByAdapterProvider</literal> automatically accepts as
  985. valid any <literal>AuthByAdapter</literal> implementation that returns
  986. the expected hash of the key.</para>
  987. <para>To reiterate, this means the adapter will perform the initial
  988. authentication using providers such as
  989. <literal>DaoAuthenticationProvider</literal>, returning an
  990. <literal>AuthByAdapter</literal> instance that contains a hash code of
  991. the key. Later, when an application calls a
  992. <literal>SecurityInterceptor</literal> managed bean, the
  993. <literal>AuthByAdapter</literal> instance in the
  994. <literal>ContextHolder</literal> will be tested by the application's
  995. <literal>AuthByAdapterProvider</literal>. There is no requirement for
  996. additional authentication providers such as
  997. <literal>DaoAuthenticationProvider</literal> within the
  998. application-specific bean context, as the only type of
  999. <literal>Authentication</literal> instance that will be presented by
  1000. the application is from the container adapter.</para>
  1001. <para>Classloader issues are frequent with containers and the use of
  1002. container adapters illustrates this further. Each container requires a
  1003. very specific configuration. The installation instructions are
  1004. provided below. Once installed, please take the time to try the sample
  1005. application to ensure your container adapter is properly
  1006. configured.</para>
  1007. </sect2>
  1008. <sect2>
  1009. <title>Catalina (Tomcat) Installation</title>
  1010. <para>The following was tested with Jakarta Tomcat 5.0.19. We
  1011. automatically test the following directions using our container
  1012. integration test system and this version of Catalina (Tomcat).</para>
  1013. <para><literal>$CATALINA_HOME</literal> refers to the root of your
  1014. Catalina (Tomcat) installation.</para>
  1015. <para>Edit your <literal>$CATALINA_HOME/conf/server.xml</literal> file
  1016. so the <literal>&lt;Engine&gt;</literal> section contains only one
  1017. active <literal>&lt;Realm&gt;</literal> entry. An example realm
  1018. entry:</para>
  1019. <para><programlisting> &lt;Realm className="net.sf.acegisecurity.adapters.catalina.CatalinaAcegiUserRealm"
  1020. appContextLocation="conf/acegisecurity.xml"
  1021. key="my_password" /&gt;</programlisting></para>
  1022. <para>Be sure to remove any other <literal>&lt;Realm&gt;</literal>
  1023. entry from your <literal>&lt;Engine&gt;</literal> section.</para>
  1024. <para>Copy <literal>acegisecurity.xml</literal> into
  1025. <literal>$CATALINA_HOME/conf</literal>.</para>
  1026. <para>Copy <literal>acegi-security-catalina-server.jar</literal> into
  1027. <literal>$CATALINA_HOME/server/lib</literal>.</para>
  1028. <para>Copy the following files into
  1029. <literal>$CATALINA_HOME/common/lib</literal>:</para>
  1030. <itemizedlist>
  1031. <listitem>
  1032. <para><literal>aopalliance.jar</literal></para>
  1033. </listitem>
  1034. <listitem>
  1035. <para><literal>spring.jar</literal></para>
  1036. </listitem>
  1037. <listitem>
  1038. <para><literal>acegi-security-catalina-common.jar</literal></para>
  1039. </listitem>
  1040. </itemizedlist>
  1041. <para>None of the above JAR files (or
  1042. <literal>acegi-security.jar</literal>) should be in your application's
  1043. <literal>WEB-INF/lib</literal>. The realm name indicated in your
  1044. <literal>web.xml</literal> does not matter with Catalina.</para>
  1045. </sect2>
  1046. <sect2>
  1047. <title>Jetty Installation</title>
  1048. <para>The following was tested with Jetty 4.2.18. We automatically
  1049. test the following directions using our container integration test
  1050. system and this version of Jetty.</para>
  1051. <para><literal>$JETTY_HOME</literal> refers to the root of your Jetty
  1052. installation.</para>
  1053. <para>Edit your <literal>$JETTY_HOME/etc/jetty.xml</literal> file so
  1054. the <literal>&lt;Configure class&gt;</literal> section has a new
  1055. addRealm call:</para>
  1056. <para><programlisting> &lt;Call name="addRealm"&gt;
  1057. &lt;Arg&gt;
  1058. &lt;New class="net.sf.acegisecurity.adapters.jetty.JettyAcegiUserRealm"&gt;
  1059. &lt;Arg&gt;Spring Powered Realm&lt;/Arg&gt;
  1060. &lt;Arg&gt;my_password&lt;/Arg&gt;
  1061. &lt;Arg&gt;/etc/acegisecurity.xml&lt;/Arg&gt;
  1062. &lt;/New&gt;
  1063. &lt;/Arg&gt;
  1064. &lt;/Call&gt;</programlisting></para>
  1065. <para>Copy <literal>acegisecurity.xml</literal> into
  1066. <literal>$JETTY_HOME/etc</literal>.</para>
  1067. <para>Copy the following files into
  1068. <literal>$JETTY_HOME/ext</literal>:<itemizedlist>
  1069. <listitem>
  1070. <para><literal>aopalliance.jar</literal></para>
  1071. </listitem>
  1072. <listitem>
  1073. <para><literal>commons-logging.jar</literal></para>
  1074. </listitem>
  1075. <listitem>
  1076. <para><literal>spring.jar</literal></para>
  1077. </listitem>
  1078. <listitem>
  1079. <para><literal>acegi-security-jetty-ext.jar</literal></para>
  1080. </listitem>
  1081. </itemizedlist></para>
  1082. <para>None of the above JAR files (or
  1083. <literal>acegi-security.jar</literal>) should be in your application's
  1084. <literal>WEB-INF/lib</literal>. The realm name indicated in your
  1085. <literal>web.xml</literal> does matter with Jetty. The
  1086. <literal>web.xml</literal> must express the same
  1087. <literal>&lt;realm-name&gt;</literal> as your
  1088. <literal>jetty.xml</literal> (in the example above, "Spring Powered
  1089. Realm").</para>
  1090. </sect2>
  1091. <sect2>
  1092. <title>JBoss Installation</title>
  1093. <para>The following was tested with JBoss 3.2.3. We automatically test
  1094. the following directions using our container integration test system
  1095. and this version of JBoss.</para>
  1096. <para><literal>$JBOSS_HOME</literal> refers to the root of your JBoss
  1097. installation.</para>
  1098. <para>Edit your
  1099. <literal>$JBOSS_HOME/server/your_config/conf/login-config.xml</literal>
  1100. file so that it contains a new entry under the
  1101. <literal>&lt;Policy&gt;</literal> section:</para>
  1102. <para><programlisting> &lt;application-policy name = "SpringPoweredRealm"&gt;
  1103. &lt;authentication&gt;
  1104. &lt;login-module code = "net.sf.acegisecurity.adapters.jboss.JbossSpringLoginModule"
  1105. flag = "required"&gt;
  1106. &lt;module-option name = "appContextLocation"&gt;acegisecurity.xml&lt;/module-option&gt;
  1107. &lt;module-option name = "key"&gt;my_password&lt;/module-option&gt;
  1108. &lt;/login-module&gt;
  1109. &lt;/authentication&gt;
  1110. &lt;/application-policy&gt;</programlisting></para>
  1111. <para>Copy <literal>acegisecurity.xml</literal> into
  1112. <literal>$JBOSS_HOME/server/your_config/conf</literal>.</para>
  1113. <para>Copy the following files into
  1114. <literal>$JBOSS_HOME/server/your_config/lib</literal>:<itemizedlist>
  1115. <listitem>
  1116. <para><literal>aopalliance.jar</literal></para>
  1117. </listitem>
  1118. <listitem>
  1119. <para><literal>spring.jar</literal></para>
  1120. </listitem>
  1121. <listitem>
  1122. <para><literal>acegi-security-jboss-lib.jar</literal></para>
  1123. </listitem>
  1124. </itemizedlist></para>
  1125. <para>None of the above JAR files (or
  1126. <literal>acegi-security.jar</literal>) should be in your application's
  1127. <literal>WEB-INF/lib</literal>. The realm name indicated in your
  1128. <literal>web.xml</literal> does not matter with JBoss. However, your
  1129. web application's <literal>WEB-INF/jboss-web.xml</literal> must
  1130. express the same <literal>&lt;security-domain&gt;</literal> as your
  1131. <literal>login-config.xml</literal>. For example, to match the above
  1132. example, your <literal>jboss-web.xml</literal> would look like
  1133. this:</para>
  1134. <para><programlisting>&lt;jboss-web&gt;
  1135. &lt;security-domain&gt;java:/jaas/SpringPoweredRealm&lt;/security-domain&gt;
  1136. &lt;/jboss-web&gt;</programlisting></para>
  1137. </sect2>
  1138. <sect2>
  1139. <title>Resin Installation</title>
  1140. <para>The following was tested with Resin 3.0.6.</para>
  1141. <para><literal>$RESIN_HOME</literal> refers to the root of your Resin
  1142. installation.</para>
  1143. <para>Resin provides several ways to support the container adapter. In
  1144. the instructions below we have elected to maximise consistency with
  1145. other container adapter configurations. This will allow Resin users to
  1146. simply deploy the sample application and confirm correct
  1147. configuration. Developers comfortable with Resin are naturally able to
  1148. use its capabilities to package the JARs with the web application
  1149. itself, and/or support single sign-on.</para>
  1150. <para>Copy the following files into
  1151. <literal>$RESIN_HOME/lib</literal>:<itemizedlist>
  1152. <listitem>
  1153. <para><literal>aopalliance.jar</literal></para>
  1154. </listitem>
  1155. <listitem>
  1156. <para><literal>commons-logging.jar</literal></para>
  1157. </listitem>
  1158. <listitem>
  1159. <para><literal>spring.jar</literal></para>
  1160. </listitem>
  1161. <listitem>
  1162. <para><literal>acegi-security-resin-lib.jar</literal></para>
  1163. </listitem>
  1164. </itemizedlist></para>
  1165. <para>Unlike the container-wide <literal>acegisecurity.xml</literal>
  1166. files used by other container adapters, each Resin web application
  1167. will contain its own
  1168. <literal>WEB-INF/resin-acegisecurity.xml</literal> file. Each web
  1169. application will also contain a <literal>resin-web.xml</literal> file
  1170. which Resin uses to start the container adapter:</para>
  1171. <para><programlisting>&lt;web-app&gt;
  1172. &lt;authenticator&gt;
  1173. &lt;type&gt;net.sf.acegisecurity.adapters.resin.ResinAcegiAuthenticator&lt;/type&gt;
  1174. &lt;init&gt;
  1175. &lt;app-context-location&gt;WEB-INF/resin-acegisecurity.xml&lt;/app-context-location&gt;
  1176. &lt;key&gt;my_password&lt;/key&gt;
  1177. &lt;/init&gt;
  1178. &lt;/authenticator&gt;
  1179. &lt;/web-app&gt;</programlisting></para>
  1180. <para>With the basic configuration provided above, none of the JAR
  1181. files listed (or <literal>acegi-security.jar</literal>) should be in
  1182. your application's <literal>WEB-INF/lib</literal>. The realm name
  1183. indicated in your <literal>web.xml</literal> does not matter with
  1184. Resin, as the relevant authentication class is indicated by the
  1185. <literal>&lt;authenticator&gt;</literal> setting.</para>
  1186. </sect2>
  1187. </sect1>
  1188. <sect1 id="security-sample">
  1189. <title>Sample Application</title>
  1190. <para>Included with the Acegi Security System for Spring is a very
  1191. simple application that can demonstrate the basic security facilities
  1192. provided by the system and confirm your container adapter is properly
  1193. configured.</para>
  1194. <para>To install, configure your container as described in the Container
  1195. Adapters section of this chapter. Do not modify
  1196. <literal>acegisecurity.xml</literal>. It contains a very basic in-memory
  1197. authentication configuration that is compatible with the sample
  1198. application. Next, copy the <literal>contacts.war</literal> file from
  1199. the Acegi Security System for Spring distribution into your container’s
  1200. <literal>webapps</literal> directory.</para>
  1201. <para>After starting your container, check the application can load.
  1202. Visit <literal>http://localhost:8080/contacts</literal> (or whichever
  1203. URL is appropriate for your web container). A random contact should be
  1204. displayed. Click "Refresh" several times and you will see different
  1205. contacts. The business method that provides this random contact is not
  1206. secured.</para>
  1207. <para>Next, click "Debug". You will be prompted to authenticate, and a
  1208. series of usernames and passwords are suggested on that page. Simply
  1209. authenticate with any of these and view the resulting page. It should
  1210. contain a success message similar to the following:</para>
  1211. <blockquote>
  1212. <para>Context on ContextHolder is of type:
  1213. net.sf.acegisecurity.context.SecureContextImpl</para>
  1214. <para>The Context implements SecureContext.</para>
  1215. <para>Authentication object is of type:
  1216. net.sf.acegisecurity.adapters.PrincipalAcegiUserToken</para>
  1217. <para>Authentication object as a String:
  1218. net.sf.acegisecurity.adapters.PrincipalAcegiUserToken@e9a7c2:
  1219. Username: marissa; Password: [PROTECTED]; Authenticated: true; Granted
  1220. Authorities: ROLE_TELLER, ROLE_SUPERVISOR</para>
  1221. <para>Authentication object holds the following granted
  1222. authorities:</para>
  1223. <para>ROLE_TELLER (getAuthority(): ROLE_TELLER)</para>
  1224. <para>ROLE_SUPERVISOR (getAuthority(): ROLE_SUPERVISOR)</para>
  1225. <para>SUCCESS! Your container adapter appears to be properly
  1226. configured!</para>
  1227. </blockquote>
  1228. <para>If you receive a different message, check you have properly
  1229. configured your container adapter. Refer to the instructions provided
  1230. above.</para>
  1231. <para>Once you successfully receive the above message, return to the
  1232. sample application's home page and click "Manage". You can then try out
  1233. the application. Notice that only the contacts belonging to the
  1234. currently logged on user are displayed, and only users with
  1235. <literal>ROLE_SUPERVISOR</literal> are granted access to delete their
  1236. contacts. Behind the scenes, the <literal>SecurityInterceptor</literal>
  1237. is securing the business objects.</para>
  1238. </sect1>
  1239. <sect1 id="security-become-involved">
  1240. <title>Become Involved</title>
  1241. <para>We welcome you to become involved in the Acegi Security System for
  1242. Spring project. There are many ways of contributing, including reading
  1243. the mailing list and responding to questions from other people, writing
  1244. new code, improving existing code, assisting with documentation, or
  1245. simply making suggestions.</para>
  1246. <para>SourceForge provides CVS services for the project, allowing
  1247. anybody to access the latest code. If you wish to contribute new code,
  1248. please observe the following requirements. These exist to maintain the
  1249. quality and consistency of the project:</para>
  1250. <itemizedlist>
  1251. <listitem>
  1252. <para>Run the Ant <literal>format</literal> task to convert your
  1253. code into the project's consistent style</para>
  1254. </listitem>
  1255. <listitem>
  1256. <para>Ensure your code does not break any unit tests (run the Ant
  1257. <literal>tests</literal> target)</para>
  1258. </listitem>
  1259. <listitem>
  1260. <para>Please use the container integration test system to test your
  1261. code in the project's officially supported containers</para>
  1262. </listitem>
  1263. <listitem>
  1264. <para>When writing a new container adapter, expand the container
  1265. integration test system to properly test it</para>
  1266. </listitem>
  1267. <listitem>
  1268. <para>If you have added new code, please provide suitable unit
  1269. tests</para>
  1270. </listitem>
  1271. <listitem>
  1272. <para>Add a CVS <literal>$Id$</literal> tag to the JavaDocs for any
  1273. new class you create </para>
  1274. </listitem>
  1275. </itemizedlist>
  1276. <para>Mentioned above is our container integration test system, which
  1277. aims to test the Acegi Security System for Spring container adapters
  1278. with current, production versions of each container. Some containers
  1279. might not be supported due to difficulties with starting or stopping the
  1280. container within an Ant target. You will need to download the container
  1281. release files as specified in the integration test
  1282. <literal>readme.txt</literal> file. These files are intentionally
  1283. excluded from CVS due to their large size.</para>
  1284. </sect1>
  1285. <sect1 id="security-further">
  1286. <title>Further Information</title>
  1287. <para>Questions and comments on the Acegi Security System for Spring are
  1288. welcome. Please direct comments to the Spring Users mailing list or
  1289. ben.alex@acegi.com.au. Our project home page (where you can obtain the
  1290. latest release of the project and access to CVS) is at
  1291. <literal>http://acegisecurity.sourceforge.net</literal>.</para>
  1292. </sect1>
  1293. </chapter>
  1294. </book>