Project

General

Profile

1 1365 tao
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that loads eml-access.xml file containing ACL
4
 *             for a metadata document into relational DB
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Jivka Bojilova
8
 *
9
 *   '$Author$'
10
 *     '$Date$'
11
 * '$Revision$'
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 5089 daigle
package edu.ucsb.nceas.metacat.accesscontrol;
29 1365 tao
30 5098 daigle
import java.io.IOException;
31
import java.io.StringReader;
32
import java.sql.PreparedStatement;
33
import java.sql.ResultSet;
34
import java.sql.SQLException;
35
import java.util.Vector;
36 5089 daigle
37 2663 sgarg
import org.apache.log4j.Logger;
38 5098 daigle
import org.xml.sax.ContentHandler;
39
import org.xml.sax.ErrorHandler;
40
import org.xml.sax.InputSource;
41
import org.xml.sax.SAXException;
42
import org.xml.sax.XMLReader;
43
import org.xml.sax.helpers.XMLReaderFactory;
44 1365 tao
45 6744 leinfelder
import edu.ucsb.nceas.metacat.DBUtil;
46
import edu.ucsb.nceas.metacat.IdentifierManager;
47
import edu.ucsb.nceas.metacat.McdbDocNotFoundException;
48 5098 daigle
import edu.ucsb.nceas.metacat.McdbException;
49
import edu.ucsb.nceas.metacat.PermissionController;
50 5015 daigle
import edu.ucsb.nceas.metacat.database.DBConnection;
51
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
52 5098 daigle
import edu.ucsb.nceas.metacat.properties.PropertyService;
53 5089 daigle
import edu.ucsb.nceas.metacat.shared.AccessException;
54 5025 daigle
import edu.ucsb.nceas.metacat.util.DocumentUtil;
55 5098 daigle
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
56 7475 leinfelder
import edu.ucsb.nceas.utilities.access.AccessControlInterface;
57
import edu.ucsb.nceas.utilities.access.DocInfoHandler;
58
import edu.ucsb.nceas.utilities.access.XMLAccessDAO;
59 1365 tao
60 4080 daigle
61 1365 tao
/**
62
 * A Class that loads eml-access.xml file containing ACL for a metadata
63
 * document into relational DB. It extends DefaultHandler class to handle
64
 * SAX parsing events when processing the XML stream.
65
 */
