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