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