Project

General

Profile

1 5091 daigle
/**
2
 *  '$RCSfile$'
3 5098 daigle
 *    Purpose: A Class that manages database access of xml access
4 5091 daigle
 *             information.
5
 *  Copyright: 2009 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Michael Daigle
8
 *
9
 *   '$Author: daigle $'
10
 *     '$Date: 2009-03-23 13:56:56 -0800 (Mon, 23 Mar 2009) $'
11
 * '$Revision: 4854 $'
12
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 */
27
28
package edu.ucsb.nceas.metacat.accesscontrol;
29
30
import java.sql.PreparedStatement;
31
import java.sql.ResultSet;
32
import java.sql.SQLException;
33 6108 leinfelder
import java.util.List;
34 5091 daigle
import java.util.Vector;
35
36
import org.apache.log4j.Logger;
37
38 6422 leinfelder
import edu.ucsb.nceas.metacat.AccessionNumber;
39 6527 jones
import edu.ucsb.nceas.metacat.AccessionNumberException;
40 6422 leinfelder
import edu.ucsb.nceas.metacat.DBUtil;
41
import edu.ucsb.nceas.metacat.IdentifierManager;
42
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
43 5091 daigle
import edu.ucsb.nceas.metacat.database.DBConnection;
44
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
45
import edu.ucsb.nceas.metacat.shared.AccessException;
46
import edu.ucsb.nceas.metacat.shared.BaseAccess;
47
48
public class XMLAccessAccess extends BaseAccess {
49
50
	private Logger logMetacat = Logger.getLogger(XMLAccessAccess.class);
51
52 6122 leinfelder
	private static String DOCID = "docid";
53
54
	private static String GUID = "guid";
55
56
	private String idAttribute = DOCID;
57
58 5091 daigle
	// Constructor
59 5108 daigle
	public XMLAccessAccess() throws AccessException {}
60 5091 daigle
61 6122 leinfelder
	public XMLAccessAccess(boolean useGuid) {
62
		if (useGuid) {
63
			idAttribute = GUID;
64
		}
65
	}
66
67 5091 daigle
	/**
68
	 * Get all xml access for a document
69
	 *
70 6122 leinfelder
	 * @param id
71 5091 daigle
	 *            the id of the document
72
	 * @return an xml access DAO list
73
	 */
74 6122 leinfelder
	public Vector<XMLAccessDAO> getXMLAccessForDoc(String id) throws AccessException {
75 5091 daigle
76
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
77
78 6122 leinfelder
		if (id == null) {
79 5091 daigle
			throw new AccessException("XMLAccessAccess.getXMLAccessForDoc - doc id " +
80
					"must be specified when selecting xml_access record");
81
		}
82
83 5115 daigle
		// first get the xml access from the db and put it into a DAO list
84 5091 daigle
		PreparedStatement pstmt = null;
85 5108 daigle
		DBConnection conn = null;
86
		int serialNumber = -1;
87
		try {
88
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForDoc");
89
    		serialNumber = conn.getCheckOutSerialNumber();
90
91 6122 leinfelder
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ?";
92 5091 daigle
			pstmt = conn.prepareStatement(sql);
93
94 6122 leinfelder
			pstmt.setString(1, id);
95 5091 daigle
96
			String sqlReport = "XMLAccessAccess.getXMLAccessForDoc - SQL: " + sql;
97 6122 leinfelder
			sqlReport += " [" + id + "]";
98 5091 daigle
99
			logMetacat.info(sqlReport);
100
101
			pstmt.execute();
102
103
			ResultSet resultSet = pstmt.getResultSet();
104
			while (resultSet.next()) {
105
				XMLAccessDAO xmlAccessDAO = populateDAO(resultSet);
106
				xmlAccessList.add(xmlAccessDAO);
107
			}
108 5115 daigle
109
			// make sure permission orders do not conflict in the database
110 5091 daigle
			validateDocXMLAccessList(xmlAccessList);
111
112
			return xmlAccessList;
113
114
		} catch (SQLException sqle) {
115
			throw new AccessException("XMLAccessAccess.getXMLAccessForDoc - SQL error when getting access " +
116 6122 leinfelder
					" for id: " + id  + " : "  + sqle.getMessage());
117 5091 daigle
		} catch (PermOrderException poe) {
118
			String errorStr = "XMLAccessAccess.getXMLAccessForDoc - Permission order error when getting " +
119 6122 leinfelder
				"access record for doc id: " + id + " : "  + poe.getMessage();
120 5091 daigle
			logMetacat.error(errorStr);
121
			throw new AccessException(errorStr);
122
		} finally {
123 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
124 5091 daigle
		}
125
	}
126
127
	/**
128
	 * Get all xml access for a principal for a certain document
129
	 *
130 6122 leinfelder
	 * @param id
131 5091 daigle
	 *            the id of the document
132
	 * @param principalName
133
	 *            the credentials of the principal in the database
134
	 * @return an xml access DAO list
135
	 */
136 6122 leinfelder
	public Vector<XMLAccessDAO> getXMLAccessForPrincipal(String id, String principalName)
137 5091 daigle
			throws AccessException {
138
139
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
140
141 6122 leinfelder
		if (id == null) {
142 5091 daigle
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - doc id " +
143
					"must be specified when selecting xml_access record");
144
		}
145
		if (principalName == null) {
146
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - doc id " +
147
					"must be specified when selecting xml_access record");
148
		}
149
150 5115 daigle
		// first get the xml access for this principal from the db and put it into a DAO list
151 5091 daigle
		PreparedStatement pstmt = null;
152 5108 daigle
		DBConnection conn = null;
153
		int serialNumber = -1;