66
public class AccessControlForSingleFile implements AccessControlInterface
67
{
68
69 6744 leinfelder
  private String _guid;
70
71 2663 sgarg
  private Logger logMetacat = Logger.getLogger(AccessControlForSingleFile.class);
72 1365 tao
73 5115 daigle
    /**
74
	 * Construct an instance of the AccessControlForSingleFile class.  This
75
	 * instance will represent one file only.
76
	 *
77
	 * @param myAccessNumber
78
	 *            the docid or docid with dev will be controlled
79
	 */
80
	public AccessControlForSingleFile(String accessionNumber)
81
			throws AccessControlException {
82 5098 daigle
83 6744 leinfelder
		// this is a local metacat id
84
		String docid = DocumentUtil.getDocIdFromString(accessionNumber);
85
		// get the revision
86
		String revision = DocumentUtil.getRevisionStringFromString(accessionNumber);
87
		int rev = -1;
88
		if (revision != null) {
89
			// we were given it
90
			rev = Integer.valueOf(revision);
91
		} else {
92
			// look up the latest
93
			try {
94
				rev = DBUtil.getLatestRevisionInDocumentTable(docid);
95
			} catch (SQLException e) {
96
				AccessControlException ace = new AccessControlException(e.getMessage());
97
				ace.initCause(e);
98
				throw ace;
99
			}
100
			if (rev <= 0) {
101
				// look in the revisions table
102
				try {
103
					rev = DBUtil.getMaxRevFromRevisionTable(docid);
104
				} catch (SQLException e) {
105
					AccessControlException ace = new AccessControlException(e.getMessage());
106
					ace.initCause(e);
107
					throw ace;
108
				}
109
			}
110 5115 daigle
		}
111 6744 leinfelder
112
		// find the guid for this docid.rev
113
		try {
114
			_guid = IdentifierManager.getInstance().getGUID(docid, rev);
115
		} catch (McdbDocNotFoundException e) {
116
			AccessControlException ace = new AccessControlException(e.getMessage());
117
			ace.initCause(e);
118
			throw ace;
119
		}
120
121
		// couldn't find it?
122
		if (_guid == null || _guid.equals("")) {
123
			throw new AccessControlException("Guid cannot be null");
124
		}
125 5115 daigle
126 6744 leinfelder
		logMetacat.debug("AccessControlForSingleFile() - docid: " + _guid);
127 5115 daigle
	}
128 1365 tao
129 5098 daigle
  	/**
130
	 * Insert a single access record into the database based on access DAO
131
	 * object
132
	 *
133
	 * @param xmlAccessDAO
134
	 *            dao object holding info to insert
135
	 */
136 5109 daigle
	public void insertPermissions(XMLAccessDAO xmlAccessDAO)
137
			throws AccessControlException, PermOrderException{
138 5098 daigle
		insertPermissions(xmlAccessDAO.getPrincipalName(), xmlAccessDAO.getPermission(),
139 6017 leinfelder
				xmlAccessDAO.getPermType(), xmlAccessDAO.getPermOrder(), xmlAccessDAO.getAccessFileId(), xmlAccessDAO.getSubTreeId());
140 5098 daigle
	}
141 1365 tao
142 5098 daigle
	/**
143
	 * Insert a single access record into the database.
144
	 *
145
	 * @param principalName
146 5115 daigle
	 *            the principal credentials
147 5098 daigle
	 * @param permission
148 5115 daigle
	 *            the permission
149 5098 daigle
	 * @param permType
150 5115 daigle
	 *            the permission type
151 5098 daigle
	 * @param permOrder
152 5115 daigle
	 *            the permission order
153 5098 daigle
	 */
154 6017 leinfelder
	public void insertPermissions(String principalName, Long permission, String permType, String permOrder, String accessFileId, String subTreeId)
155 5109 daigle
			throws AccessControlException, PermOrderException {
156 5089 daigle
		try {
157
			// The addXMLAccess method will create the permission record if it does not exist.
158
			// It will bitwise OR to permissions if the principal already has a record for this
159
			// doc id.
160
			XMLAccessAccess xmlAccessAccess = new XMLAccessAccess();
161 5734 berkley
			//System.out.println("permission in accessControlForSingleFile.insertPermissions: " + permission);
162 6744 leinfelder
			xmlAccessAccess.addXMLAccess(_guid, principalName, new Long(permission), permType, permOrder, accessFileId, subTreeId);
163 5089 daigle
		} catch (AccessException ae) {
164
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
165
					+ "DB access error when inserting permissions: " + ae.getMessage());
166
		}
167
	}
168 4419 leinfelder
169 5098 daigle
	/**
170
	 * Replace existing permissions with a given block of permissions for this
171
	 * document.
172 5089 daigle
	 *
173 5098 daigle
	 * @param accessBlock
174
	 *            the xml access block. This is the same structure as that
175
	 *            returned by the getdocumentinfo action in metacat.
176
	 */
177
	public void insertPermissions(String accessBlock) throws AccessControlException {
178 5115 daigle
		try {
179
			// use DocInfoHandler to parse the access section into DAO objects
180 5098 daigle
			XMLReader parser = null;
181 6744 leinfelder
			DocInfoHandler docInfoHandler = new DocInfoHandler(_guid);
182 5098 daigle
			ContentHandler chandler = docInfoHandler;
183
184
			// Get an instance of the parser
185
			String parserName = PropertyService.getProperty("xml.saxparser");
186
			parser = XMLReaderFactory.createXMLReader(parserName);
187
188
			// Turn off validation
189
			parser.setFeature("http://xml.org/sax/features/validation", false);
190
			parser.setContentHandler((ContentHandler)chandler);
191
			parser.setErrorHandler((ErrorHandler)chandler);
192
193
			parser.parse(new InputSource(new StringReader(accessBlock)));
194
195 5099 daigle
			XMLAccessAccess xmlAccessAccess = new XMLAccessAccess();
196 5115 daigle
197
			// replace all access on the document
198 5098 daigle
	        Vector<XMLAccessDAO> accessControlList = docInfoHandler.getAccessControlList();
199 6744 leinfelder
	        xmlAccessAccess.replaceAccess(_guid, accessControlList);
200 5109 daigle
201 5098 daigle
		} catch (PropertyNotFoundException pnfe) {
202
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
203 5099 daigle
					+ "property error when replacing permissions: " + pnfe.getMessage());
204
		} catch (AccessException ae) {
205
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
206
					+ "DB access error when replacing permissions: " + ae.getMessage());
