secured-objects.xml 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. <chapter xmlns="http://docbook.org/ns/docbook" version="5.0" xml:id="secure-object-impls" xmlns:xlink="http://www.w3.org/1999/xlink">
  2. <info><title>Secure Object Implementations</title></info>
  3. <section xml:id="aop-alliance">
  4. <info>
  5. <title>AOP Alliance (MethodInvocation) Security Interceptor</title>
  6. </info>
  7. <para>
  8. Prior to Spring Security 2.0, securing <classname>MethodInvocation</classname>s needed quite a
  9. lot of boiler plate configuration. Now the recommended approach for method security
  10. is to use <link xlink:href="#ns-method-security">namespace configuration</link>.
  11. This way the method security infrastructure beans are configured automatically for you so you don't really need to
  12. know about the implementation classes. We'll just provide a quick overview of the classes that are involved here.
  13. </para>
  14. <para>
  15. Method security in enforced using a <classname>MethodSecurityInterceptor</classname>, which secures
  16. <classname>MethodInvocation</classname>s. Depending on the configuration approach, an interceptor may be specific to a single
  17. bean or shared between multiple beans. The interceptor uses a <interfacename>MethodDefinitionSource</interfacename>
  18. instance to obtain the configuration attributes that apply to a particular method invocation.
  19. <classname>MapBasedMethodDefinitionSource</classname> is used to store configuration attributes keyed by method names
  20. (which can be wildcarded) and will be used internally when the attributes are defined in the application context using
  21. the <literal>&lt;intercept-methods&gt;</literal> or <literal>&lt;protect-point&gt;</literal> elements. Other implementations
  22. will be used to handle annotation-based configuration.
  23. </para>
  24. <section>
  25. <title>Explicit MethodSecurityIterceptor Configuration</title>
  26. <para>
  27. You can of course configure a <classname>MethodSecurityIterceptor</classname> directly in your application context
  28. for use with one of Spring AOP's proxying mechanisms:
  29. <programlisting><![CDATA[
  30. <bean id="bankManagerSecurity"
  31. class="org.springframework.security.intercept.aopalliance.MethodSecurityInterceptor">
  32. <property name="authenticationManager" ref="authenticationManager"/>
  33. <property name="accessDecisionManager" ref="accessDecisionManager"/>
  34. <property name="afterInvocationManager" ref="afterInvocationManager"/>
  35. <property name="securityMetadataSource">
  36. <value>
  37. com.mycompany.BankManager.delete*=ROLE_SUPERVISOR
  38. com.mycompany.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR
  39. </value>
  40. </property>
  41. </bean> ]]>
  42. </programlisting>
  43. </para>
  44. </section>
  45. </section>
  46. <section xml:id="aspectj">
  47. <info>
  48. <title>AspectJ (JoinPoint) Security Interceptor</title>
  49. </info>
  50. <para>The AspectJ security interceptor is very similar to the AOP
  51. Alliance security interceptor discussed in the previous section.
  52. Indeed we will only discuss the differences in this section.</para>
  53. <para>The AspectJ interceptor is named
  54. <literal>AspectJSecurityInterceptor</literal>. Unlike the AOP Alliance
  55. security interceptor, which relies on the Spring application context
  56. to weave in the security interceptor via proxying, the
  57. <literal>AspectJSecurityInterceptor</literal> is weaved in via the
  58. AspectJ compiler. It would not be uncommon to use both types of
  59. security interceptors in the same application, with
  60. <literal>AspectJSecurityInterceptor</literal> being used for domain
  61. object instance security and the AOP Alliance
  62. <classname>MethodSecurityInterceptor</classname> being used for services
  63. layer security.</para>
  64. <para>Let's first consider how the
  65. <literal>AspectJSecurityInterceptor</literal> is configured in the
  66. Spring application context:</para>
  67. <programlisting><![CDATA[
  68. <bean id="bankManagerSecurity"
  69. class="org.springframework.security.intercept.aspectj.AspectJSecurityInterceptor">
  70. <property name="authenticationManager" ref="authenticationManager"/>
  71. <property name="accessDecisionManager" ref="accessDecisionManager"/>
  72. <property name="afterInvocationManager" ref="afterInvocationManager"/>
  73. <property name="securityMetadataSource">
  74. <value>
  75. com.mycompany.BankManager.delete*=ROLE_SUPERVISOR
  76. com.mycompany.BankManager.getBalance=ROLE_TELLER,ROLE_SUPERVISOR
  77. </value>
  78. </property>
  79. </bean>]]> </programlisting>
  80. <para>As you can see, aside from the class name, the
  81. <literal>AspectJSecurityInterceptor</literal> is exactly the same as
  82. the AOP Alliance security interceptor. Indeed the two interceptors can
  83. share the same <literal>securityMetadataSource</literal>, as the
  84. <interfacename>SecurityMetadataSource</interfacename> works with
  85. <literal>java.lang.reflect.Method</literal>s rather than an AOP
  86. library-specific class. Of course, your access decisions have access
  87. to the relevant AOP library-specific invocation (ie
  88. <classname>MethodInvocation</classname> or <literal>JoinPoint</literal>)
  89. and as such can consider a range of addition criteria when making
  90. access decisions (such as method arguments).</para>
  91. <para>Next you'll need to define an AspectJ <literal>aspect</literal>.
  92. For example:</para>
  93. <programlisting>
  94. package org.springframework.security.samples.aspectj;
  95. import org.springframework.security.intercept.aspectj.AspectJSecurityInterceptor;
  96. import org.springframework.security.intercept.aspectj.AspectJCallback;
  97. import org.springframework.beans.factory.InitializingBean;
  98. public aspect DomainObjectInstanceSecurityAspect implements InitializingBean {
  99. private AspectJSecurityInterceptor securityInterceptor;
  100. pointcut domainObjectInstanceExecution(): target(PersistableEntity)
  101. &amp;&amp; execution(public * *(..)) &amp;&amp; !within(DomainObjectInstanceSecurityAspect);
  102. Object around(): domainObjectInstanceExecution() {
  103. if (this.securityInterceptor == null) {
  104. return proceed();
  105. }
  106. AspectJCallback callback = new AspectJCallback() {
  107. public Object proceedWithObject() {
  108. return proceed();
  109. }
  110. };
  111. return this.securityInterceptor.invoke(thisJoinPoint, callback);
  112. }
  113. public AspectJSecurityInterceptor getSecurityInterceptor() {
  114. return securityInterceptor;
  115. }
  116. public void setSecurityInterceptor(AspectJSecurityInterceptor securityInterceptor) {
  117. this.securityInterceptor = securityInterceptor;
  118. }
  119. public void afterPropertiesSet() throws Exception {
  120. if (this.securityInterceptor == null)
  121. throw new IllegalArgumentException("securityInterceptor required");
  122. }
  123. }</programlisting>
  124. <para>In the above example, the security interceptor will be applied
  125. to every instance of <literal>PersistableEntity</literal>, which is an
  126. abstract class not shown (you can use any other class or
  127. <literal>pointcut</literal> expression you like). For those curious,
  128. <literal>AspectJCallback</literal> is needed because the
  129. <literal>proceed();</literal> statement has special meaning only
  130. within an <literal>around()</literal> body. The
  131. <literal>AspectJSecurityInterceptor</literal> calls this anonymous
  132. <literal>AspectJCallback</literal> class when it wants the target
  133. object to continue.</para>
  134. <para>You will need to configure Spring to load the aspect and wire it
  135. with the <literal>AspectJSecurityInterceptor</literal>. A bean
  136. declaration which achieves this is shown below:</para>
  137. <programlisting><![CDATA[
  138. <bean id="domainObjectInstanceSecurityAspect"
  139. class="org.springframework.security.samples.aspectj.DomainObjectInstanceSecurityAspect"
  140. factory-method="aspectOf">
  141. <property name="securityInterceptor" ref="aspectJSecurityInterceptor"/>
  142. </bean>]]>
  143. </programlisting>
  144. <para>That's it! Now you can create your beans from anywhere within
  145. your application, using whatever means you think fit (eg <literal>new
  146. Person();</literal>) and they will have the security interceptor
  147. applied.</para>
  148. </section>
  149. <section xml:id="filter-invocation-authorization">
  150. <info><title>FilterInvocation Security Interceptor</title></info>
  151. <para>To secure <classname>FilterInvocation</classname>s, developers need
  152. to add a <classname>FilterSecurityInterceptor</classname> to their filter chain.
  153. A typical configuration example is provided below:</para>
  154. <para>In the application context you will need to configure three
  155. beans:</para>
  156. <programlisting>
  157. <![CDATA[
  158. <bean id="exceptionTranslationFilter"
  159. class="org.springframework.security.web.access.ExceptionTranslationFilter">
  160. <property name="authenticationEntryPoint" ref="authenticationEntryPoint"/>
  161. </bean>
  162. <bean id="authenticationEntryPoint"
  163. class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
  164. <property name="loginFormUrl" value="/acegilogin.jsp"/>
  165. <property name="forceHttps" value="false"/>
  166. </bean>
  167. <bean id="filterSecurityInterceptor"
  168. class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
  169. <property name="authenticationManager" ref="authenticationManager"/>
  170. <property name="accessDecisionManager" ref="accessDecisionManager"/>
  171. <property name="securityMetadataSource">
  172. <security:filter-invocation-definition-source>
  173. <security:intercept-url pattern="/secure/super/**" access="ROLE_WE_DONT_HAVE"/>
  174. <security:intercept-url pattern="/secure/**" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
  175. </security:filter-invocation-definition-source>
  176. </property>
  177. </bean>]]> </programlisting>
  178. <para>The <classname>ExceptionTranslationFilter</classname> provides
  179. the bridge between Java exceptions and HTTP responses. It is solely
  180. concerned with maintaining the user interface. This filter does not do
  181. any actual security enforcement. If an
  182. <exceptionname>AuthenticationException</exceptionname> is detected,
  183. the filter will call the AuthenticationEntryPoint to commence the
  184. authentication process (e.g. a user login).</para>
  185. <para>The <interfacename>AuthenticationEntryPoint</interfacename> will be called
  186. if the user requests a secure HTTP resource but they are not
  187. authenticated. The class handles presenting the appropriate response
  188. to the user so that authentication can begin. Three concrete
  189. implementations are provided with Spring Security:
  190. <classname>LoginUrlAuthenticationEntryPoint</classname> for
  191. commencing a form-based authentication,
  192. <literal>BasicProcessingFilterEntryPoint</literal> for commencing a
  193. HTTP Basic authentication process, and
  194. <literal>CasProcessingFilterEntryPoint</literal> for commencing a
  195. JA-SIG Central Authentication Service (CAS) login. The
  196. <classname>LoginUrlAuthenticationEntryPoint</classname> and
  197. <literal>CasProcessingFilterEntryPoint</literal> have optional
  198. properties related to forcing the use of HTTPS, so please refer to the
  199. JavaDocs if you require this.</para>
  200. <para><classname>FilterSecurityInterceptor</classname> is responsible for
  201. handling the security of HTTP resources. Like any other security
  202. interceptor, it requires a reference to an
  203. <interfacename>AuthenticationManager</interfacename> and an
  204. <interfacename>AccessDecisionManager</interfacename>, which are both discussed in
  205. separate sections below. The
  206. <classname>FilterSecurityInterceptor</classname> is also configured with
  207. configuration attributes that apply to different HTTP URL requests. A
  208. full discussion of configuration attributes is provided in the High
  209. Level Design section of this document.</para>
  210. <para>The <classname>FilterSecurityInterceptor</classname> can be
  211. configured with configuration attributes in two ways. The first,
  212. which is shown above, is using the <literal>&lt;filter-invocation-definition-source&gt;</literal>
  213. namespace element. This is similar to the <literal>&lt;filter-chain-map&gt;</literal>
  214. used to configure a <classname>FilterChainProxy</classname> but the <literal>&lt;intercept-url&gt;</literal>
  215. child elements only use the <literal>pattern</literal> and <literal>access</literal> attributes.
  216. The second is by writing your own
  217. <interfacename>SecurityMetadataSource</interfacename>, although this is beyond the
  218. scope of this document. Irrespective of the approach used, the
  219. <interfacename>SecurityMetadataSource</interfacename> is responsible for returning
  220. a <literal>List&lt;ConfigAttribute&gt;</literal> containing
  221. all of the configuration attributes associated with a single secure
  222. HTTP URL.</para>
  223. <para>It should be noted that the
  224. <literal>FilterSecurityInterceptor.setSecurityMetadataSource()</literal>
  225. method actually expects an instance of
  226. <interfacename>FilterInvocationDefinitionSource</interfacename>. This is a marker
  227. interface which subclasses <interfacename>SecurityMetadataSource</interfacename>.
  228. It simply denotes the <interfacename>SecurityMetadataSource</interfacename>
  229. understands <classname>FilterInvocation</classname>s. In the interests of
  230. simplicity we'll continue to refer to the
  231. <interfacename>FilterInvocationDefinitionSource</interfacename> as an
  232. <interfacename>SecurityMetadataSource</interfacename>, as the distinction is of
  233. little relevance to most users of the
  234. <classname>FilterSecurityInterceptor</classname>.</para>
  235. <para>When using the namespace option to configure the interceptor,
  236. commas are used to delimit the different configuration
  237. attributes that apply to each HTTP URL. Each configuration attribute
  238. is assigned into its own <literal>SecurityConfig</literal> object. The
  239. <literal>SecurityConfig</literal> object is discussed in the High
  240. Level Design section. The <interfacename>SecurityMetadataSource</interfacename>
  241. created by the property editor,
  242. <interfacename>FilterInvocationDefinitionSource</interfacename>, matches
  243. configuration attributes against <literal>FilterInvocations</literal>
  244. based on expression evaluation of the request URL. Two standard
  245. expression syntaxes are supported. The default is to treat all
  246. expressions as Apache Ant paths and regular expressions are also supported
  247. for ore complex cases. The <literal>path-type</literal> attribute is used
  248. to specify the type of pattern being used. It is not possible to
  249. mix expression syntaxes within the same definition. For example, the
  250. previous configuration using regular expressions instead of Ant paths would be
  251. written as follows:</para>
  252. <programlisting><![CDATA[
  253. <bean id="filterInvocationInterceptor"
  254. class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
  255. <property name="authenticationManager" ref="authenticationManager"/>
  256. <property name="accessDecisionManager" ref="accessDecisionManager"/>
  257. <property name="runAsManager" ref="runAsManager"/>
  258. <property name="securityMetadataSource">
  259. <security:filter-invocation-definition-source path-type="regex">
  260. <security:intercept-url pattern="\A/secure/super/.*\Z" access="ROLE_WE_DONT_HAVE"/>
  261. <security:intercept-url pattern="\A/secure/.*\" access="ROLE_SUPERVISOR,ROLE_TELLER"/>
  262. </security:filter-invocation-definition-source>
  263. </property>
  264. </bean>]]> </programlisting>
  265. <para>Irrespective of the type of expression syntax used, expressions
  266. are always evaluated in the order they are defined. Thus it is
  267. important that more specific expressions are defined higher in the
  268. list than less specific expressions. This is reflected in our example
  269. above, where the more specific <literal>/secure/super/</literal>
  270. pattern appears higher than the less specific
  271. <literal>/secure/</literal> pattern. If they were reversed, the
  272. <literal>/secure/</literal> pattern would always match and the
  273. <literal>/secure/super/</literal> pattern would never be
  274. evaluated.</para>
  275. <para>As with other security interceptors, the
  276. <literal>validateConfigAttributes</literal> property is observed. When
  277. set to <literal>true</literal> (the default), at startup time the
  278. <classname>FilterSecurityInterceptor</classname> will evaluate if the
  279. provided configuration attributes are valid. It does this by checking
  280. each configuration attribute can be processed by either the
  281. <interfacename>AccessDecisionManager</interfacename> or the
  282. <literal>RunAsManager</literal>. If neither of these can process a
  283. given configuration attribute, an exception is thrown.</para>
  284. </section>
  285. </chapter>