154 5091 daigle
		try {
155 5108 daigle
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForPrincipal");
156
    		serialNumber = conn.getCheckOutSerialNumber();
157
158 6122 leinfelder
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ?";
159 5091 daigle
			pstmt = conn.prepareStatement(sql);
160
161 6122 leinfelder
			pstmt.setString(1, id);
162 5091 daigle
			pstmt.setString(2, principalName);
163
164
			String sqlReport = "XMLAccessAccess.getXMLAccessForPrincipal - SQL: " + sql;
165 6122 leinfelder
			sqlReport += " [" + id + "," + principalName + "]";
166 5091 daigle
167
			logMetacat.info(sqlReport);
168
169
			pstmt.execute();
170
171
			ResultSet resultSet = pstmt.getResultSet();
172
			while (resultSet.next()) {
173
				XMLAccessDAO xmlAccessDAO = populateDAO(resultSet);
174
				xmlAccessList.add(xmlAccessDAO);
175
			}
176
177 5115 daigle
			// make sure permission orders do not conflict in the database
178 5091 daigle
			validatePrincipalXMLAccessList(xmlAccessList);
179
180
			return xmlAccessList;
181
182
		} catch (SQLException sqle) {
183
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - SQL error when getting access " +
184 6122 leinfelder
					" for id: " + id + ", principal: " + principalName  + " : "  + sqle.getMessage());
185 5091 daigle
		} catch (PermOrderException poe) {
186
			String errorStr = "XMLAccessAccess.getXMLAccessForPrincipal - Permission order error when getting " +
187 6122 leinfelder
				"access record for id: " + id + ", principal: " + principalName + " : "  + poe.getMessage();
188 5091 daigle
			logMetacat.error(errorStr);
189
			throw new AccessException(errorStr);
190
		} finally {
191 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
192 5091 daigle
		}
193
	}
194
195
	/**
196 5115 daigle
	 * Get all xml access for a principal/permType/permOrder for a certain document
197 5091 daigle
	 *
198 6122 leinfelder
	 * @param id
199 5091 daigle
	 *            the id of the document
200
	 * @param principalName
201
	 *            the credentials of the principal in the database
202
	 * @return an xml access DAO list
203
	 */
204 6122 leinfelder
	public Vector<XMLAccessDAO> getXMLAccessForPrincipal(String id, String principalName, String permType, String permOrder)
205 5091 daigle
			throws AccessException {
206
207
		Vector<XMLAccessDAO> xmlAccessList = new Vector<XMLAccessDAO>();
208
209 6122 leinfelder
		if (id == null) {
210 5091 daigle
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - doc id " +
211
					"must be specified when selecting xml_access record");
212
		}
213
		if (principalName == null) {
214
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - doc id " +
215
					"must be specified when selecting xml_access record");
216
		}
217
		if (permType == null) {
218
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - permission type " +
219
					"must be specified when selecting xml_access record");
220
		}
221
		if (permOrder == null) {
222
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - permission order " +
223
					"must be specified when selecting xml_access record");
224
		}
225
226 5115 daigle
		// first get the xml access for this principal from the db and put it into a DAO list
227 5091 daigle
		PreparedStatement pstmt = null;
228 5108 daigle
		DBConnection conn = null;
229
		int serialNumber = -1;
230 5091 daigle
		try {
231 5108 daigle
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.getXMLAccessForPrincipal");
232
    		serialNumber = conn.getCheckOutSerialNumber();
233
234 6122 leinfelder
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ? " +
235 5091 daigle
				"AND perm_type = ? AND perm_order = ?";
236
			pstmt = conn.prepareStatement(sql);
237
238 6122 leinfelder
			pstmt.setString(1, id);
239 5091 daigle
			pstmt.setString(2, principalName);
240
			pstmt.setString(3, permType);
241
			pstmt.setString(4, permOrder);
242
243
			String sqlReport = "XMLAccessAccess.getXMLAccessForPrincipal - SQL: " + sql;
244 6122 leinfelder
			sqlReport += " [" + id + "," + principalName + "," +  permType + "," + permOrder + "]";
245 5091 daigle
246
			logMetacat.info(sqlReport);
247
248
			pstmt.execute();
249
250
			ResultSet resultSet = pstmt.getResultSet();
251
			while (resultSet.next()) {
252
				XMLAccessDAO xmlAccessDAO = populateDAO(resultSet);
253
				xmlAccessList.add(xmlAccessDAO);
254
			}
255
256
			validatePrincipalXMLAccessList(xmlAccessList);
257
258
			return xmlAccessList;
259
260
		} catch (SQLException sqle) {
261
			throw new AccessException("XMLAccessAccess.getXMLAccessForPrincipal - SQL error when getting access " +
262 6122 leinfelder
					" for id: " + id + ", principal: " + principalName  + " : "  + sqle.getMessage());
263 5091 daigle
		} catch (PermOrderException poe) {
264
			String errorStr = "XMLAccessAccess.getXMLAccessForPrincipal - Permission order error when getting " +
265 6122 leinfelder
				"access record for id: " + id + ", principal: " + principalName + " : "  + poe.getMessage();
266 5091 daigle
			logMetacat.error(errorStr);
267
			throw new AccessException(errorStr);
268
		} finally {
269 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
270 5091 daigle
		}
271
	}
272
273
	/**
274 5098 daigle
	 * Add permissions for a given principal on a given document. If the
275
	 * principal already exists, bitwise OR the permission to the existing
276 5091 daigle
	 * permission and update.
277
	 *
278 6122 leinfelder
	 * @param id
279 5091 daigle
	 *            document id
280
	 * @param principalName
281
	 *            principal credentials
282
	 * @param permission
283
	 *            permission bitmap
284
	 * @param permType
285
	 *            permission type
286
	 * @param permOrder
287
	 *            permission order
288
	 */
