2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright 2009 University of California at Berkeley
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
16 * https://source.collectionspace.org/collection-space/LICENSE.txt
18 * Unless required by applicable law or agreed to in writing, software
19 * distributed under the License is distributed on an "AS IS" BASIS,
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21 * See the License for the specific language governing permissions and
22 * limitations under the License.
24 package org.collectionspace.services.authorization.driver;
27 import java.util.ArrayList;
28 import java.util.HashSet;
29 import java.util.List;
31 import javax.persistence.EntityManager;
32 import javax.persistence.EntityManagerFactory;
34 import org.collectionspace.authentication.AuthN;
35 import org.collectionspace.services.authorization.AuthZ;
36 import org.collectionspace.services.authorization.perms.Permission;
37 import org.collectionspace.services.authorization.PermissionRole;
38 import org.collectionspace.services.authorization.PermissionRoleRel;
39 import org.collectionspace.services.authorization.Role;
40 import org.collectionspace.services.authorization.SubjectType;
41 import org.collectionspace.services.authorization.importer.AuthorizationGen;
42 import org.collectionspace.services.authorization.importer.AuthorizationSeed;
43 import org.collectionspace.services.common.authorization_mgt.AuthorizationCommon;
44 import org.collectionspace.services.common.authorization_mgt.AuthorizationStore;
45 import org.collectionspace.services.common.authorization_mgt.PermissionRoleUtil;
46 import org.collectionspace.services.common.context.ServiceContext;
47 import org.collectionspace.services.common.storage.jpa.JPATransactionContext;
48 import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
50 import org.hibernate.exception.ConstraintViolationException;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
55 import org.springframework.context.support.ClassPathXmlApplicationContext;
56 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
57 import org.springframework.security.core.Authentication;
58 import org.springframework.security.core.GrantedAuthority;
59 import org.springframework.security.core.authority.SimpleGrantedAuthority;
60 import org.springframework.security.core.context.SecurityContextHolder;
61 import org.springframework.transaction.TransactionDefinition;
62 import org.springframework.transaction.TransactionStatus;
63 import org.springframework.transaction.support.DefaultTransactionDefinition;
66 * A driver for seeding authorization
69 public class AuthorizationSeedDriver {
71 final Logger logger = LoggerFactory.getLogger(AuthorizationSeedDriver.class);
72 final static private String SPRING_SECURITY_METADATA = "applicationContext-authorization-test.xml";
73 final static private String ROLE_FILE = "import-roles.xml";
74 final static private String PERMISSION_FILE = "import-permissions.xml";
75 final static private String PERMISSION_ROLE_FILE = "import-permissions-roles.xml";
77 private String password;
78 private String tenantBindingFile;
79 private String exportDir;
80 private AuthorizationGen authzGen;
81 private org.springframework.jdbc.datasource.DataSourceTransactionManager txManager;
84 * AuthorizationSeedDriver
85 * @param user to use to establish security context. should be in ROLE_ADMINISTRATOR
87 * @param tenantBindingFile
88 * @param importDir dir to import permisison/permission role file from. same as
89 * export dir by default
90 * @param exportDir dir to export permission/permission role file to
92 public AuthorizationSeedDriver(String user, String password,
93 String tenantBindingFile,
95 if (user == null || user.isEmpty()) {
96 throw new IllegalArgumentException("username required.");
100 if (password == null || password.isEmpty()) {
101 throw new IllegalArgumentException("password required.");
103 this.password = password;
105 if (tenantBindingFile == null || tenantBindingFile.isEmpty()) {
106 throw new IllegalArgumentException("tenantbinding file are required.");
108 this.tenantBindingFile = tenantBindingFile;
109 if (exportDir == null || exportDir.isEmpty()) {
110 throw new IllegalArgumentException("exportdir required.");
112 this.exportDir = exportDir;
116 public void generate(JPATransactionContext jpaTransactionContext) {
118 authzGen = new AuthorizationGen();
119 authzGen.initialize(tenantBindingFile);
120 authzGen.createDefaultRoles(jpaTransactionContext);
121 authzGen.createDefaultPermissions(jpaTransactionContext);
122 authzGen.associateDefaultPermissionsRoles();
123 authzGen.exportDefaultRoles(exportDir + File.separator + ROLE_FILE);
124 authzGen.exportDefaultPermissions(exportDir + File.separator + PERMISSION_FILE);
125 authzGen.exportDefaultPermissionRoles(exportDir + File.separator + PERMISSION_ROLE_FILE);
126 if (logger.isDebugEnabled()) {
127 logger.debug("Authorization generation completed but not yet persisted.");
129 } catch (Exception ex) {
130 logger.error("AuthorizationSeedDriver caught an exception: ", ex);
131 throw new RuntimeException(ex);
135 public void seed(JPATransactionContext jpaTransactionContext) {
136 TransactionStatus status = null;
138 // Push all the authz info into the cspace DB tables -this include default roles, permissions, and permroles
142 status = beginTransaction("seedData");
143 AuthorizationSeed authzSeed = new AuthorizationSeed();
144 authzSeed.seedPermissions(jpaTransactionContext, authzGen.getDefaultPermissions(), authzGen.getDefaultPermissionRoles());
145 if (logger.isDebugEnabled()) {
146 logger.debug("Authorization seeding completed.");
148 } catch (Exception ex) {
149 if (status != null) {
150 rollbackTransaction(status);
152 if (logger.isDebugEnabled()) {
153 ex.printStackTrace();
155 throw new RuntimeException(ex);
157 if (status != null) {
158 commitTransaction(status);
165 * Setup of Spring Security context
167 private void setupSpring() {
168 ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
169 new String[]{SPRING_SECURITY_METADATA});
171 System.setProperty("spring-beans-config", SPRING_SECURITY_METADATA);
173 // authZ local not used but call to AuthZ.get() has side-effect of initializing our Spring Security context
175 AuthZ authZ = AuthZ.get();
176 txManager = (org.springframework.jdbc.datasource.DataSourceTransactionManager) appContext.getBean("transactionManager");
180 if (logger.isDebugEnabled()) {
181 logger.debug("Spring Security setup complete.");
185 private void login() {
186 //GrantedAuthority cspace_admin = new SimpleGrantedAuthority("ROLE_ADMINISTRATOR");
187 GrantedAuthority spring_security_admin = new SimpleGrantedAuthority(AuthN.ROLE_SPRING_ADMIN_NAME); //NOTE: Must match with value in applicationContext-authorization-test.xml (aka SPRING_SECURITY_METADATA)
188 HashSet<GrantedAuthority> gauths = new HashSet<GrantedAuthority>();
189 //gauths.add(cspace_admin);
190 gauths.add(spring_security_admin);
191 Authentication authRequest = new UsernamePasswordAuthenticationToken(user, password, gauths);
192 SecurityContextHolder.getContext().setAuthentication(authRequest);
193 if (logger.isDebugEnabled()) {
194 logger.debug("Spring Security login successful for user=" + user);
198 private void logout() {
199 SecurityContextHolder.getContext().setAuthentication(null);
200 if (logger.isDebugEnabled()) {
201 logger.debug("Spring Security logged out user=" + user);
205 private void store() throws Exception {
206 JPATransactionContext jpaTransactionContext = new JPATransactionContext((ServiceContext)null);
208 jpaTransactionContext.beginTransaction();
210 AuthorizationStore authzStore = new AuthorizationStore();
211 logger.info("Seeding Roles metadata to database.");
212 for (Role role : authzGen.getDefaultRoles()) {
214 authzStore.store(jpaTransactionContext, role);
215 } catch (Exception e) {
217 // If the role already exists, read it in and replace the instance
218 // we're trying to import with the exist one. This will ensure that the rest
219 // of import uses the correct CSID.
220 if (e.getCause() instanceof ConstraintViolationException) {
221 Role existingRole = authzStore.getRoleByName(jpaTransactionContext, role.getRoleName(), role.getTenantId());
228 logger.info("Seeding Permissions metadata to database.");
229 for (Permission perm : authzGen.getDefaultPermissions()) { //FIXME: REM - 3/27/2012 - If we change the CSID of permissions to something like a refname, then we need to check for existing perms just like we did above for roles
230 authzStore.store(jpaTransactionContext, perm);
233 logger.info("Seeding Permissions/Roles relationships metadata to database.");
234 List<PermissionRoleRel> permRoleRels = new ArrayList<PermissionRoleRel>();
235 for (PermissionRole pr : authzGen.getDefaultPermissionRoles()) {
236 String tenantId = getTenantId(pr);
237 PermissionRoleUtil.buildPermissionRoleRel(jpaTransactionContext, pr, SubjectType.ROLE, permRoleRels, false /*not for delete*/, tenantId);
239 for (PermissionRoleRel permRoleRel : permRoleRels) {
240 authzStore.store(jpaTransactionContext, permRoleRel);
243 jpaTransactionContext.commitTransaction();
244 if (logger.isInfoEnabled()) {
245 logger.info("All Authorization metadata persisted.");
247 } catch (Exception e) {
248 jpaTransactionContext.markForRollback();
249 if (logger.isDebugEnabled()) {
250 logger.debug("Caught exception and rolling back permission creation: ", e);
254 jpaTransactionContext.close();
259 * Find the associated tenant ID for this permission role instance. Uses the tenant ID found in the first role.
261 private String getTenantId(PermissionRole pr) {
262 String result = null;
264 // Since all the role and permission values in a PermissionRole instance *must* have the same tenant ID, we
265 // can just get the tenant ID from the 0th (first) role.
266 result = pr.getRole().get(0).getTenantId();
271 private TransactionStatus beginTransaction(String name) {
272 DefaultTransactionDefinition def = new DefaultTransactionDefinition();
273 // explicitly setting the transaction name is something that can only be done programmatically
275 def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
276 return txManager.getTransaction(def);
279 private void rollbackTransaction(TransactionStatus status) {
280 txManager.rollback(status);
283 private void commitTransaction(TransactionStatus status) {
284 txManager.commit(status);