]> git.aero2k.de Git - tmp/jakarta-migration.git/blob
2b1c5942faad73c36527b89c5336501205867e3c
[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.account.storage;
25
26 import java.util.Date;
27 import javax.persistence.EntityManager;
28 import javax.persistence.EntityManagerFactory;
29 import javax.persistence.Query;
30 import org.collectionspace.services.account.AccountsCommon;
31 import org.collectionspace.services.authentication.User;
32 import org.collectionspace.services.common.context.ServiceContext;
33 import org.collectionspace.services.common.document.BadRequestException;
34 import org.collectionspace.services.common.document.DocumentException;
35 import org.collectionspace.services.common.document.DocumentHandler;
36 import org.collectionspace.services.common.document.DocumentHandler.Action;
37 import org.collectionspace.services.common.document.DocumentNotFoundException;
38 import org.collectionspace.services.common.document.DocumentWrapper;
39 import org.collectionspace.services.common.document.DocumentWrapperImpl;
40 import org.collectionspace.services.common.security.SecurityUtils;
41 import org.collectionspace.services.common.storage.jpa.JpaStorageClientImpl;
42 import org.collectionspace.services.common.storage.jpa.JpaStorageUtils;
43
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46
47 /**
48  * AccountStorageClient deals with both Account and Default Identity Provider's
49  * state in persistent storage
50  * @author 
51  */
52 public class AccountStorageClient extends JpaStorageClientImpl {
53
54     private final Logger logger = LoggerFactory.getLogger(AccountStorageClient.class);
55
56     public AccountStorageClient() {
57     }
58
59     @Override
60     public String create(ServiceContext ctx,
61             DocumentHandler handler) throws BadRequestException,
62             DocumentException {
63
64         if (ctx == null) {
65             throw new IllegalArgumentException(
66                     "AccountStorageClient.create : ctx is missing");
67         }
68         if (handler == null) {
69             throw new IllegalArgumentException(
70                     "AccountStorageClient.create: handler is missing");
71         }
72         EntityManagerFactory emf = null;
73         EntityManager em = null;
74         try {
75             handler.prepare(Action.CREATE);
76             AccountsCommon account = (AccountsCommon) handler.getCommonPart();
77             DocumentWrapper<AccountsCommon> wrapDoc =
78                     new DocumentWrapperImpl<AccountsCommon>(account);
79             handler.handle(Action.CREATE, wrapDoc);
80             emf = JpaStorageUtils.getEntityManagerFactory();
81             em = emf.createEntityManager();
82             em.getTransaction().begin();
83             //if userid and password are given, add to default id provider
84             if (account.getUserId() != null && account.getPassword() != null) {
85                 User user = createUser(account);
86                 em.persist(user);
87             }
88 //            if (account.getTenant() != null) {
89 //                UserTenant ut = createTenantAssoc(account);
90 //                em.persist(ut);
91 //            }
92             account.setCreatedAtItem(new Date());
93             em.persist(account);
94             em.getTransaction().commit();
95             handler.complete(Action.CREATE, wrapDoc);
96             return (String) getValue(account, "getCsid");
97         } catch (BadRequestException bre) {
98             if (em != null && em.getTransaction().isActive()) {
99                 em.getTransaction().rollback();
100             }
101             throw bre;
102         } catch (Exception e) {
103             if (em != null && em.getTransaction().isActive()) {
104                 em.getTransaction().rollback();
105             }
106             if (logger.isDebugEnabled()) {
107                 logger.debug("Caught exception ", e);
108             }
109             throw new DocumentException(e);
110         } finally {
111             if (em != null) {
112                 JpaStorageUtils.releaseEntityManagerFactory(emf);
113             }
114         }
115     }
116
117     @Override
118     public void update(ServiceContext ctx, String id, DocumentHandler handler)
119             throws BadRequestException, DocumentNotFoundException,
120             DocumentException {
121         if (ctx == null) {
122             throw new IllegalArgumentException(
123                     "AccountStorageClient.update : ctx is missing");
124         }
125         if (handler == null) {
126             throw new IllegalArgumentException(
127                     "AccountStorageClient.update: handler is missing");
128         }
129         EntityManagerFactory emf = null;
130         EntityManager em = null;
131         try {
132             handler.prepare(Action.UPDATE);
133             AccountsCommon account = (AccountsCommon) handler.getCommonPart();
134             DocumentWrapper<AccountsCommon> wrapDoc =
135                     new DocumentWrapperImpl<AccountsCommon>(account);
136             setCsid(account, id); //set id just in case it was not populated by consumer
137             handler.handle(Action.UPDATE, wrapDoc);
138             emf = JpaStorageUtils.getEntityManagerFactory();
139             em = emf.createEntityManager();
140             em.getTransaction().begin();
141             AccountsCommon accountFound = getAccount(em, id);
142             Date now = new Date();
143             checkAllowedUpdates(account, accountFound);
144             //if userid and password are given, add to default id provider
145             if (account.getUserId() != null && hasPassword(account.getPassword())) {
146                 updateUser(em, account);
147             }
148             account = em.merge(account);
149             account.setUpdatedAtItem(now);
150             if (logger.isDebugEnabled()) {
151                 logger.debug("merged account=" + account.toString());
152             }
153             em.getTransaction().commit();
154             handler.complete(Action.UPDATE, wrapDoc);
155         } catch (BadRequestException bre) {
156             if (em != null && em.getTransaction().isActive()) {
157                 em.getTransaction().rollback();
158             }
159             throw bre;
160         } catch (DocumentException de) {
161             if (em != null && em.getTransaction().isActive()) {
162                 em.getTransaction().rollback();
163             }
164             throw de;
165         } catch (Exception e) {
166             if (logger.isDebugEnabled()) {
167                 logger.debug("Caught exception ", e);
168             }
169             throw new DocumentException(e);
170         } finally {
171             if (emf != null) {
172                 JpaStorageUtils.releaseEntityManagerFactory(emf);
173             }
174         }
175     }
176
177     @Override
178     public void delete(ServiceContext ctx, String id)
179             throws DocumentNotFoundException,
180             DocumentException {
181
182         if (logger.isDebugEnabled()) {
183             logger.debug("deleting entity with id=" + id);
184         }
185         if (ctx == null) {
186             throw new IllegalArgumentException(
187                     "AccountStorageClient.delete : ctx is missing");
188         }
189         EntityManagerFactory emf = null;
190         EntityManager em = null;
191         try {
192             emf = JpaStorageUtils.getEntityManagerFactory();
193             em = emf.createEntityManager();
194             //TODO investigate if deep delete is possible
195             //query an delete is inefficient
196             AccountsCommon accountFound = getAccount(em, id);
197
198             //TODO: add tenant id
199
200             //if userid gives any indication about the id provider, it should
201             //be used to avoid the following approach
202             Query usrDel = null;
203             User userLocal = getUser(em, accountFound);
204             if (userLocal != null) {
205                 StringBuilder usrDelStr = new StringBuilder("DELETE FROM ");
206                 usrDelStr.append(User.class.getCanonicalName());
207                 usrDelStr.append(" WHERE username = :username");
208                 //TODO: add tenant id
209                 usrDel = em.createQuery(usrDelStr.toString());
210                 usrDel.setParameter("username", accountFound.getUserId());
211             }
212             em.getTransaction().begin();
213
214             if (userLocal != null) {
215                 int usrDelCount = usrDel.executeUpdate();
216                 if (usrDelCount != 1) {
217                     if (em != null && em.getTransaction().isActive()) {
218                         em.getTransaction().rollback();
219                     }
220                     String msg = "could not find user with username=" + accountFound.getUserId();
221                     logger.error(msg);
222                     throw new DocumentNotFoundException(msg);
223                 }
224             }
225             em.remove(accountFound);
226             em.getTransaction().commit();
227
228         } catch (DocumentException de) {
229             if (em != null && em.getTransaction().isActive()) {
230                 em.getTransaction().rollback();
231             }
232             throw de;
233         } catch (Exception e) {
234             if (logger.isDebugEnabled()) {
235                 logger.debug("Caught exception ", e);
236             }
237             if (em != null && em.getTransaction().isActive()) {
238                 em.getTransaction().rollback();
239             }
240             throw new DocumentException(e);
241         } finally {
242             if (emf != null) {
243                 JpaStorageUtils.releaseEntityManagerFactory(emf);
244             }
245         }
246     }
247
248     private AccountsCommon getAccount(EntityManager em, String id) throws DocumentNotFoundException {
249         AccountsCommon accountFound = em.find(AccountsCommon.class, id);
250         if (accountFound == null) {
251             if (em != null && em.getTransaction().isActive()) {
252                 em.getTransaction().rollback();
253             }
254             String msg = "could not find account with id=" + id;
255             logger.error(msg);
256             throw new DocumentNotFoundException(msg);
257         }
258         return accountFound;
259     }
260
261     private boolean checkAllowedUpdates(AccountsCommon toAccount, AccountsCommon fromAccount) throws BadRequestException {
262         if (!fromAccount.getUserId().equals(toAccount.getUserId())) {
263             String msg = "User id " + toAccount.getUserId() + " does not match "
264                     + "for given account with csid=" + fromAccount.getCsid();
265             logger.error(msg);
266             logger.debug(msg + " found userid=" + fromAccount.getUserId());
267             throw new BadRequestException(msg);
268         }
269         return true;
270     }
271
272     private User createUser(AccountsCommon account) throws Exception {
273         User user = new User();
274         user.setUsername(account.getUserId());
275         if (hasPassword(account.getPassword())) {
276             user.setPasswd(getEncPassword(account));
277         }
278         user.setCreatedAtItem(new Date());
279         return user;
280     }
281
282     private User getUser(EntityManager em, AccountsCommon account) throws DocumentNotFoundException {
283         User userFound = em.find(User.class, account.getUserId());
284         if (userFound == null) {
285             if (em != null && em.getTransaction().isActive()) {
286                 em.getTransaction().rollback();
287             }
288             String msg = "could not find user with id=" + account.getUserId();
289             logger.error(msg);
290             throw new DocumentNotFoundException(msg);
291         }
292         return userFound;
293     }
294
295     private void updateUser(EntityManager em, AccountsCommon account) throws Exception {
296         User userFound = getUser(em, account);
297         if (userFound != null) {
298             userFound.setPasswd(getEncPassword(account));
299             userFound.setUpdatedAtItem(new Date());
300             if (logger.isDebugEnabled()) {
301                 logger.debug("updated user=" + userFound.toString());
302             }
303             em.persist(userFound);
304         }
305     }
306
307     private String getEncPassword(AccountsCommon account) throws BadRequestException {
308         //jaxb unmarshaller already unmarshal xs:base64Binary, no need to b64 decode
309         //byte[] bpass = Base64.decodeBase64(account.getPassword());
310         try {
311             SecurityUtils.validatePassword(new String(account.getPassword()));
312         } catch (Exception e) {
313             throw new BadRequestException(e.getMessage());
314         }
315         String secEncPasswd = SecurityUtils.createPasswordHash(
316                 account.getUserId(), new String(account.getPassword()));
317         return secEncPasswd;
318     }
319
320     private boolean hasPassword(byte[] bpass) {
321         return bpass != null && bpass.length > 0;
322     }
323 //    private UserTenant createTenantAssoc(AccountsCommon account) {
324 //        UserTenant userTenant = new UserTenant();
325 //        userTenant.setUserId(account.getUserId());
326 //        List<AccountsCommon.Tenant> atl = account.getTenant();
327 //        List<UserTenant.Tenant> utl =
328 //                new ArrayList<UserTenant.Tenant>();
329 //        for (AccountsCommon.Tenant at : atl) {
330 //            UserTenant.Tenant ut = new UserTenant.Tenant();
331 //            ut.setId(at.getId());
332 //            ut.setName(at.getName());
333 //            utl.add(ut);
334 //        }
335 //        userTenant.setTenant(utl);
336 //        return userTenant;
337 //    }
338 }