207 5098 daigle
		} catch (SAXException se) {
208
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
209 5099 daigle
					+ "SAX error when replacing permissions: " + se.getMessage());
210 5098 daigle
		} catch(IOException ioe) {
211
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
212 5099 daigle
					+ "I/O error when replacing permissions: " + ioe.getMessage());
213 5098 daigle
		}
214
	}
215
216
	/**
217 5115 daigle
	 * Check if access control comination for
218
	 * docid/principal/permission/permorder/permtype already exists.
219 5098 daigle
	 *
220 5115 daigle
	 * @param xmlAccessDAO
221
	 *            the dao object holding the access we want to check for.
222 5089 daigle
	 * @return true if the Access Control for this file already exists in the DB
223
	 */
224 5098 daigle
	public boolean accessControlExists(XMLAccessDAO xmlAccessDAO) throws AccessControlException {
225
		boolean exists = false;
226
		PreparedStatement pstmt = null;
227
		DBConnection conn = null;
228
		int serialNumber = -1;
229
		try {
230
			//check out DBConnection
231
			conn=DBConnectionPool.getDBConnection
232 4450 leinfelder
                               ("AccessControlForSingleFiel.accessControlExists");
233 5098 daigle
			serialNumber=conn.getCheckOutSerialNumber();
234
			pstmt = conn.prepareStatement(
235
				"SELECT * FROM xml_access " +
236 6779 leinfelder
				"WHERE guid = ? " +
237 5098 daigle
				"AND principal_name = ? " +
238
				"AND permission = ? " +
239
				"AND perm_type = ? " +
240 6017 leinfelder
				"AND perm_order = ? ");
241 4450 leinfelder
242 5098 daigle
			// Bind the values to the query
243 6744 leinfelder
			pstmt.setString(1, _guid);
244 5098 daigle
			pstmt.setString(2, xmlAccessDAO.getPrincipalName());
245
			pstmt.setLong(3, xmlAccessDAO.getPermission());
246
			pstmt.setString(4, xmlAccessDAO.getPermType());
247
			pstmt.setString(5, xmlAccessDAO.getPermOrder());
248 4450 leinfelder
249 5098 daigle
			pstmt.execute();
250
			ResultSet rs = pstmt.getResultSet();
251
			exists = rs.next();
252 4450 leinfelder
253 5098 daigle
		} catch (SQLException sqle){
254
			throw new AccessControlException("AccessControlForSingleFile.accessControlExists - SQL error when " +
255
					"checking if access control exists: " + sqle.getMessage());
256
		} finally {
257
			try {
258
				if(pstmt != null) {
259
					pstmt.close();
260
				}
261
			} catch (SQLException sqle) {
262
				logMetacat.error("AccessControlForSingleFile.accessControlExists - Could not close " +
263
						"prepared statement: " +sqle.getMessage());
264
			} finally {
265
				DBConnectionPool.returnDBConnection(conn, serialNumber);
266
			}
267
		}
268 4450 leinfelder
269 5098 daigle
		return exists;
270
	}
271 4450 leinfelder
272 5098 daigle
	/**
273
	 * Get Access Control List information for document from db connetion. User
274
	 * or Group should have permissions for reading access control information
275
	 * for a document specified by
276
	 *
277
	 * @param user
278
	 *            name of user connected to Metacat system
279
	 * @param groups
280
	 *            names of user's groups to which user belongs
281
	 */
282 5099 daigle
	public String getACL(String user, String[] groups)