289 6122 leinfelder
	public void addXMLAccess(String id, String principalName, Long permission, String permType,
290 6017 leinfelder
			String permOrder, String accessFileId, String subTreeId) throws AccessException, PermOrderException {
291 5108 daigle
292 6122 leinfelder
		permOrderConflict(id, permOrder);
293 5108 daigle
294 5091 daigle
		Vector<XMLAccessDAO> xmlAccessList =
295 6122 leinfelder
			getXMLAccessForPrincipal(id, principalName, permType, permOrder);
296 5091 daigle
297
		// if more than one record exists for this principal on this document with the same
298
		// access type / access order combination, call cleanup to combine common access and then
299
		// re-retrieve the access list.
300
		if (xmlAccessList.size() == 0) {
301 6122 leinfelder
			insertXMLAccess(id, principalName, permission, permType, permOrder, accessFileId, subTreeId);
302 5091 daigle
			return;
303
		}
304
305
		if (xmlAccessList.size() > 1) {
306
			cleanupXMLAccessForPrincipal(xmlAccessList);
307 6122 leinfelder
			xmlAccessList = getXMLAccessForPrincipal(id, principalName, permType, permOrder);
308 5091 daigle
		}
309
310
		if (xmlAccessList.size() == 0) {
311
			throw new AccessException("XMLAccessAccess.addXMLAccess - xml access list is empty when " +
312 6122 leinfelder
				"it shouldn't be for id: " + id + ", prinicpal name: " + principalName + ", perm type " +
313 5091 daigle
				permType + ", perm order: " + permOrder);
314
		}
315
316
		XMLAccessDAO xmlAccessDAO = xmlAccessList.get(0);
317 5108 daigle
318 5091 daigle
		// if the permission on the xml access dao does not already contain the permission we are
319
		//trying to add, update the access record with the existing permission bitwis OR-ed with our
320
		// new permission
321
		if ((xmlAccessDAO.getPermission() & permission) != permission) {
322 6122 leinfelder
			updateXMLAccessPermission(id, principalName, xmlAccessDAO.getPermission() | permission);
323 5091 daigle
		}
324
	}
325
326
	/**
327 5098 daigle
	 * Set permissions for a given document. This means first removing all access control for the
328
	 * document and then adding the given rules.
329
	 *
330 6122 leinfelder
	 * @param id
331 5091 daigle
	 *            document id
332 5098 daigle
	 * @param xmlAccessList
333
	 *            list of xml access dao objects that hold new access for the document
334
	 */
335 6122 leinfelder
	public void replaceAccess(String id, List<XMLAccessDAO> xmlAccessList) throws AccessException {
336
		deleteXMLAccessForDoc(id);
337 5098 daigle
338
		// if more than one record exists for this principal on this document with the same
339
		// access type / access order combination, call cleanup to combine common access and then
340
		// re-retrieve the access list.
341
		for(XMLAccessDAO xmlAccessDAO : xmlAccessList) {
342 6122 leinfelder
			insertXMLAccess(id, xmlAccessDAO.getPrincipalName(), xmlAccessDAO.getPermission(),
343 6017 leinfelder
					xmlAccessDAO.getPermType(), xmlAccessDAO.getPermOrder(), xmlAccessDAO.getAccessFileId(), xmlAccessDAO.getSubTreeId());
344 5098 daigle
		}
345
	}
346
347
	/**
348
	 * Insert an xml access record.  It is assumed that the checks have already been made to
349
	 * make sure the principal does not already have an access record for this document.  If
350
	 * one does already exist, that record should be updated and this insert not called.
351
	 *
352 6122 leinfelder
	 * @param id
353 5098 daigle
	 *            document id
354 5091 daigle
	 * @param principal
355
	 *            principal credentials
356
	 * @param permission
357
	 *            permission bitmap
358
	 * @param permType
359
	 *            permission type
360
	 * @param permOrder
361
	 *            permission order
362
	 */
