NOTE: AndroMDA has been upgraded to Spring 3.1, however the Acegi framework is not compatible with Spring 2.5+, and has been replaced by the spring-security framework. This completely changes the namespace and values in the Spring configuration file. The andromda templates have been updated to the correct classes and namespaces, but have not been tested yet. See http://static.springsource.org/spring-security/site/ and http://java.dzone.com/tips/pathway-acegi-spring-security- and http://raibledesigns.com/rd/entry/upgrading_to_spring_security_2
In this section we will add security to TimeTracker by integrating it with the Spring Security System. The integration will ensure that only authenticated users can access secured pages. Currently all pages in TimeTracker are specified to be secure, except of course the Login page. Even if the user has bookmarked a page and tries to view it directly without presenting her credentials, Spring Security will intercept the request and present the Login page. Once the credentials are presented and verified, user will be directed to the page she was trying to access.
We chose Spring Security System because it provides a portable and effective security framework for enterprise applications. Look at the Spring Security Home Page to understand its key features. Also look at the Frequently Asked Questions to understand what Spring Security provides over alternate solutions such as web.xml security and JAAS. You may also want to read the Main Features section of the Spring Security Reference Guide. Armed with all this knowledge, let's get down to business. Remember that if you run into problems, you can always compare your implementation with the completed solution to figure out what's going on.
We will first create a new service called SecurityService that allows the front-end to verify user credentials. We chose not to add this functionality to the UserService because of the confidential nature of this information. UserService may be something you want to expose to the outside world, but definately not passwords and other secure information of similar nature. Follow the steps below to add SecurityService to TimeTracker.
-- Password is 'cooldude' encoded using MD5 insert into USERS (ID, USERNAME, PASSWORD, FIRST_NAME, LAST_NAME, EMAIL, IS_ACTIVE, CREATION_DATE, COMMENT) values (1, 'nbhatia', '756slLjeNViurJBGI5JeqA==', 'Naresh', 'Bhatia', 'nbhatia@northwind.com', 1, '2011/01/01 09:00', null); insert into USERS (ID, USERNAME, PASSWORD, FIRST_NAME, LAST_NAME, EMAIL, IS_ACTIVE, CREATION_DATE, COMMENT) values (2, 'lcoude', '756slLjeNViurJBGI5JeqA==', 'Louis', 'Coude', 'lcoude@northwind.com', 1, '2011/01/01 09:00', null); insert into USERS (ID, USERNAME, PASSWORD, FIRST_NAME, LAST_NAME, EMAIL, IS_ACTIVE, CREATION_DATE, COMMENT) values (3, 'ecrutchfield', '756slLjeNViurJBGI5JeqA==', 'Eric', 'Crutchfield', 'ecrutchfield@northwind.com', 1, '2011/01/01 09:00', null); insert into USERS (ID, USERNAME, PASSWORD, FIRST_NAME, LAST_NAME, EMAIL, IS_ACTIVE, CREATION_DATE, COMMENT) values (4, 'cmicali', '756slLjeNViurJBGI5JeqA==', 'Chris', 'Micali', 'cmicali@northwind.com', 1, '2011/01/01 09:00', null); insert into USER_ROLE (ID, ROLE, USER_FK) values (1, 'StandardUser', 1); insert into USER_ROLE (ID, ROLE, USER_FK) values (2, 'Administrator', 1); insert into USER_ROLE (ID, ROLE, USER_FK) values (3, 'StandardUser', 2); insert into USER_ROLE (ID, ROLE, USER_FK) values (4, 'StandardUser', 3); insert into USER_ROLE (ID, ROLE, USER_FK) values (5, 'StandardUser', 4); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values ( 1, 'Approved', '2011/05/15', 'Timecard 01', 1, 2); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values ( 2, 'Approved', '2011/05/15', 'Timecard 02', 2, 3); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values ( 3, 'Approved', '2011/05/15', 'Timecard 03', 3, 4); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values ( 4, 'Approved', '2011/05/15', 'Timecard 04', 4, 1); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values ( 5, 'Rejected', '2011/05/22', 'Timecard 05', 1, 2); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values ( 6, 'Rejected', '2011/05/22', 'Timecard 06', 2, 3); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values ( 7, 'Rejected', '2011/05/22', 'Timecard 07', 3, 4); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values ( 8, 'Rejected', '2011/05/22', 'Timecard 08', 4, 1); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values ( 9, 'Submitted', '2011/05/29', 'Timecard 09', 1, 2); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values (10, 'Submitted', '2011/05/29', 'Timecard 10', 2, 3); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values (11, 'Submitted', '2011/05/29', 'Timecard 11', 3, 4); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values (12, 'Submitted', '2011/05/29', 'Timecard 12', 4, 1); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values (13, 'Draft', '2011/06/05', 'Timecard 13', null, 2); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values (14, 'Draft', '2011/06/05', 'Timecard 14', null, 3); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values (15, 'Draft', '2011/06/05', 'Timecard 15', null, 4); insert into TIMECARD (ID, STATUS, START_DATE, COMMENTS, APPROVER_FK, SUBMITTER_FK) values (16, 'Draft', '2011/06/05', 'Timecard 16', null, 1);
protected User handleGetUserDetails(String username) throws Exception { User user = (User)getSession().createQuery( "from org.andromda.timetracker.domain.User user " + "left join fetch user.roles " + "where user.username = :username") .setParameter("username", username) .uniqueResult(); return user; }
import java.util.Collection; import org.andromda.timetracker.vo.UserRoleVO;
public void toUserDetailsVO( org.andromda.timetracker.domain.User sourceEntity, org.andromda.timetracker.vo.UserDetailsVO targetVO) { super.toUserDetailsVO(sourceEntity, targetVO); // Convert roles Collection srcRoles = sourceEntity.getRoles(); UserRoleVO[] targetRoles = new UserRoleVO[srcRoles.size()]; int i=0; for (Object srcRole : srcRoles) { targetRoles[i] = getUserRoleDao().toUserRoleVO((UserRole)srcRole); i++; } targetVO.setRoles(targetRoles); }
import org.andromda.timetracker.domain.User; import org.andromda.timetracker.vo.UserDetailsVO; ... protected UserDetailsVO handleGetUserDetails(String username) throws java.lang.Exception { UserDetailsVO userDetailsVO = null; User user = getUserDao().getUserDetails(username); if (user != null) { userDetailsVO = getUserDao().toUserDetailsVO(user); } return userDetailsVO; }
We are now ready to introduce Spring Security as a dependency for TimeTracker.
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>3.1.0.RELEASE</version> <exclusions> <exclusion> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-remoting</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-support</artifactId> </exclusion> </exclusions> </dependency>
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> </dependency>
Congratulations! You have made it successfully to the end of this tutorial. Click here to find out where to go from here.