283 5098 daigle
			throws AccessControlException {
284
		StringBuffer output = new StringBuffer();
285
		boolean hasPermission = false;
286 1365 tao
287 5099 daigle
		try {
288 5115 daigle
			hasPermission = isOwned(user);
289 5098 daigle
			if (!hasPermission) {
290 7291 leinfelder
				// get the docid for this guid
291
				String docid = IdentifierManager.getInstance().getLocalId(_guid);
292
				PermissionController controller = new PermissionController(docid);
293 5098 daigle
				hasPermission =
294
					controller.hasPermission(user, groups, READSTRING);
295
			}
296 1365 tao
297 5115 daigle
			// if the user has permissions, get the access dao list for this doc and return
298
			// it as a string.  Otherwise, get the string for an empty access dao list
299
			// (which will return the access section with no allow or deny sections)
300 5098 daigle
			if (hasPermission) {
301 5099 daigle
				// Get a list of all access dao objects for this docid
302
				XMLAccessAccess xmlAccessAccess = new XMLAccessAccess();
303 6744 leinfelder
				Vector<XMLAccessDAO> xmlAccessDAOList = xmlAccessAccess.getXMLAccessForDoc(_guid);
304 5099 daigle
				output.append(getAccessString(xmlAccessDAOList));
305
			} else {
306
				output.append(getAccessString(new Vector<XMLAccessDAO>()));
307 5098 daigle
			}
308 4419 leinfelder
309 5098 daigle
			return output.toString();
310
311
		} catch (SQLException sqle) {
312
			throw new AccessControlException("AccessControlForSingleFile.getACL() - SQL error when " +
313
					"getting ACL: " + sqle.getMessage());
314
		} catch (AccessException ae) {
315
			throw new AccessControlException("AccessControlForSingleFile.getACL() - DB access error when " +
316
					"getting ACL: " + ae.getMessage());
317
		} catch (McdbException mcdb) {
318
			throw new AccessControlException("AccessControlForSingleFile.getACL() - MCDB error when " +
319
					"getting ACL: " + mcdb.getMessage());
320
		}
321
	}
322
323 5115 daigle
	/**
324
	 * Get the access xml for all access on this docid
325
	 *
326
	 * @return string representation of access
327
	 */
328 5098 daigle
	public String getAccessString() throws AccessControlException {
329
		Vector<XMLAccessDAO> xmlAccessDAOList = null;
330
331
		try {
332
			// Get a list of all access dao objects for this docid
333
			XMLAccessAccess xmlAccessAccess = new XMLAccessAccess();
334 6744 leinfelder
			xmlAccessDAOList = xmlAccessAccess.getXMLAccessForDoc(_guid);
335 5098 daigle
		} catch (AccessException ae) {
336
				throw new AccessControlException("AccessControlForSingleFile.getAccessString() - DB access error when " +
337
						"getting access string: " + ae.getMessage());
338
		}
339
340 5099 daigle
		return getAccessString(xmlAccessDAOList);
341 5098 daigle
	}
342
343 5115 daigle
	/**
344
	 * Put together an xml representation of the objects in a given access dao list
345
	 * @param xmlAccessDAOList list of xml access DAO objects
346
	 * @return string representation of access
347
	 */