363 6122 leinfelder
	private void insertXMLAccess(String id, String principalName, Long permission, String permType,
364 6017 leinfelder
			String permOrder, String accessFileId, String subTreeId) throws AccessException {
365 5734 berkley
	    //System.out.println("permission in insertXMLAccess: " + permission);
366
	    try
367
	    {
368
	        if(permission == -1)
369
	        {
370
	            throw new Exception("Permission is -1 in XMLAccessAccess.insertXMLAccess().");
371
	        }
372
	    }
373
	    catch(Exception e)
374
	    {
375
	        e.printStackTrace();
376
	        logMetacat.warn(e.getMessage());
377
	    }
378
379 6122 leinfelder
		if (id == null) {
380
			throw new AccessException("XMLAccessAccess.insertXMLAccess - id is required when " +
381 5091 daigle
					"inserting XML access record");
382
		}
383
		if (principalName == null) {
384
			throw new AccessException("XMLAccessAccess.insertXMLAccess - principal is required when " +
385
					"inserting XML access record");
386
		}
387
		if (permission == null) {
388
			throw new AccessException("XMLAccessAccess.insertXMLAccess - permission is required when " +
389
					"inserting XML access record");
390
		}
391
		if (permType == null) {
392
			throw new AccessException("XMLAccessAccess.insertXMLAccess - permType is required when " +
393
					"inserting XML access record");
394
		}
395
		if (permOrder == null) {
396
			permOrder = AccessControlInterface.ALLOWFIRST;
397
		}
398
399
	    PreparedStatement pstmt = null;
400
		DBConnection conn = null;
401
		int serialNumber = -1;
402
		try {
403
			// check out DBConnection
404
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.insertXMLAccess");
405
			serialNumber = conn.getCheckOutSerialNumber();
406 5120 daigle
407 5091 daigle
			String sql = "INSERT INTO xml_access " +
408 6422 leinfelder
				"(docid, guid, principal_name, permission, perm_type, perm_order, accessfileid, subtreeid ) " +
409
				"VALUES (?,?,?,?,?,?,?,?)";
410 5091 daigle
			pstmt = conn.prepareStatement(sql);
411
412 6422 leinfelder
			String guid = null;
413
			String docid = null;
414
			if (idAttribute.equals(GUID)) {
415
				guid = id;
416
				try {
417 6527 jones
					String localId = IdentifierManager.getInstance().getLocalId(id);
418
					// Parse the localId into scope and rev parts, strip off the rev
419
		            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
420
		            docid = acc.getDocid();
421 6422 leinfelder
				} catch (McdbDocNotFoundException e) {
422
					//ignore
423
					logMetacat.warn("No local id mapping found for guid: " + id);
424 6527 jones
				} catch (NumberFormatException e) {
425
                    logMetacat.warn("LocalId could not be parsed for guid: " + id);
426
                } catch (AccessionNumberException e) {
427
                    logMetacat.warn("LocalId could not be parsed for guid: " + id);
428
                }
429 6422 leinfelder
			} else {
430
				int rev = DBUtil.getLatestRevisionInDocumentTable(id);
431
				try {
432
					guid = IdentifierManager.getInstance().getGUID(id, rev);
433
				} catch (McdbDocNotFoundException e) {
434
					//ignore
435
					logMetacat.warn("No guid mapping found for docid: " + id + "." + rev);
436
				}
437
				docid = id;
438
			}
439
440 5091 daigle
			// Bind the values to the query
441 6422 leinfelder
			pstmt.setString(1, docid);
442
			pstmt.setString(2, guid);
443
			pstmt.setString(3, principalName);
444
			pstmt.setLong(4, permission);
445
			pstmt.setString(5, permType);
446
			pstmt.setString(6, permOrder);
447
			pstmt.setString(7, accessFileId);
448
			pstmt.setString(8, subTreeId);
449 5091 daigle
450
			String sqlReport = "XMLAccessAccess.insertXMLAccess - SQL: " + sql;
451 6422 leinfelder
			sqlReport += " [" + docid + "," + guid + "," + principalName + "," +  permission + "," +  permType + "," + permOrder + "]";
452 5091 daigle
453
			logMetacat.info(sqlReport);
454
455
			pstmt.execute();
456
		} catch (SQLException sqle) {
457
			throw new AccessException("XMLAccessAccess.insertXMLAccess - SQL error when inserting"
458 6122 leinfelder
					+ "xml access permissions for id: " + id + ", principal: " +
459 5091 daigle
					principalName + ":" + sqle.getMessage());
460
		} finally {
461 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
462 5091 daigle
		}
463
	}
464
465
	/**
466 5098 daigle
	 * Update existing xml access permissions in the db.  The permission value should be the combined
467
	 * value of pre-existing permissions plus new permissions.
468
	 *
469 6122 leinfelder
	 * @param id
470 5091 daigle
	 *            document id
471
	 * @param principalName
472
	 *            principal credentials
473
	 * @param permission
474
	 *            permission bitmap
475
	 */
476 6122 leinfelder
	private void updateXMLAccessPermission(String id, String principalName, Long permission)
477 5091 daigle
			throws AccessException {
478 6122 leinfelder
		if (id == null) {
479
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - id is required when " +
480 5091 daigle
					"updating XML access record");
481
		}
482
		if (principalName == null) {
483
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - principal is required when " +
484
					"updating XML access record");
485
		}
486
		if (permission == null) {
487
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - permission is required when " +
488
					"updating XML access record");
489
		}
490
491
	    PreparedStatement pstmt = null;
492
		DBConnection conn = null;
493
		int serialNumber = -1;
494
		try {
495
			// check out DBConnection
496
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.updateXMLAccessPermission");
497
			serialNumber = conn.getCheckOutSerialNumber();
498 5120 daigle
499 5091 daigle
			String sql = "UPDATE xml_access SET permission = ?" +
500 6122 leinfelder
				"WHERE " + idAttribute + " = ? AND principal_name = ?";
501 5091 daigle
			pstmt = conn.prepareStatement(sql);
502
503
			// Bind the values to the query
504
			pstmt.setLong(1, permission);
505 6122 leinfelder
			pstmt.setString(2, id);
506 5091 daigle
			pstmt.setString(3, principalName);
507
508
			String sqlReport = "XMLAccessAccess.updateXMLAccessPermission - SQL: " + sql;
509 6122 leinfelder
			sqlReport += " [" + permission + "," + id + "," + principalName + "]";
510 5091 daigle
511
			logMetacat.info(sqlReport);
512
513
			pstmt.execute();
514
		} catch (SQLException sqle) {
515
			throw new AccessException("XMLAccessAccess.updateXMLAccessPermission - SQL error when updating"
516 6122 leinfelder
					+ "xml access permissions for id: " + id + ", principal: " +
517 5091 daigle
					principalName + ":" + sqle.getMessage());
518
		} finally {
519 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
520 5091 daigle
		}
521
522
	}
523
524
	/**
525 5098 daigle
	 * Remove xml access.  This modifies the access in the database for a principal
526 5091 daigle
	 * for a given document.  If the provided permission is exactly the same as what
527 5098 daigle
	 * the principal has, the record is deleted from the database.
528
	 *
529 6122 leinfelder
	 * @param id
530 5091 daigle
	 *            document id
531
	 * @param principalName
532
	 *            principal credentials
533
	 */
