#Enabling method security
- Add a
<security:global-method-security/>configuration tag and enable the secured annotations - Add
@org.springframework.security.access.annotation.SecuredAnnotations with a role name to the methods of theSimpleAccountManager. The role name must start with `ROLE_ - Verify that the test fails with An Authentication object was not found in the SecurityContext
- Create a
@org.junit.BeforeMethod inside the jUnit Test and authenticate the user by- Creating a empty
SecurityContextwithSecurityContextHolder.createEmptyContext(); - Setting a org.springframework.security.authentication.TestingAuthenticationToken` to the context
- Binding the context with
org.springframework.security.core.context.SecurityContextHolder#setContextmethod
- Creating a empty
- Do not forget to create a
@org.junit.Aftermethod which clears theSecurityContext - Add a
<security:authentication-manager/>element into your code - Refactor the
@Beforemethod to use theorg.springframework.security.authentication.AuthenticationManagerto authenticate before setting theSecurityContext - Run the test an notice the exception No AuthenticationProvider found for org.springframework.security.authentication.TestingAuthenticationToken
- Configure a
org.springframework.security.authentication.TestingAuthenticationProvider - Reference to the newly created
TestingAuthenticationProviderinside<security:authentication-manager/>with a nestedsecurity:authentication-providerelement - Run the test and verify that it is green
- Add a new
<security:user-service/>element and created one user with a password and the specific role as nested<security:user/>element - Name the
<security:user-service/>with an id, which will be used later - Replace the
<security:authentication-provider ref=".."/>attribute with an<security:authentication-provider user-service-ref=".."/>attribute - Provide the bean name to your
<security:user-service/>bean - Run the test and notice a No AuthenticationProvider found for org.springframework.security.authentication.TestingAuthenticationToken
- Re-write your
@Beforemethod to use aorg.springframework.security.authentication.UsernamePasswordAuthenticationToken - Verify that the test runs
- OPTIONAL: You can change the password (which is different to the configured user) and see that a Bad Credentials exception is thrown
- Add a
<security:password-encoder hash="md5"/>to the<security:authentication-provider/>as a nested element - Run the test and recognize the Bad Credentials exception
- Replace your password with a md5 hashed one (e.g. 5ebe2294ecd0e0f08eab7690d2a6ee69 instead of secret )
- Re-run the test and verify the green bar
- Add a new element
<security:salt-source system-wide="verySecret"/>as a sub element of<security:password-encoder hash="md5"/> - Re-run the test and recognize the Bad Credentials exception
- Create a md5 (e.g. online) for the password with the salt
password{salt}(e.g. secret{verySecret} has a md5 of 69819676c786fc8d36f1365e7cf07d2c) and set that as a password for your user - Change the
<security:salt-source />to use a user-property ("username") instead of a system-wide salt - Re-run the test and see them failing with a Bad Credentials exception
- Change the hash to match your username and salt (e.g. for the user agim the the md5 source is secret{agim} which is dadacb850ece4991a835177831d1fb35)
- Re-run the test and see the green bar
- Create an own instance of the
org.springframework.security.core.userdetails.UserDetailsServiceinterface - Inside that class implement the method
loadUserByUsernameto return aorg.springframework.security.core.userdetails.Userfor the given user name (Do not forget to return the encoded password ) - Annotate your implementation with a
org.springframework.stereotype.Componentannotation - Remove the
<security:user-service/>and replace theuser-service-refattribute inside thesecurity:authentication-providerwith your bean name - Re-run the test and notice the green bar (If one test runs and the other fails, then please ensure to return a copy of the User for each request, because credentials are erased after authentication)
-
First add the following dependencies to the maven pom and refresh your project
org.apache.directory.server:apacheds-server-jndi:1.5.5org.springframework.security:spring-security-ldap:${spring-security-version}org.slf4j:slf4j-jcl:1.5.6
-
We need to populate our ldap server with the user to register, therefore open
src/main/resources/account/users.ldifand add the following user definitiondn: uid=<myUser>,ou=people,dc=mimacom,dc=comobjectclass: topobjectclass: personobjectclass: organizationalPersonobjectclass: inetOrgPersonuid: <myUser>userPassword: <myPassword> -
Replace
<myUser>(2xtimes) and<myPassword>with your values, please ensure to user the same user that you have used before -
Open the
/account/accounts-config.xmland add an<security:ldap-server/>element with anid, the reference to the ldif file and the followingrootattribute value"dc=mimacom,dc=com" -
Replace your authentication provider with an
ldap-authentication-providerelement -
Add a server reference to the
<security:ldap-server/>server -
Run the tests, you should now get a Access is denied. This because the user does not have any roles in the LDAP
-
Open
src/main/resources/account/users.ldifand insert the following group definition (after your user)
dn: cn=<myRole>,ou=groups,dc=mimacom,dc=com
objectClass: groupOfNames
objectClass: top
cn: <myRole>
description: Application users
- Add your user to the definition by adding the following line after the group description
uniquemember: uid=<myUser>,ou=people,dc=mimacom,dc=com - Replace
<myUser>with your user id created before - Replace
<myRole>with the role name in the@Securedannotation (e.g. if you haveROLE_USERreplace it withUSER) - Run the test and notice the green bar
- Restore your configuration to use the UserDetailsService and remove all LDAP specific configuration files (replace
ldap-authentication-providerwith<security:authentication-provider user-service-ref="simpleUserDetailsService"> <security:password-encoder hash="md5"> <security:salt-source user-property="username"/> </security:password-encoder> </security:authentication-provider>) - Re-run your test to ensure that you have a green bar
- Add a new role to the
account.internal.SimpleAccountManager#storeAccountmethod (e.g. you should have two roles@Secured({"ROLE_USER", "ROLE_ADMIN"})) - Run the test and ensure that you have a green bar
- Create a new
org.springframework.security.access.vote.AffirmativeBasedbean and add aorg.springframework.security.access.vote.RoleVoterto the constructor argument - In the
<security:global-method-security/>element set the attributeaccess-decision-manager-refas a reference to the previously created access decision manager - Run the test and ensure that you have a green bar
- Replace the
org.springframework.security.access.vote.AffirmativeBasedbean class with aorg.springframework.security.access.vote.UnanimousBased - Run the test an notice the red bar with the Access is denied exception
- Go into you
org.springframework.security.core.userdetails.UserDetailsServiceimplementation and give the user both roles that you specified in the store method - Re-run the test and notice the green bar
- Remove your custom access decision manager created before
- Enable the
org.springframework.security.access.prepost.PreAuthorizeandorg.springframework.security.access.prepost.PostAuthorizein the<security:global-method-security/>element - Replace the
org.springframework.security.access.annotation.Securedannotation withorg.springframework.security.access.prepost.PreAuthorizeannotation - Run the tests to ensure a green bar
- Add a new field called
ownerto theaccount.domain.Accountclass of typeString, the owner will be the user name who is allowed to load and store the accounts - Add a
org.springframework.security.access.prepost.PostAuthorizeannotation to theaccount.internal.SimpleAccountManager#getByIdmethod. Check if the returned object it's owner field equals to the username (Hint: the return object is available through the key wordreturnObjectand the current user through the key wordauthentication) - Extends the
org.springframework.security.access.prepost.PreAuthorizeto also evaluate that theaccountparameter has the same owner as the current user. You can retrieve the parameter through the#accountkeyword. - Run the test and ensure a green bar
- Play around by setting a different user name to the Account object then the logged in user, you should recognize an Access Denied exception
- Add the following maven dependencies to use spring security in a web environment
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring-framework-version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>${spring-security-version}</version> </dependency> - Open the file
src/main/webapp/WEB-INF/web.xmland add a new listener with the class nameorg.springframework.web.context.ContextLoaderListener - Create a spring configuration file
/src/main/webapp/WEB-INF/applicationContext.xmland import the fileclasspath:/account/accounts-config.xml - Start the application, and you should see rendered
index.jspon your browser - Add a
<security:http/>element to the config file and an automated form login by adding a<security:form-login/>element as a sub-element - Open the
src/main/webapp/WEB-INF/web.xmland add a new filter with the namespringSecurityFilterChainand the classorg.springframework.web.filter.DelegatingFilterProxy - Map the filter to intercept all the request with the pattern /*
- Open the
src/main/webapp/WEB-INF/web.xmland secure the url /* to be only accessed by a valid role - Re-start your server and login into your application
1.- Create a key store for the server by calling the java key tool with the following command
keytool -genkeypair -alias serverkey -keyalg RSA -dname "CN=Web Server,OU=Hosting Company,O=mimacom,L=Stuttgart,S=BW,C=DE" -keystore server.jks
-
Create a key store for the client by calling the java key tool with the following command
keytool -genkeypair -alias clientkey -keyalg RSA -dname "CN=agim,OU=Development,O=mimacom,L=Stuttgart,S=BW,C=DE" -keystore client.jks -
Now export public key of the client (which will be imported on the server) by issueing the following command
keytool -exportcert -alias clientkey -file client-public.cer -keystore client.jks -
Now import the client certificate to the server it’s trust store (so that the server can verify the private key of the client)
keytool -importcert -keystore server.jks -alias clientcert -file client-public.cer -
Now export the public certificate from the server for the client browser du verify the server it’s identity
keytool -exportcert -alias serverkey -file server-public.cer -keystore server.jks -
Now import the client server certificate to the client trust store, in case you want to use a java client
keytool -importcert -keystore client.jks -alias servercert -file server-public.cer -
Configure the SSL connector for tomcat and point to your
server.jksfile and configure the password for the key store. You can configure the connector in the server.xml inside the conf directory of your tomcat instance. The definition for a container looks like this
<Connector protocol="HTTP/1.1" port="8443" maxThreads="20" scheme="https" secure="true" SSLEnabled="true" keystoreFile="<yourPath>/server.jks" keystorePass=„<yourPass>" truststoreFile=„<yourPath>/server.jks" truststorePass="<yourPass>" clientAuth=„false" sslProtocol="TLS" />
- Next start the web application and use the link [https://localhost:8080], add the (unsigned) certificate to your browser key store
- Next open the file
src/main/webapp/WEB-INF/applicationContext.xmland replace the<security:form-login/>element with a<security:x509 /> - Add a
user-service-refelement to your user details service - Next you need to export the key store certificate which is Java specific to an open key file. Please run the following command to export your private key into a browser readable format
keytool -importkeystore -srckeystore client.jks -destkeystore client-private.p12 -srcstoretype jks -deststoretype pkcs12 - Next we need to enable the client authentication with certificates for the ssl connector. Therefore open the file
server.xmlin the conf folder of your and enable the client authentication by setting the clientAuth attribute to true in your config. - Restart your tomcat and call [http://localhost:8080/] and provide the exported certificate
- You should now see your application