348 5099 daigle
	public String getAccessString(Vector<XMLAccessDAO> xmlAccessDAOList) throws AccessControlException {
349 5098 daigle
350
		StringBuffer output = new StringBuffer();
351
		StringBuffer tmpOutput = new StringBuffer();
352
		StringBuffer allowOutput = new StringBuffer();
353
		StringBuffer denyOutput = new StringBuffer();
354
355
		String principal = null;
356
		int permission = -1;
357
		String permOrder = ALLOWFIRST;
358
		String permType = null;
359 6016 leinfelder
		String accessfileid = null;
360
		String subtreeid = null;
361 5098 daigle
362
		// We assume that all the records will have the same permission order, so we can just
363
		// grab the perm order from the first one.
364
		if (xmlAccessDAOList.size() > 0) {
365
			permOrder = xmlAccessDAOList.get(0).getPermOrder();
366 6016 leinfelder
			accessfileid = xmlAccessDAOList.get(0).getAccessFileId();
367
			subtreeid = xmlAccessDAOList.get(0).getSubTreeId();
368 5098 daigle
		}
369 7307 leinfelder
370
		// get the docid for this guid
371
		String docid = _guid;
372
		try {
373
			docid = IdentifierManager.getInstance().getLocalId(_guid);
374
		} catch (McdbDocNotFoundException e) {
375
			logMetacat.warn("Could not lookup docid for guid, defaulting to guid: " + _guid, e);
376
		}
377 5098 daigle
378 7307 leinfelder
		output.append("<access authSystem=\"knb\" order=\"" + permOrder + "\" id=\"" + docid + "\" scope=\"document\"");
379 6016 leinfelder
		if (accessfileid != null) {
380
			output.append(" accessfileid=\"" + accessfileid + "\"");
381
		}
382
		if (subtreeid != null) {
383
			output.append(" subtreeid=\"" + subtreeid + "\"");
384
		}
385 5098 daigle
386
		output.append(">\n");
387
388
		for (XMLAccessDAO xmlAccessDAO : xmlAccessDAOList) {
389
			principal = xmlAccessDAO.getPrincipalName();
390
			permission = xmlAccessDAO.getPermission().intValue();
391 5734 berkley
			//System.out.println("accessControlForSingleFile.getAccessString: permission is set to: " + permission);
392 5098 daigle
			permType = xmlAccessDAO.getPermType();
393
394
			tmpOutput.append("    <" + permType + ">\n");
395
			tmpOutput.append("      <principal>" + principal + "</principal>\n");
396
397
			if ((permission & READ) == READ) {
398
				tmpOutput.append("      <permission>read</permission>\n");
399
			}
400
			if ((permission & WRITE) == WRITE) {
401
				tmpOutput.append("      <permission>write</permission>\n");
402
			}
403
			if ((permission & ALL) == ALL) {
404
				tmpOutput.append("      <permission>all</permission>\n");
405
			}
406
			if ((permission & CHMOD) == CHMOD) {
407
				tmpOutput.append("      <permission>chmod</permission>\n");
408
			}
409
410
			tmpOutput.append("    </" + permType + ">\n");
411
412
			if (permType.equals(ALLOW)) {
413
				allowOutput.append(tmpOutput);
414
			} else if (permType.equals(DENY)) {
415
				denyOutput.append(tmpOutput);
416
			}
417
			tmpOutput = new StringBuffer();
418
		}
419
420
		// This just orders the allow/deny sections based on the permOrder.  Not
421
		// required, but convenient later when parsing the output.
422
		if (permOrder.equals(ALLOWFIRST)) {
423
			output.append(allowOutput);
424
			output.append(denyOutput);
425
		} else if (permOrder.equals(DENYFIRST)) {
426
			output.append(denyOutput);
427
			output.append(allowOutput);
428
		}
429
430 5099 daigle
		output.append("</access>");
431 5098 daigle
432
		return output.toString();
433
	}
434
435 5115 daigle
	/**
436
	 * check if the docid represented in this class is owned by the user
437
	 *
438
	 * @param user
439
	 *            the user credentials
440
	 * @return true if doc is owned by user, false otherwise
441
	 */
442
	private boolean isOwned(String user) throws SQLException {
443 5098 daigle
		PreparedStatement pstmt = null;
444
		DBConnection conn = null;
445
		int serialNumber = -1;
446
		try {
447
			// check out DBConnection
448
			conn = DBConnectionPool.getDBConnection("AccessControlList.isOwned");
449
			serialNumber = conn.getCheckOutSerialNumber();
450 6779 leinfelder
			String query =
451
				"SELECT id.guid FROM xml_documents xd, identifier id "
452
				+ "WHERE xd.docid = id.docid " +
453
						"AND xd.rev = id.rev " +
454
						"AND id.guid = ? " +
455
						"AND user_owner = ? ";
456
			pstmt = conn.prepareStatement(query );
457 6744 leinfelder
			pstmt.setString(1, _guid);
458 5098 daigle
			pstmt.setString(2, user);
459
			pstmt.execute();
460
			ResultSet rs = pstmt.getResultSet();
461
			boolean hasRow = rs.next();
462
			return hasRow;
463
		} finally {
464
			try {
465
				if (pstmt != null) {
466
					pstmt.close();
467
				}
468
			} finally {
469
				DBConnectionPool.returnDBConnection(conn, serialNumber);
470
			}
471
		}
472
	}
473 1365 tao
}