534 6122 leinfelder
	public void removeXMLAccessForPrincipal(String id, String principalName, Long permission) throws AccessException {
535
		if (id == null) {
536
			throw new AccessException("XMLAccessAccess.removeXMLAccessForPrincipal - id is required when " +
537 5091 daigle
					"removing XML access");
538
		}
539
		if (principalName == null) {
540
			throw new AccessException("XMLAccessAccess.removeXMLAccessForPrincipal - principal is required when " +
541
					"deleting XML access");
542
		}
543
		if (permission == null) {
544
			throw new AccessException("XMLAccessAccess.removeXMLAccessForPrincipal - permission is required when " +
545
					"updating XML access");
546
		}
547
548 6122 leinfelder
		Vector<XMLAccessDAO> xmlAccessList = getXMLAccessForPrincipal(id, principalName);
549 5091 daigle
		if (xmlAccessList.size() == 0) {
550
			logMetacat.warn("XMLAccessAccess.removeXMLAccessForPrincipal - attempting to remove access when no " +
551 6122 leinfelder
				"access record exists for id: " + id + ", principal: " + principalName);
552 5091 daigle
		} else {
553
			long permissionMask = 0;
554
			for (XMLAccessDAO xmlAccessDAO : xmlAccessList) {
555
				permissionMask |= xmlAccessDAO.getPermission();
556
			}
557
			permissionMask |= permission;
558
559
			// in this case, the only existing permissions are the ones we want to remove, so
560
			// delete the record(s) for this principal on this document
561
			if ((permissionMask & permission) == permission) {
562 6122 leinfelder
				deleteXMLAccessForPrincipal(id, principalName);
563 5091 daigle
			}
564
565
			if (xmlAccessList.size() > 1) {
566
567
			} else {
568 6122 leinfelder
				updateXMLAccessPermission(id, principalName, permission);
569 5091 daigle
			}
570
		}
571
572
	}
573
574
	/**
575 5098 daigle
	 * Delete xml access.  This removes all access records from the database for a given document
576
	 *
577 6122 leinfelder
	 * @param id
578 5098 daigle
	 *            document id
579
	 */
580 6122 leinfelder
	public void deleteXMLAccessForDoc(String id) throws AccessException {
581
		if (id == null) {
582
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " +
583 5098 daigle
					"deleting XML access record");
584
		}
585
586
	    PreparedStatement pstmt = null;
587
		DBConnection conn = null;
588
		int serialNumber = -1;
589
		try {
590 6536 leinfelder
591
			String guid = null;
592
			String docid = null;
593
			if (idAttribute.equals(GUID)) {
594
				guid = id;
595
				try {
596
					String localId = IdentifierManager.getInstance().getLocalId(id);
597
					// Parse the localId into scope and rev parts, strip off the rev
598
		            AccessionNumber acc = new AccessionNumber(localId, "NOACTION");
599
		            docid = acc.getDocid();
600
				} catch (McdbDocNotFoundException e) {
601
					//ignore
602
					logMetacat.warn("No local id mapping found for guid: " + id);
603
				} catch (NumberFormatException e) {
604
                    logMetacat.warn("LocalId could not be parsed for guid: " + id);
605
                } catch (AccessionNumberException e) {
606
                    logMetacat.warn("LocalId could not be parsed for guid: " + id);
607
                }
608
			} else {
609
				int rev = DBUtil.getLatestRevisionInDocumentTable(id);
610
				try {
611
					guid = IdentifierManager.getInstance().getGUID(id, rev);
612
				} catch (McdbDocNotFoundException e) {
613
					//ignore
614
					logMetacat.warn("No guid mapping found for docid: " + id + "." + rev);
615
				}
616
				docid = id;
617
			}
618
619 5098 daigle
			// check out DBConnection
620
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.deleteXMLAccessForDoc");
621 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
622
623 6536 leinfelder
			String sql = "DELETE FROM xml_access WHERE docid = ? OR guid = ?";
624 5098 daigle
			pstmt = conn.prepareStatement(sql);
625
626
			// Bind the values to the query
627 6536 leinfelder
			pstmt.setString(1, docid);
628
			pstmt.setString(2, guid);
629 5098 daigle
630 6536 leinfelder
631 5098 daigle
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForDoc - SQL: " + sql;
632 6122 leinfelder
			sqlReport += " [" + id + "]";
633 5098 daigle
634
			logMetacat.info(sqlReport);
635
636
			pstmt.execute();
637
		} catch (SQLException sqle) {
638
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForDoc - SQL error when deleting"
639 6122 leinfelder
					+ "xml access permissions for id: " + id + ":" + sqle.getMessage());
640 5098 daigle
		} finally {
641 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
642 5098 daigle
		}
643
	}
644
645
	/**
646 5091 daigle
	 * Delete xml access.  This removes all access records from the database for a principal
647
	 * for a given document
648 5098 daigle
	 *
649 6122 leinfelder
	 * @param id
650 5091 daigle
	 *            document id
651
	 * @param principal
652
	 *            principal credentials
653
	 */
654 6122 leinfelder
	private void deleteXMLAccessForPrincipal(String id, String principalName) throws AccessException {
655
		if (id == null) {
656
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " +
657 5091 daigle
					"deleting XML access record");
658
		}
659
		if (principalName == null) {
660
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - principal is required when " +
661
					"deleting XML access record");
662
		}
663
664
	    PreparedStatement pstmt = null;
665
		DBConnection conn = null;
666
		int serialNumber = -1;
667
		try {
668
			// check out DBConnection
669
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.deleteXMLAccessForPrincipal");
670 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
671
672 6122 leinfelder
			String sql = "DELETE FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ?";
673 5091 daigle
			pstmt = conn.prepareStatement(sql);
674
675
			// Bind the values to the query
676 6122 leinfelder
			pstmt.setString(1, id);
677 5091 daigle
			pstmt.setString(2, principalName);
678
679
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
680 6122 leinfelder
			sqlReport += " [" + id + "," + principalName + "]";
681 5091 daigle
682
			logMetacat.info(sqlReport);
683
684
			pstmt.execute();
685
		} catch (SQLException sqle) {
686
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - SQL error when deleting"
687 6122 leinfelder
					+ "xml access permissions for id: " + id + ", principal: " +
688 5091 daigle
					principalName + ":" + sqle.getMessage());
