]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
b54b8e50d8c18ac29cf54c5162b6bfb3829b432a
[tmp/jakarta-migration.git] /
1 /**
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:
5
6  *  http://www.collectionspace.org
7  *  http://wiki.collectionspace.org
8
9  *  Copyright 2009 University of California at Berkeley
10
11  *  Licensed under the Educational Community License (ECL), Version 2.0.
12  *  You may not use this file except in compliance with this License.
13
14  *  You may obtain a copy of the ECL 2.0 License at
15
16  *  https://source.collectionspace.org/collection-space/LICENSE.txt
17
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.
23  */
24 package org.collectionspace.services.authorization.driver;
25
26 import java.io.File;
27 import java.util.ArrayList;
28 import java.util.HashSet;
29 import java.util.List;
30
31 import javax.persistence.EntityManager;
32 import javax.persistence.EntityManagerFactory;
33
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;
49
50 import org.hibernate.exception.ConstraintViolationException;
51
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
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;
64
65 /**
66  * A driver for seeding authorization
67  * @author 
68  */
69 public class AuthorizationSeedDriver {
70
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";
76     private String user;
77     private String password;
78     private String tenantBindingFile;
79     private String exportDir;
80     private AuthorizationGen authzGen;
81     private org.springframework.jdbc.datasource.DataSourceTransactionManager txManager;
82
83     /**
84      * AuthorizationSeedDriver
85      * @param user to use to establish security context. should be in ROLE_ADMINISTRATOR
86      * @param password
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
91      */
92     public AuthorizationSeedDriver(String user, String password,
93             String tenantBindingFile,
94             String exportDir) {
95         if (user == null || user.isEmpty()) {
96             throw new IllegalArgumentException("username required.");
97         }
98         this.user = user;
99
100         if (password == null || password.isEmpty()) {
101             throw new IllegalArgumentException("password required.");
102         }
103         this.password = password;
104         
105         if (tenantBindingFile == null || tenantBindingFile.isEmpty()) {
106             throw new IllegalArgumentException("tenantbinding file are required.");
107         }
108         this.tenantBindingFile = tenantBindingFile;
109         if (exportDir == null || exportDir.isEmpty()) {
110             throw new IllegalArgumentException("exportdir required.");
111         }
112         this.exportDir = exportDir;
113
114     }
115
116     public void generate(JPATransactionContext jpaTransactionContext) {
117         try {
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.");
128             }
129         } catch (Exception ex) {
130             logger.error("AuthorizationSeedDriver caught an exception: ", ex);
131             throw new RuntimeException(ex);
132         }
133     }
134
135     public void seed(JPATransactionContext jpaTransactionContext) {
136         TransactionStatus status = null;
137         try {
138                 // Push all the authz info into the cspace DB tables -this include default roles, permissions, and permroles
139             store();
140
141             setupSpring();
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.");
147             }
148         } catch (Exception ex) {
149             if (status != null) {
150                 rollbackTransaction(status);
151             }
152             if (logger.isDebugEnabled()) {
153                 ex.printStackTrace();
154             }
155             throw new RuntimeException(ex);
156         } finally {
157             if (status != null) {
158                 commitTransaction(status);
159             }
160             logout();
161         }
162     }
163
164     /**
165      * Setup of Spring Security context
166      */
167     private void setupSpring() {
168         ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext(
169                 new String[]{SPRING_SECURITY_METADATA});
170         login();
171         System.setProperty("spring-beans-config", SPRING_SECURITY_METADATA);
172         //
173         // authZ local not used but call to AuthZ.get() has side-effect of initializing our Spring Security context
174         //
175         AuthZ authZ = AuthZ.get();
176         txManager = (org.springframework.jdbc.datasource.DataSourceTransactionManager) appContext.getBean("transactionManager");
177         //
178         // debug
179         //
180         if (logger.isDebugEnabled()) {
181             logger.debug("Spring Security setup complete.");
182         }
183     }
184
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);
195         }
196     }
197
198     private void logout() {
199         SecurityContextHolder.getContext().setAuthentication(null);
200         if (logger.isDebugEnabled()) {
201             logger.debug("Spring Security logged out user=" + user);
202         }
203     }
204
205     private void store() throws Exception {
206         JPATransactionContext jpaTransactionContext = new JPATransactionContext((ServiceContext)null);
207         try {
208                 jpaTransactionContext.beginTransaction();
209             
210                 AuthorizationStore authzStore = new AuthorizationStore();
211                 logger.info("Seeding Roles metadata to database.");
212                 for (Role role : authzGen.getDefaultRoles()) {
213                         try {
214                                 authzStore.store(jpaTransactionContext, role);
215                         } catch (Exception e) {
216                                 //
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());
222                                         //
223                                         role = existingRole;
224                                 }
225                         }
226                 }
227         
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);
231                 }
232         
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);
238                 }
239                 for (PermissionRoleRel permRoleRel : permRoleRels) {
240                     authzStore.store(jpaTransactionContext, permRoleRel);
241                 }
242         
243                 jpaTransactionContext.commitTransaction();
244                 if (logger.isInfoEnabled()) {
245                     logger.info("All Authorization metadata persisted.");
246                 }
247         } catch (Exception e) {
248                 jpaTransactionContext.markForRollback();
249             if (logger.isDebugEnabled()) {
250                 logger.debug("Caught exception and rolling back permission creation: ", e);
251             }
252             throw e;
253         } finally {
254                 jpaTransactionContext.close();
255         }
256     }
257
258     /*
259      * Find the associated tenant ID for this permission role instance.  Uses the tenant ID found in the first role.  
260      */
261     private String getTenantId(PermissionRole pr) {
262                 String result = null;
263                 
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();
267                 
268                 return result;
269         }
270
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
274         def.setName(name);
275         def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
276         return txManager.getTransaction(def);
277     }
278
279     private void rollbackTransaction(TransactionStatus status) {
280         txManager.rollback(status);
281     }
282
283     private void commitTransaction(TransactionStatus status) {
284         txManager.commit(status);
285     }
286 }