|
@@ -5,7 +5,8 @@
|
|
|
|
|
|
<body>
|
|
<body>
|
|
<h1>Tutorial: Adding Security to Spring Petclinic</h1>
|
|
<h1>Tutorial: Adding Security to Spring Petclinic</h1>
|
|
-<h2>Background requirements</h2>
|
|
|
|
|
|
+
|
|
|
|
+<h2>Preparation</h2>
|
|
|
|
|
|
<p>To complete this tutorial, you will require a servlet container (such as Tomcat)
|
|
<p>To complete this tutorial, you will require a servlet container (such as Tomcat)
|
|
and a general understanding of using Spring without Acegi Security. The Petclinic
|
|
and a general understanding of using Spring without Acegi Security. The Petclinic
|
|
@@ -14,11 +15,13 @@ only try to learn one thing at a time, and start with Spring/Petclinic before
|
|
Acegi Security.
|
|
Acegi Security.
|
|
</p>
|
|
</p>
|
|
|
|
|
|
-<h2>Download</h2>
|
|
|
|
|
|
+<p>
|
|
|
|
+You will also need to download:
|
|
<ul>
|
|
<ul>
|
|
<li>Spring 2.0 M4 with dependencies ZIP file</li>
|
|
<li>Spring 2.0 M4 with dependencies ZIP file</li>
|
|
<li>Acegi Security 1.0.0</li>
|
|
<li>Acegi Security 1.0.0</li>
|
|
</ul>
|
|
</ul>
|
|
|
|
+</p>
|
|
|
|
|
|
<p>
|
|
<p>
|
|
Unzip both files. After unzipping Acegi Security, you'll need to unzip the
|
|
Unzip both files. After unzipping Acegi Security, you'll need to unzip the
|
|
@@ -29,105 +32,104 @@ unzipped WAR, not the original ZIP). There is no need to setup any environment
|
|
variables to complete the tutorial.
|
|
variables to complete the tutorial.
|
|
</p>
|
|
</p>
|
|
|
|
|
|
-<h2>Setup database</h2>
|
|
|
|
-
|
|
|
|
-<p>Start the Hypersonic server (this is just normal Petclinic configuration):
|
|
|
|
-<pre>
|
|
|
|
-cd %spring%\samples\petclinic\db\hsqldb
|
|
|
|
-server
|
|
|
|
-</pre>
|
|
|
|
-</p>
|
|
|
|
|
|
+<h2>Add required Acegi Security files to Petclinic</h2>
|
|
|
|
|
|
<p>
|
|
<p>
|
|
-Insert some data (again, normal Petclinic configuration):
|
|
|
|
|
|
+We now need to put some extra files into Petclinic. The following commands should work:
|
|
<pre>
|
|
<pre>
|
|
-cd %spring%\samples\petclinic
|
|
|
|
-build setupDB
|
|
|
|
|
|
+mkdir %spring%\samples\petclinic\war\WEB-INF\lib
|
|
|
|
+copy %acegi%\acegilogin.jsp %spring%\samples\petclinic\war
|
|
|
|
+copy %acegi%\accessDenied.jsp %spring%\samples\petclinic\war
|
|
|
|
+copy %acegi%\WEB-INF\users.properties %spring%\samples\petclinic\war\WEB-INF
|
|
|
|
+copy %acegi%\WEB-INF\applicationContext-acegi-security.xml %spring%\samples\petclinic\war\WEB-INF
|
|
|
|
+copy %acegi%\WEB-INF\lib\acegi-security-1.0.0.jar %spring%\samples\petclinic\war\WEB-INF\lib
|
|
|
|
+copy %acegi%\WEB-INF\lib\oro-2.0.8.jar %spring%\samples\petclinic\war\WEB-INF\lib
|
|
|
|
+copy %acegi%\WEB-INF\lib\commons-codec-1.3.jar %spring%\samples\petclinic\war\WEB-INF\lib
|
|
</pre>
|
|
</pre>
|
|
</p>
|
|
</p>
|
|
|
|
|
|
-<h2>Setup Petclinic's web.xml</h2>
|
|
|
|
|
|
+<h2>Configure Petclinic's files</h2>
|
|
|
|
|
|
<p>Edit %spring%\samples\petclinic\war\WEB-INF\web.xml and insert the following block of code.
|
|
<p>Edit %spring%\samples\petclinic\war\WEB-INF\web.xml and insert the following block of code.
|
|
<pre>
|
|
<pre>
|
|
- <filter>
|
|
|
|
- <filter-name>Acegi Filter Chain Proxy</filter-name>
|
|
|
|
- <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
|
|
|
|
- <init-param>
|
|
|
|
- <param-name>targetClass</param-name>
|
|
|
|
- <param-value>org.acegisecurity.util.FilterChainProxy</param-value>
|
|
|
|
- </init-param>
|
|
|
|
- </filter>
|
|
|
|
-
|
|
|
|
- <filter-mapping>
|
|
|
|
- <filter-name>Acegi Filter Chain Proxy</filter-name>
|
|
|
|
- <url-pattern>/*</url-pattern>
|
|
|
|
- </filter-mapping>
|
|
|
|
|
|
+<filter>
|
|
|
|
+ <filter-name>Acegi Filter Chain Proxy</filter-name>
|
|
|
|
+ <filter-class>org.acegisecurity.util.FilterToBeanProxy</filter-class>
|
|
|
|
+ <init-param>
|
|
|
|
+ <param-name>targetClass</param-name>
|
|
|
|
+ <param-value>org.acegisecurity.util.FilterChainProxy</param-value>
|
|
|
|
+ </init-param>
|
|
|
|
+</filter>
|
|
|
|
+
|
|
|
|
+<filter-mapping>
|
|
|
|
+ <filter-name>Acegi Filter Chain Proxy</filter-name>
|
|
|
|
+ <url-pattern>/*</url-pattern>
|
|
|
|
+</filter-mapping>
|
|
</pre>
|
|
</pre>
|
|
Next, locate the "contextConfigLocation" parameter, and add a new line into the existing param-value.
|
|
Next, locate the "contextConfigLocation" parameter, and add a new line into the existing param-value.
|
|
The resulting block will look like this:
|
|
The resulting block will look like this:
|
|
<pre>
|
|
<pre>
|
|
<context-param>
|
|
<context-param>
|
|
- <param-name>contextConfigLocation</param-name>
|
|
|
|
- <param-value>
|
|
|
|
- /WEB-INF/applicationContext-jdbc.xml
|
|
|
|
- /WEB-INF/applicationContext-acegi-security.xml
|
|
|
|
- </param-value>
|
|
|
|
|
|
+ <param-name>contextConfigLocation</param-name>
|
|
|
|
+ <param-value>
|
|
|
|
+ /WEB-INF/applicationContext-jdbc.xml
|
|
|
|
+ /WEB-INF/applicationContext-acegi-security.xml
|
|
|
|
+ </param-value>
|
|
</context-param>
|
|
</context-param>
|
|
</pre>
|
|
</pre>
|
|
</p>
|
|
</p>
|
|
|
|
|
|
-<h2>Add the necessary files</h2>
|
|
|
|
-
|
|
|
|
<p>
|
|
<p>
|
|
-We now need to put some extra files into Petclinic. The following commands should work:
|
|
|
|
|
|
+To make it easier to experiment with the application, now edit
|
|
|
|
+%spring%\samples\petclinic\war\WEB-INF\jsp\footer.jsp. Add a new "logout" link, as shown:
|
|
<pre>
|
|
<pre>
|
|
-copy %acegi%\acegilogin.jsp %spring%\samples\petclinic\war
|
|
|
|
-copy %acegi%\WEB-INF\users.properties %spring%\samples\petclinic\war\WEB-INF
|
|
|
|
-copy %acegi%\WEB-INF\applicationContext-acegi-security.xml %spring%\samples\petclinic\war\WEB-INF
|
|
|
|
-copy %acegi%\WEB-INF\lib\acegi-security-1.0.0.jar %spring%\samples\petclinic\war\WEB-INF\lib
|
|
|
|
-copy %acegi%\WEB-INF\lib\oro-2.0.8.jar %spring%\samples\petclinic\war\WEB-INF\lib
|
|
|
|
-copy %acegi%\WEB-INF\lib\commons-codec-1.3.jar %spring%\samples\petclinic\war\WEB-INF\lib
|
|
|
|
|
|
+<table style="width:100%"><tr>
|
|
|
|
+ <td><A href="<c:url value="/welcome.htm"/>">Home</A></td>
|
|
|
|
+ <td><A href="<c:url value="/j_acegi_logout"/>">Logout</A></td>
|
|
|
|
+ <td style="text-align:right;color:silver">PetClinic :: a Spring Framework demonstration</td>
|
|
|
|
+</tr></table>
|
|
</pre>
|
|
</pre>
|
|
</p>
|
|
</p>
|
|
|
|
|
|
<p>
|
|
<p>
|
|
-To make it easier to experiment with the application, let's edit
|
|
|
|
-%spring%\samples\petclinic\war\WEB-INF\jsp\footer.jsp. Add a new "logout" link, as shown:
|
|
|
|
|
|
+Our last step is to specify which URLs require authorization and which do not. Let's
|
|
|
|
+edit %spring%\samples\petclinic\war\WEB-INF\applicationContext-acegi-security.xml.
|
|
|
|
+Locate the bean definition for FilterSecurityInterceptor. Edit its objectDefinitionSource
|
|
|
|
+property so that it reflects the following:
|
|
<pre>
|
|
<pre>
|
|
- <table style="width:100%"><tr>
|
|
|
|
- <td><A href="<c:url value="/welcome.htm"/>">Home</A></td>
|
|
|
|
- <td><A href="<c:url value="/j_acegi_logout"/>">Logout</A></td>
|
|
|
|
- <td style="text-align:right;color:silver">PetClinic :: a Spring Framework demonstration</td>
|
|
|
|
- </tr></table>
|
|
|
|
-
|
|
|
|
|
|
+<property name="objectDefinitionSource">
|
|
|
|
+ <value>
|
|
|
|
+ CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
|
|
|
|
+ PATTERN_TYPE_APACHE_ANT
|
|
|
|
+ /acegilogin.jsp=IS_AUTHENTICATED_ANONYMOUSLY
|
|
|
|
+ /**=IS_AUTHENTICATED_REMEMBERED
|
|
|
|
+ </value>
|
|
|
|
+</property>
|
|
</pre>
|
|
</pre>
|
|
-
|
|
|
|
</p>
|
|
</p>
|
|
|
|
|
|
-<h2>Modify the allowed URLs</h2>
|
|
|
|
|
|
+<h2>Start Petclinic's database</h2>
|
|
|
|
+
|
|
|
|
+<p>Start the Hypersonic server (this is just normal Petclinic configuration):
|
|
|
|
+<pre>
|
|
|
|
+cd %spring%\samples\petclinic\db\hsqldb
|
|
|
|
+server
|
|
|
|
+</pre>
|
|
|
|
+</p>
|
|
|
|
|
|
<p>
|
|
<p>
|
|
-Our last step is to specify which URLs require authorization and which do not. Let's
|
|
|
|
-edit %spring%\samples\petclinic\war\WEB-INF\applicationContext-acegi-security.xml.
|
|
|
|
-Scroll to the bottom and locate the bean definition for FilterSecurityInterceptor.
|
|
|
|
-Edit its objectDefinitionSource property so that it reflects the following:
|
|
|
|
|
|
+Insert some data (again, normal Petclinic configuration):
|
|
<pre>
|
|
<pre>
|
|
- <property name="objectDefinitionSource">
|
|
|
|
- <value>
|
|
|
|
- CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
|
|
|
|
- PATTERN_TYPE_APACHE_ANT
|
|
|
|
- /acegilogin.jsp=IS_AUTHENTICATED_ANONYMOUSLY
|
|
|
|
- /**=IS_AUTHENTICATED_REMEMBERED
|
|
|
|
- </value>
|
|
|
|
- </property>
|
|
|
|
|
|
+cd %spring%\samples\petclinic
|
|
|
|
+build setupDB
|
|
</pre>
|
|
</pre>
|
|
</p>
|
|
</p>
|
|
|
|
|
|
|
|
+
|
|
<h2>Build and deploy the Petclinic WAR file</h2>
|
|
<h2>Build and deploy the Petclinic WAR file</h2>
|
|
|
|
|
|
<p>
|
|
<p>
|
|
-Use the Ant build and deploy to your servlet container:
|
|
|
|
|
|
+Use Petclinic's Ant build script and deploy to your servlet container:
|
|
<pre>
|
|
<pre>
|
|
cd %spring%\samples\petclinic
|
|
cd %spring%\samples\petclinic
|
|
build warfile
|
|
build warfile
|
|
@@ -138,12 +140,83 @@ copy dist\petclinic.war %TOMCAT_HOME%\webapps
|
|
<p>Finally, start your container and try to visit the home page.
|
|
<p>Finally, start your container and try to visit the home page.
|
|
Your request should be intercepted and you will be forced to login.</p>
|
|
Your request should be intercepted and you will be forced to login.</p>
|
|
|
|
|
|
|
|
+<h2>Optional Bonus: Securing the Middle Tier</h2>
|
|
|
|
+<p>
|
|
|
|
+Whilst you've now secured your web requests, you might want to stop users
|
|
|
|
+from being able to add clinic visits unless authorized. We'll make it so
|
|
|
|
+you need to hold ROLE_SUPERVISOR to add a clinic visit.
|
|
|
|
+</p>
|
|
|
|
+
|
|
|
|
+<p>
|
|
|
|
+In %spring%\samples\petclinic\war\WEB-INF\applicationContext-jdbc.xml, locate
|
|
|
|
+the TransactionProxyFactoryBean definition. Add an additional property after
|
|
|
|
+the existing "preInterceptors" property:
|
|
|
|
+<pre>
|
|
|
|
+<property name="postInterceptors" ref="methodSecurityInterceptor"/>
|
|
|
|
+</pre>
|
|
|
|
+</p>
|
|
|
|
+
|
|
|
|
+<p>
|
|
|
|
+Finally, we need to add in the referred-to "methodSecurityInterceptor" bean definition.
|
|
|
|
+So pop an extra bean definition in, as shown below:
|
|
|
|
+<pre>
|
|
|
|
+<bean id="methodSecurityInterceptor" class="org.acegisecurity.intercept.method.aopalliance.MethodSecurityInterceptor">
|
|
|
|
+ <property name="authenticationManager"><ref bean="authenticationManager"/></property>
|
|
|
|
+ <property name="accessDecisionManager">
|
|
|
|
+ <bean class="org.acegisecurity.vote.AffirmativeBased">
|
|
|
|
+ <property name="allowIfAllAbstainDecisions" value="false"/>
|
|
|
|
+ <property name="decisionVoters">
|
|
|
|
+ <list>
|
|
|
|
+ <bean class="org.acegisecurity.vote.RoleVoter"/>
|
|
|
|
+ <bean class="org.acegisecurity.vote.AuthenticatedVoter"/>
|
|
|
|
+ </list>
|
|
|
|
+ </property>
|
|
|
|
+ </bean>
|
|
|
|
+ </property>
|
|
|
|
+ <property name="objectDefinitionSource">
|
|
|
|
+ <value>
|
|
|
|
+ org.springframework.samples.petclinic.Clinic.*=IS_AUTHENTICATED_REMEMBERED
|
|
|
|
+ org.springframework.samples.petclinic.Clinic.storeVisit=ROLE_SUPERVISOR
|
|
|
|
+ </value>
|
|
|
|
+ </property>
|
|
|
|
+</bean>
|
|
|
|
+</pre>
|
|
|
|
+</p>
|
|
|
|
+
|
|
|
|
+<p>
|
|
|
|
+Redeploy your web application. Use the earlier process to do that. Be careful to
|
|
|
|
+ensure that the old Petclinic WAR is replaced by the new Petclinic WAR in your
|
|
|
|
+servlet container. Login as "marissa", who has ROLE_SUPERVISOR. You will be able to
|
|
|
|
+then view a customer and add a visit. Logout, then login as anyone other than Marissa.
|
|
|
|
+You will receive an access denied error when you attempt to add a visit.
|
|
|
|
+</p>
|
|
|
|
+
|
|
|
|
+<p>
|
|
|
|
+To clean things up a bit, you might want to wrap up by hiding the "add visit" link
|
|
|
|
+unless you are authorized to use it. Acegi Security provides a tag library to help
|
|
|
|
+you do that. Edit %spring%\samples\petclinic\war\WEB-INF\jsp\owner.jsp. Add
|
|
|
|
+the following line to the top of the file:
|
|
|
|
+<pre>
|
|
|
|
+<%@ taglib prefix="authz" uri="http://acegisecurity.org/authz" %>
|
|
|
|
+</pre>
|
|
|
|
+Next, scroll down and find the link to "add visit". Modify it as follows:
|
|
|
|
+<pre>
|
|
|
|
+<authz:authorize ifAllGranted="ROLE_SUPERVISOR">
|
|
|
|
+ <FORM method=GET action="<c:url value="/addVisit.htm"/>" name="formVisitPet<c:out value="${pet.id}"/>">
|
|
|
|
+ <INPUT type="hidden" name="petId" value="<c:out value="${pet.id}"/>"/>
|
|
|
|
+ <INPUT type="submit" value="Add Visit"/>
|
|
|
|
+ </FORM>
|
|
|
|
+</authz:authorize>
|
|
|
|
+</pre>
|
|
|
|
+</p>
|
|
|
|
+
|
|
<h2>What now?</h2>
|
|
<h2>What now?</h2>
|
|
<p>
|
|
<p>
|
|
These steps can be applied to your own application. Although we do suggest
|
|
These steps can be applied to your own application. Although we do suggest
|
|
that you visit <a href="http://acegisecurity.org">http://acegisecurity.org</a>
|
|
that you visit <a href="http://acegisecurity.org">http://acegisecurity.org</a>
|
|
and in particular review the "Suggested Steps" for getting started with Acegi
|
|
and in particular review the "Suggested Steps" for getting started with Acegi
|
|
-Security.</p>
|
|
|
|
-
|
|
|
|
|
|
+Security. The suggested steps are optimized for learning Acegi Security quickly
|
|
|
|
+and applying it to your own projects. It also includes realistic time estimates
|
|
|
|
+for each step so you can plan your integration activities.</p>
|
|
</body>
|
|
</body>
|
|
</html>
|
|
</html>
|