689
		} finally {
690 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
691 5091 daigle
		}
692
	}
693
694
	/**
695 5115 daigle
	 * Checks to see if there is a permission order conflict for a given document.  Each
696
	 * document is only allowed to have a single permission order
697
	 *
698 6122 leinfelder
	 * @param id
699 5091 daigle
	 *            document id
700
	 * @param principal
701
	 *            principal credentials
702
	 */
703 6122 leinfelder
	private void permOrderConflict(String id, String permOrder) throws AccessException, PermOrderException {
704
		if (id == null) {
705
			throw new AccessException("XMLAccessAccess.permOrderConflict - id is required when " +
706 5108 daigle
					"determining perm order conflict");
707
		}
708
		if (permOrder == null) {
709
			throw new AccessException("XMLAccessAccess.permOrderConflict - perm order is required when " +
710
					"determining perm order conflict");
711
		}
712
713
	    PreparedStatement pstmt = null;
714
		DBConnection conn = null;
715
		int serialNumber = -1;
716
		try {
717
			// check out DBConnection
718
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.permOrderConflict");
719 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
720
721 6122 leinfelder
			String sql = "SELECT * FROM xml_access WHERE " + idAttribute + " = ? AND perm_order != ?";
722 5108 daigle
			pstmt = conn.prepareStatement(sql);
723
724
			// Bind the values to the query
725 6122 leinfelder
			pstmt.setString(1, id);
726 5108 daigle
			pstmt.setString(2, permOrder);
727
728
			String sqlReport = "XMLAccessAccess.permOrderConflict - SQL: " + sql;
729 6122 leinfelder
			sqlReport += " [" + id + "," + permOrder + "]";
730 5108 daigle
731
			logMetacat.info(sqlReport);
732
733
			pstmt.execute();
734
735
			ResultSet resultSet = pstmt.getResultSet();
736
			if (resultSet.next()) {
737
				throw new PermOrderException("XMLAccessAccess.addXMLAccess - cannot add permission " +
738 6122 leinfelder
					"record for id: " + id + "with permOrder: " + permOrder + " due to permOrder conflict");
739 5108 daigle
			}
740
		} catch (SQLException sqle) {
741
			throw new AccessException("XMLAccessAccess.permOrderConflict - SQL error when checking"
742 6122 leinfelder
					+ "for perm order conflict on: " + id + ":" + sqle.getMessage());
743 5108 daigle
		} finally {
744
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
745
		}
746
747
	}
748
749
	/**
750
	 * Delete xml access.  This removes all access records from the database for a principal
751
	 * for a given document, perm type and perm order
752 5115 daigle
	 *
753 6122 leinfelder
	 * @param id
754 5108 daigle
	 *            document id
755
	 * @param principal
756
	 *            principal credentials
757
	 */
758 6122 leinfelder
	private void deleteXMLAccessForPrincipal(String id, String principalName, String permType, String permOrder) throws AccessException {
759
		if (id == null) {
760
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - id is required when " +
761 5091 daigle
					"deleting XML access record");
762
		}
763
		if (principalName == null) {
764
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - principal is required when " +
765
					"deleting XML access record");
766
		}
767
		if (permType == null) {
768
			throw new AccessException(
769
					"XMLAccessAccess.deleteXMLAccessForPrincipal - perm type is required when "
770
							+ "deleting XML access record");
771
		}
772
		if (permOrder == null) {
773
			throw new AccessException(
774
					"XMLAccessAccess.deleteXMLAccessForPrincipal - perm order is required when "
775
							+ "deleting XML access record");
776
		}
777
778
	    PreparedStatement pstmt = null;
779
		DBConnection conn = null;
780
		int serialNumber = -1;
781
		try {
782
			// check out DBConnection
783
			conn = DBConnectionPool.getDBConnection("XMLAccessAccess.deleteXMLAccessForPrincipal");
784 5120 daigle
    		serialNumber = conn.getCheckOutSerialNumber();
785
786 6122 leinfelder
			String sql = "DELETE FROM xml_access WHERE " + idAttribute + " = ? AND principal_name = ? " +
787 5108 daigle
				"AND perm_type = ? AND perm_order = ?";
788 5091 daigle
			pstmt = conn.prepareStatement(sql);
789
790
			// Bind the values to the query
791 6122 leinfelder
			pstmt.setString(1, id);
792 5091 daigle
			pstmt.setString(2, principalName);
793
			pstmt.setString(3, permType);
794
			pstmt.setString(4, permOrder);
795
796
			String sqlReport = "XMLAccessAccess.deleteXMLAccessForPrincipal - SQL: " + sql;
797 6122 leinfelder
			sqlReport += " [" + id + "," + principalName + "," + permType + "," + permOrder + "]";
798 5091 daigle
799
			logMetacat.info(sqlReport);
800
801
			pstmt.execute();
802
		} catch (SQLException sqle) {
803
			throw new AccessException("XMLAccessAccess.deleteXMLAccessForPrincipal - SQL error when deleting"
804 6122 leinfelder
					+ "xml access permissions for id: " + id + ", principal: " +
805 5091 daigle
					principalName + ":" + sqle.getMessage());
806
		} finally {
807 5108 daigle
			closeDBObjects(pstmt, conn, serialNumber, logMetacat);
808 5091 daigle
		}
809
810
	}
