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.account.storage;
26 import javax.persistence.EntityManager;
27 import javax.persistence.EntityManagerFactory;
28 import javax.persistence.NoResultException;
29 import javax.persistence.Query;
30 import org.apache.commons.codec.binary.Base64;
31 import org.collectionspace.services.account.AccountsCommon;
32 import org.collectionspace.services.authentication.User;
33 import org.collectionspace.services.common.context.ServiceContext;
34 import org.collectionspace.services.common.document.BadRequestException;
35 import org.collectionspace.services.common.document.DocumentException;
36 import org.collectionspace.services.common.document.DocumentFilter;
37 import org.collectionspace.services.common.document.DocumentHandler;
38 import org.collectionspace.services.common.document.DocumentHandler.Action;
39 import org.collectionspace.services.common.document.DocumentNotFoundException;
40 import org.collectionspace.services.common.document.DocumentWrapper;
41 import org.collectionspace.services.common.document.DocumentWrapperImpl;
42 import org.collectionspace.services.common.security.SecurityUtils;
43 import org.collectionspace.services.common.storage.jpa.JpaStorageClient;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
48 * AccountStorageClient deals with both Account and Default Identity Provider's
49 * state in persistent storage
52 public class AccountStorageClient extends JpaStorageClient {
54 private final Logger logger = LoggerFactory.getLogger(AccountStorageClient.class);
56 public AccountStorageClient() {
60 public String create(ServiceContext ctx,
61 DocumentHandler handler) throws BadRequestException,
64 String docType = ctx.getDocumentType();
65 if (docType == null) {
66 throw new DocumentNotFoundException(
67 "Unable to find DocumentType for service " + ctx.getServiceName());
69 if (handler == null) {
70 throw new IllegalArgumentException(
71 "AccountStorageClient.create: handler is missing");
73 EntityManagerFactory emf = null;
74 EntityManager em = null;
76 handler.prepare(Action.CREATE);
77 AccountsCommon account = (AccountsCommon) handler.getCommonPart();
78 DocumentWrapper<AccountsCommon> wrapDoc =
79 new DocumentWrapperImpl<AccountsCommon>(account);
80 handler.handle(Action.CREATE, wrapDoc);
81 emf = getEntityManagerFactory();
82 em = emf.createEntityManager();
83 em.getTransaction().begin();
84 //if userid and password are given, add to default id provider
85 if (account.getUserId() != null && account.getPassword() != null) {
86 User user = createUser(account, ctx.getTenantId());
89 account.setTenantid(ctx.getTenantId());
91 em.getTransaction().commit();
92 handler.complete(Action.CREATE, wrapDoc);
93 return (String) getValue(account, "getCsid");
94 } catch (Exception e) {
95 if (em != null && em.getTransaction().isActive()) {
96 em.getTransaction().rollback();
98 if (logger.isDebugEnabled()) {
99 logger.debug("Caught exception ", e);
101 throw new DocumentException(e);
104 releaseEntityManagerFactory(emf);
110 public void update(ServiceContext ctx, String id, DocumentHandler handler)
111 throws BadRequestException, DocumentNotFoundException,
113 String docType = ctx.getDocumentType();
114 if (docType == null) {
115 throw new DocumentNotFoundException(
116 "Unable to find DocumentType for service " + ctx.getServiceName());
118 if (handler == null) {
119 throw new IllegalArgumentException(
120 "AccountStorageClient.update: handler is missing");
122 EntityManagerFactory emf = null;
123 EntityManager em = null;
125 handler.prepare(Action.UPDATE);
126 AccountsCommon account = (AccountsCommon) handler.getCommonPart();
127 DocumentWrapper<AccountsCommon> wrapDoc =
128 new DocumentWrapperImpl<AccountsCommon>(account);
129 setCsid(account, id); //set id just in case it was not populated by consumer
130 handler.handle(Action.UPDATE, wrapDoc);
131 emf = getEntityManagerFactory();
132 em = emf.createEntityManager();
133 em.getTransaction().begin();
134 AccountsCommon accountFound = getAccount(em, id);
136 checkAllowedUpdates(account, accountFound);
137 //if userid and password are given, add to default id provider
138 if (account.getUserId() != null && account.getPassword() != null) {
140 User userFound = getUser(em, account);
141 User user = createUser(account, ctx.getTenantId());
145 em.getTransaction().commit();
146 handler.complete(Action.UPDATE, wrapDoc);
147 } catch (BadRequestException bre) {
149 } catch (DocumentException de) {
151 } catch (Exception e) {
152 if (logger.isDebugEnabled()) {
153 logger.debug("Caught exception ", e);
155 throw new DocumentException(e);
158 releaseEntityManagerFactory(emf);
164 public void delete(ServiceContext ctx, String id)
165 throws DocumentNotFoundException,
168 if (logger.isDebugEnabled()) {
169 logger.debug("deleting entity with id=" + id);
171 String docType = ctx.getDocumentType();
172 if (docType == null) {
173 throw new DocumentNotFoundException(
174 "Unable to find DocumentType for service " + ctx.getServiceName());
176 EntityManagerFactory emf = null;
177 EntityManager em = null;
179 emf = getEntityManagerFactory();
180 em = emf.createEntityManager();
181 //TODO investigate if deep delete is possible
182 //query an delete is inefficient
183 AccountsCommon accountFound = getAccount(em, id);
185 StringBuilder accDelStr = new StringBuilder("DELETE FROM ");
186 accDelStr.append(getEntityName(ctx));
187 accDelStr.append(" WHERE csid = :csid");
188 //TODO: add tenant id
189 Query accDel = em.createQuery(accDelStr.toString());
190 accDel.setParameter("csid", id);
191 //TODO: add tenant id
193 //if userid gives any indication about the id provider, it should
194 //be used to avoid the following approach
195 User userLocal = em.find(User.class, accountFound.getUserId());
197 if (userLocal != null) {
198 StringBuilder usrDelStr = new StringBuilder("DELETE FROM ");
199 usrDelStr.append(User.class.getCanonicalName());
200 usrDelStr.append(" WHERE username = :username");
201 //TODO: add tenant id
202 usrDel = em.createQuery(usrDelStr.toString());
203 usrDel.setParameter("username", accountFound.getUserId());
205 em.getTransaction().begin();
206 int accDelCount = accDel.executeUpdate();
207 if (accDelCount != 1) {
208 if (em != null && em.getTransaction().isActive()) {
209 em.getTransaction().rollback();
212 if (userLocal != null) {
213 int usrDelCount = usrDel.executeUpdate();
214 if (usrDelCount != 1) {
215 if (em != null && em.getTransaction().isActive()) {
216 em.getTransaction().rollback();
219 if (usrDelCount != 1) {
220 String msg = "could not find user with username=" + accountFound.getUserId();
222 throw new DocumentNotFoundException(msg);
225 em.getTransaction().commit();
227 } catch (DocumentException de) {
229 } catch (Exception e) {
230 if (logger.isDebugEnabled()) {
231 logger.debug("Caught exception ", e);
233 if (em != null && em.getTransaction().isActive()) {
234 em.getTransaction().rollback();
236 throw new DocumentException(e);
239 releaseEntityManagerFactory(emf);
244 private AccountsCommon getAccount(EntityManager em, String id) throws DocumentNotFoundException {
245 AccountsCommon accountFound = em.find(AccountsCommon.class, id);
246 if (accountFound == null) {
247 if (em != null && em.getTransaction().isActive()) {
248 em.getTransaction().rollback();
250 String msg = "could not find account with id=" + id;
252 throw new DocumentNotFoundException(msg);
257 private boolean checkAllowedUpdates(AccountsCommon toAccount, AccountsCommon fromAccount) throws BadRequestException {
258 if (!fromAccount.getUserId().equals(toAccount.getUserId())) {
259 String msg = "User id " + toAccount.getUserId() + " not found!";
261 logger.debug(msg + " found userid=" + fromAccount.getUserId());
262 throw new BadRequestException(msg);
267 private User createUser(AccountsCommon account, String tenantId) {
268 User user = new User();
269 user.setTenantid(tenantId);
270 user.setUsername(account.getUserId());
271 byte[] bpass = Base64.decodeBase64(account.getPassword());
272 SecurityUtils.validatePassword(new String(bpass));
273 String secEncPasswd = SecurityUtils.createPasswordHash(
274 account.getUserId(), new String(bpass));
275 user.setPasswd(secEncPasswd);
279 private User getUser(EntityManager em, AccountsCommon account) throws DocumentNotFoundException {
280 User userFound = em.find(User.class, account.getUserId());
281 if (userFound == null) {
282 if (em != null && em.getTransaction().isActive()) {
283 em.getTransaction().rollback();
285 String msg = "could not find user with id=" + account.getUserId();
287 throw new DocumentNotFoundException(msg);