811 5098 daigle
812
	/**
813
	 * Make sure that only one record exists per principal/permType/document. If
814
	 * more than one record exists, delete the existing records, consolidate the
815
	 * permissions insert the new record.
816
	 *
817 5115 daigle
	 * @param xmlAccessList the access dao list
818 5098 daigle
	 */
819 5091 daigle
	private void cleanupXMLAccessForPrincipal(Vector<XMLAccessDAO> xmlAccessList) throws AccessException{
820
821 5098 daigle
		int numAllowRecords = 0;
822
		int numDenyRecords = 0;
823
		long allowPermissionMask = 0;
824
		long denyPermissionMask = 0;
825 6122 leinfelder
		String id = null;
826 5091 daigle
		String principalName = null;
827
		String permType = null;
828
		String permOrder = null;
829 6017 leinfelder
		// TODO: handle these fields
830
		String accessFileId = null;
831
		String subTreeId = null;
832 5091 daigle
833
834
		// iterate through the list of access dao objects and bttwise or the permissions.  Most
835
		// of this is just doing some error checking to make sure each record is valid.
836
		for (XMLAccessDAO xmlAccessDAO : xmlAccessList) {
837 6122 leinfelder
			String daoId = xmlAccessDAO.getDocId();
838
			if (idAttribute.equals(GUID)) {
839
				daoId = xmlAccessDAO.getGuid();
840
			}
841
			if (id == null) {
842
				id = daoId;
843 5091 daigle
			} else {
844 6122 leinfelder
				if (!id.equals(daoId)) {
845 5091 daigle
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " +
846 6122 leinfelder
							" Conflicting ids " + daoId + " and " + id);
847 5091 daigle
				}
848
			}
849
			if (principalName == null) {
850
				principalName = xmlAccessDAO.getPrincipalName();
851
			} else {
852
				if (!principalName.equals(xmlAccessDAO.getPrincipalName())) {
853
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " +
854
							" Conflicting prinicpal names " + xmlAccessDAO.getPrincipalName() +
855
							" and principalName " + principalName);
856
				}
857
			}
858
			if (permType == null) {
859
				permType = xmlAccessDAO.getPermType();
860
			} else {
861
				if (!permType.equals(xmlAccessDAO.getPermType())) {
862
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " +
863 6122 leinfelder
							" Conflicting permission orders for document " + daoId +
864 5091 daigle
							"principalName " + principalName + ". Database intervention required ");
865
				}
866
			}
867
			if (permOrder == null) {
868
				permOrder = xmlAccessDAO.getPermOrder();
869
			} else {
870
				if (!permOrder.equals(xmlAccessDAO.getPermOrder())) {
871
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " +
872 6122 leinfelder
							" Conflicting permission types for document " + daoId +
873 5091 daigle
							"principalName " + principalName + ". Database intervention required ");
874
				}
875
			}
876
			if (permType == null) {
877
				permType = xmlAccessDAO.getPermType();
878
			} else {
879
				if (!permType.equals(xmlAccessDAO.getPermType())) {
880
					throw new AccessException("XMLAccessAccess.cleanupXMLAccessForPrincipal - " +
881 6122 leinfelder
							" Conflicting permission orders for document " + daoId +
882 5091 daigle
							"principalName " + principalName + ". Database intervention required ");
883
				}
884
			}
885 5098 daigle
			if (permType.equals(AccessControlInterface.ALLOW)) {
886
				numAllowRecords++;
887
				allowPermissionMask |= xmlAccessDAO.getPermission();
888
			} else if (permType.equals(AccessControlInterface.DENY)) {
889
				numDenyRecords++;
890
				denyPermissionMask |= xmlAccessDAO.getPermission();
891
			}
892 6017 leinfelder
			if (accessFileId == null) {
893
				accessFileId = xmlAccessDAO.getAccessFileId();
894
			}
895
			if (subTreeId == null) {
896
				subTreeId = xmlAccessDAO.getSubTreeId();
897
			}
898 5091 daigle
		}
899
900 5098 daigle
		// if there was more than one allow record, remove all allow records for this user on this doc
901
		// with this perm type and perm order then insert a single record
902
		if (numAllowRecords > 1) {
903 6122 leinfelder
			deleteXMLAccessForPrincipal(id, principalName, AccessControlInterface.ALLOW, permOrder);
904
			insertXMLAccess(id, principalName, allowPermissionMask, AccessControlInterface.ALLOW, permOrder, accessFileId, subTreeId);
905 5098 daigle
		}
906
		// if there was more than one deny record, remove all deny records for this user on this doc
907
		// with this perm type and perm order then insert a single record
908
		if (numDenyRecords > 1) {
909 6122 leinfelder
			deleteXMLAccessForPrincipal(id, principalName, AccessControlInterface.DENY, permOrder);
910
			insertXMLAccess(id, principalName, denyPermissionMask, AccessControlInterface.DENY, permOrder, accessFileId, subTreeId);
911 5098 daigle
		}
912 5091 daigle
	}
913
914 5098 daigle
	/**
915 5115 daigle
	 * Make sure for a given list of access DAOs that only one perm order
916
	 * exists. It is assumed that all the DAOs are for the same doc
917 5098 daigle
	 *
918
	 * @param xmlAccessList
919 5115 daigle
	 *            the access dao list
920 5098 daigle
	 */
921 5091 daigle
	private void validateDocXMLAccessList(Vector<XMLAccessDAO> xmlAccessList) throws PermOrderException {
922
		String permOrder = null;
923
		for(XMLAccessDAO xmlAccessDAO : xmlAccessList) {
924 6122 leinfelder
			String daoId = xmlAccessDAO.getDocId();
925
			if (idAttribute.equals(GUID)) {
926
				daoId = xmlAccessDAO.getGuid();
927
			}
928 5091 daigle
			if (permOrder == null) {
929
				permOrder = xmlAccessDAO.getPermOrder();
930
			} else {
931
				if(!permOrder.equals(xmlAccessDAO.getPermOrder())) {
932
					throw new PermOrderException("XMLAccessAccess.validateXMLAccessList - " +
933 6122 leinfelder
						" Conflicting permission orders for document " + daoId +
934 5091 daigle
						". Database intervention required ");
935
				}
936
			}
937
		}
938
	}
939
940 5115 daigle
	/**
941
	 * Check that only one permOrder exists for each principal.
942
	 * TODO add check that one of each permType exists as well
943
	 *
944
	 * @param xmlAccessList
945
	 *            the access dao list
946
	 */
947 5091 daigle
	private void validatePrincipalXMLAccessList(Vector<XMLAccessDAO> xmlAccessList)
948
			throws PermOrderException {
949
950
		boolean allowFirst = false;
951
		boolean denyFirst = false;
952 6122 leinfelder
		String id = null;
953 5091 daigle
954
		// These vectors will hold all combinations of access DAOs with different permission
955
		// orders and permission types.
956
		Vector<XMLAccessDAO> allowFirstAllows = new Vector<XMLAccessDAO>();
957
		Vector<XMLAccessDAO> allowFirstDenys = new Vector<XMLAccessDAO>();
958
		Vector<XMLAccessDAO> denyFirstAllows = new Vector<XMLAccessDAO>();
959
		Vector<XMLAccessDAO> denyFirstDenys = new Vector<XMLAccessDAO>();
960
961
		// sort the access dao records into the appropriate vector
962
		for(XMLAccessDAO xmlAccessDAO : xmlAccessList) {
963 6122 leinfelder
			String daoId = xmlAccessDAO.getDocId();
964
			if (idAttribute.equals(GUID)) {
965
				daoId = xmlAccessDAO.getGuid();
966 5091 daigle
			}
967 6122 leinfelder
			if (id == null) {
968
				id = daoId;
969
			}
970 5091 daigle
			if (xmlAccessDAO.getPermOrder().equals(AccessControlInterface.ALLOWFIRST)) {
971
				allowFirst = true;
972
				if (xmlAccessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
973
					allowFirstAllows.add(xmlAccessDAO);
974
				} else if (xmlAccessDAO.getPermType().equals(AccessControlInterface.DENY)) {
975
					allowFirstDenys.add(xmlAccessDAO);
976
				} else {
977
					throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " +
978
							" Invalid permission type: " + xmlAccessDAO.getPermType() + " for document " +
979 6122 leinfelder
							daoId + ". Database intervention required ");
980 5091 daigle
				}
981
			} else if (xmlAccessDAO.getPermOrder().equals(AccessControlInterface.DENYFIRST)) {
982
				denyFirst = true;
983
				if (xmlAccessDAO.getPermType().equals(AccessControlInterface.ALLOW)) {
984
					denyFirstAllows.add(xmlAccessDAO);
985
				} else if (xmlAccessDAO.getPermType().equals(AccessControlInterface.DENY)) {
986
					denyFirstDenys.add(xmlAccessDAO);
987
				} else {
988
					throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " +
989
							" Invalid permission type: " + xmlAccessDAO.getPermType() + " for document " +
990 6122 leinfelder
							daoId + ". Database intervention required ");
991 5091 daigle
				}
992
			} else {
993
				throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " +
994
						" Invalid permission order: " + xmlAccessDAO.getPermOrder() + " for document " +
995 6122 leinfelder
						daoId + ". Database intervention required ");
996 5091 daigle
			}
997
		}
998
999
		// for a given user, there cannot be allowfirst and denyfirst records on the same
1000
		// document
1001
		if(allowFirst && denyFirst) {
1002
			throw new PermOrderException("XMLAccessAccess.validatePrincipalXMLAccessList - " +
1003 6122 leinfelder
					" Conflicting permission orders for document " + id +
1004 5091 daigle
					". Database intervention required ");
1005
		}
1006
	}
1007
1008
	/**
1009
	 * Populate a job data object with the current row in a resultset
1010
	 *
1011
	 * @param resultSet
1012
	 *            the result set which is already pointing to the desired row.
1013
	 * @return a scheduled job data object
1014
	 */
1015
	protected XMLAccessDAO populateDAO(ResultSet resultSet) throws SQLException {
1016
1017
		XMLAccessDAO xmlAccessDAO = new XMLAccessDAO();
1018 6122 leinfelder
		xmlAccessDAO.setDocId(resultSet.getString(idAttribute));
1019 5091 daigle
		xmlAccessDAO.setAccessFileId(resultSet.getString("accessfileid"));
1020
		xmlAccessDAO.setPrincipalName(resultSet.getString("principal_name"));
1021
		xmlAccessDAO.setPermission(resultSet.getLong("permission"));
1022
		xmlAccessDAO.setPermType(resultSet.getString("perm_type"));
1023
		xmlAccessDAO.setPermOrder(resultSet.getString("perm_order"));
1024
		xmlAccessDAO.setBeginTime(resultSet.getDate("begin_time"));
1025
		xmlAccessDAO.setEndTime(resultSet.getDate("end_time"));
1026
		xmlAccessDAO.setTicketCount(resultSet.getLong("ticket_count"));
1027
		xmlAccessDAO.setSubTreeId(resultSet.getString("subtreeid"));
1028
		xmlAccessDAO.setStartNodeId(resultSet.getString("startnodeid"));
1029
		xmlAccessDAO.setEndNodeId(resultSet.getString("endnodeid"));
1030
1031
		return xmlAccessDAO;
1032
	}
1033
1034
}