Project

General

Profile

1
/**
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: leinfelder $'
10
 *     '$Date: 2011-03-23 12:51:40 -0700 (Wed, 23 Mar 2011) $'
11
 * '$Revision: 6016 $'
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.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

    
37
import org.apache.log4j.Logger;
38
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

    
45
import edu.ucsb.nceas.metacat.DocInfoHandler;
46
import edu.ucsb.nceas.metacat.McdbException;
47
import edu.ucsb.nceas.metacat.PermissionController;
48
import edu.ucsb.nceas.metacat.database.DBConnection;
49
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
50
import edu.ucsb.nceas.metacat.properties.PropertyService;
51
import edu.ucsb.nceas.metacat.shared.AccessException;
52
import edu.ucsb.nceas.metacat.util.DocumentUtil;
53
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
54

    
55

    
56
/** 
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
  private String _docId;
65
  private Logger logMetacat = Logger.getLogger(AccessControlForSingleFile.class);
66

    
67
 
68
    /**
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

    
78
		// 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
  
88
  	/**
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
	public void insertPermissions(XMLAccessDAO xmlAccessDAO) 
96
			throws AccessControlException, PermOrderException{
97
		insertPermissions(xmlAccessDAO.getPrincipalName(), xmlAccessDAO.getPermission(), 
98
				xmlAccessDAO.getPermType(), xmlAccessDAO.getPermOrder());
99
	}
100

    
101
	/**
102
	 * Insert a single access record into the database.
103
	 * 
104
	 * @param principalName
105
	 *            the principal credentials
106
	 * @param permission
107
	 *            the permission
108
	 * @param permType
109
	 *            the permission type
110
	 * @param permOrder
111
	 *            the permission order
112
	 */
113
	public void insertPermissions(String principalName, Long permission, String permType, String permOrder) 
114
			throws AccessControlException, PermOrderException {
115
		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
			//System.out.println("permission in accessControlForSingleFile.insertPermissions: " + permission);
121
			xmlAccessAccess.addXMLAccess(_docId, principalName, new Long(permission), permType, permOrder);
122
		} catch (AccessException ae) {
123
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
124
					+ "DB access error when inserting permissions: " + ae.getMessage());
125
		} 
126
	}
127
  
128
	/**
129
	 * Replace existing permissions with a given block of permissions for this
130
	 * document.
131
	 * 
132
	 * @param accessBlock
133
	 *            the xml access block. This is the same structure as that
134
	 *            returned by the getdocumentinfo action in metacat.
135
	 */
136
	public void insertPermissions(String accessBlock) throws AccessControlException {
137
		try {	
138
			// use DocInfoHandler to parse the access section into DAO objects
139
			XMLReader parser = null;
140
			DocInfoHandler docInfoHandler = new DocInfoHandler(_docId); 
141
			ContentHandler chandler = docInfoHandler;
142

    
143
			// Get an instance of the parser
144
			String parserName = PropertyService.getProperty("xml.saxparser");
145
			parser = XMLReaderFactory.createXMLReader(parserName);
146

    
147
			// Turn off validation
148
			parser.setFeature("http://xml.org/sax/features/validation", false);
149
			parser.setContentHandler((ContentHandler)chandler);
150
			parser.setErrorHandler((ErrorHandler)chandler);
151

    
152
			parser.parse(new InputSource(new StringReader(accessBlock)));
153
			
154
			XMLAccessAccess xmlAccessAccess = new XMLAccessAccess();
155
				
156
			// replace all access on the document
157
	        Vector<XMLAccessDAO> accessControlList = docInfoHandler.getAccessControlList();
158
	        xmlAccessAccess.replaceAccess(_docId, accessControlList);
159

    
160
		} catch (PropertyNotFoundException pnfe) {
161
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
162
					+ "property error when replacing permissions: " + pnfe.getMessage());
163
		} catch (AccessException ae) {
164
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
165
					+ "DB access error when replacing permissions: " + ae.getMessage());
166
		} catch (SAXException se) {
167
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
168
					+ "SAX error when replacing permissions: " + se.getMessage());
169
		} catch(IOException ioe) {
170
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
171
					+ "I/O error when replacing permissions: " + ioe.getMessage());
172
		}
173
	}
174
  
175
	/**
176
	 * Check if access control comination for
177
	 * docid/principal/permission/permorder/permtype already exists.
178
	 * 
179
	 * @param xmlAccessDAO
180
	 *            the dao object holding the access we want to check for.
181
	 * @return true if the Access Control for this file already exists in the DB
182
	 */
183
	public boolean accessControlExists(XMLAccessDAO xmlAccessDAO) throws AccessControlException {
184
		boolean exists = false;
185
		PreparedStatement pstmt = null;
186
		DBConnection conn = null;
187
		int serialNumber = -1;
188
		try {
189
			//check out DBConnection
190
			conn=DBConnectionPool.getDBConnection
191
                               ("AccessControlForSingleFiel.accessControlExists");
192
			serialNumber=conn.getCheckOutSerialNumber();
193
			pstmt = conn.prepareStatement(
194
				"SELECT * FROM xml_access " + 
195
				"WHERE docid = ? " +
196
				"AND principal_name = ? " +
197
				"AND permission = ? " +
198
				"AND perm_type = ? " +
199
				"AND perm_order =? ");
200
     
201
			// Bind the values to the query
202
			pstmt.setString(1, _docId);
203
			pstmt.setString(2, xmlAccessDAO.getPrincipalName());
204
			pstmt.setLong(3, xmlAccessDAO.getPermission());
205
			pstmt.setString(4, xmlAccessDAO.getPermType());
206
			pstmt.setString(5, xmlAccessDAO.getPermOrder());
207
      
208
			pstmt.execute();
209
			ResultSet rs = pstmt.getResultSet();
210
			exists = rs.next();
211
      
212
		} catch (SQLException sqle){
213
			throw new AccessControlException("AccessControlForSingleFile.accessControlExists - SQL error when " +  
214
					"checking if access control exists: " + sqle.getMessage());
215
		} finally {
216
			try {
217
				if(pstmt != null) {
218
					pstmt.close();
219
				}
220
			} catch (SQLException sqle) {
221
				logMetacat.error("AccessControlForSingleFile.accessControlExists - Could not close " + 
222
						"prepared statement: " +sqle.getMessage());
223
			} finally {
224
				DBConnectionPool.returnDBConnection(conn, serialNumber);
225
			}
226
		}
227
    
228
		return exists;  
229
	}
230
  
231
	/**
232
	 * Get Access Control List information for document from db connetion. User
233
	 * or Group should have permissions for reading access control information
234
	 * for a document specified by
235
	 * 
236
	 * @param user
237
	 *            name of user connected to Metacat system
238
	 * @param groups
239
	 *            names of user's groups to which user belongs
240
	 */
241
	public String getACL(String user, String[] groups)
242
			throws AccessControlException {
243
		StringBuffer output = new StringBuffer();
244
		boolean hasPermission = false;
245

    
246
		try {   
247
			hasPermission = isOwned(user);
248
			if (!hasPermission) {
249
				PermissionController controller = new PermissionController(_docId);
250
				hasPermission = 
251
					controller.hasPermission(user, groups, READSTRING);
252
			}
253

    
254
			// if the user has permissions, get the access dao list for this doc and return
255
			// it as a string.  Otherwise, get the string for an empty access dao list 
256
			// (which will return the access section with no allow or deny sections)
257
			if (hasPermission) {
258
				// Get a list of all access dao objects for this docid
259
				XMLAccessAccess xmlAccessAccess = new XMLAccessAccess();
260
				Vector<XMLAccessDAO> xmlAccessDAOList = xmlAccessAccess.getXMLAccessForDoc(_docId);
261
				output.append(getAccessString(xmlAccessDAOList));
262
			} else {
263
				output.append(getAccessString(new Vector<XMLAccessDAO>()));
264
			}
265

    
266
			return output.toString();
267

    
268
		} catch (SQLException sqle) {
269
			throw new AccessControlException("AccessControlForSingleFile.getACL() - SQL error when " + 
270
					"getting ACL: " + sqle.getMessage());
271
		} catch (AccessException ae) {
272
			throw new AccessControlException("AccessControlForSingleFile.getACL() - DB access error when " + 
273
					"getting ACL: " + ae.getMessage());
274
		} catch (McdbException mcdb) {
275
			throw new AccessControlException("AccessControlForSingleFile.getACL() - MCDB error when " + 
276
					"getting ACL: " + mcdb.getMessage());
277
		}
278
	}
279
	
280
	/**
281
	 * Get the access xml for all access on this docid
282
	 * 
283
	 * @return string representation of access
284
	 */
285
	public String getAccessString() throws AccessControlException {
286
		Vector<XMLAccessDAO> xmlAccessDAOList = null;
287
		
288
		try {
289
			// Get a list of all access dao objects for this docid
290
			XMLAccessAccess xmlAccessAccess = new XMLAccessAccess();
291
			xmlAccessDAOList = xmlAccessAccess.getXMLAccessForDoc(_docId);
292
		} catch (AccessException ae) {
293
				throw new AccessControlException("AccessControlForSingleFile.getAccessString() - DB access error when " + 
294
						"getting access string: " + ae.getMessage());
295
		} 
296
		
297
		return getAccessString(xmlAccessDAOList);
298
	}
299
	
300
	/**
301
	 * Put together an xml representation of the objects in a given access dao list
302
	 * @param xmlAccessDAOList list of xml access DAO objects
303
	 * @return string representation of access
304
	 */
305
	public String getAccessString(Vector<XMLAccessDAO> xmlAccessDAOList) throws AccessControlException {
306
			
307
		StringBuffer output = new StringBuffer();
308
		StringBuffer tmpOutput = new StringBuffer();
309
		StringBuffer allowOutput = new StringBuffer();
310
		StringBuffer denyOutput = new StringBuffer();
311
		
312
		String principal = null;
313
		int permission = -1;
314
		String permOrder = ALLOWFIRST;
315
		String permType = null;
316
		String accessfileid = null;
317
		String subtreeid = null;
318
		
319
		// We assume that all the records will have the same permission order, so we can just
320
		// grab the perm order from the first one.
321
		if (xmlAccessDAOList.size() > 0) {
322
			permOrder = xmlAccessDAOList.get(0).getPermOrder();
323
			accessfileid = xmlAccessDAOList.get(0).getAccessFileId();
324
			subtreeid = xmlAccessDAOList.get(0).getSubTreeId();
325
		}
326

    
327
		output.append("<access authSystem=\"knb\" order=\"" + permOrder + "\" id=\"" + _docId + "\" scope=\"document\"");
328
		if (accessfileid != null) {
329
			output.append(" accessfileid=\"" + accessfileid + "\"");
330
		}
331
		if (subtreeid != null) {
332
			output.append(" subtreeid=\"" + subtreeid + "\"");
333
		}
334
		
335
		output.append(">\n");
336
		
337
		for (XMLAccessDAO xmlAccessDAO : xmlAccessDAOList) {
338
			principal = xmlAccessDAO.getPrincipalName();
339
			permission = xmlAccessDAO.getPermission().intValue();
340
			//System.out.println("accessControlForSingleFile.getAccessString: permission is set to: " + permission);
341
			permType = xmlAccessDAO.getPermType();
342
			
343
			tmpOutput.append("    <" + permType + ">\n");
344
			tmpOutput.append("      <principal>" + principal + "</principal>\n");
345
	
346
			if ((permission & READ) == READ) {
347
				tmpOutput.append("      <permission>read</permission>\n");
348
			}
349
			if ((permission & WRITE) == WRITE) {
350
				tmpOutput.append("      <permission>write</permission>\n");
351
			}
352
			if ((permission & ALL) == ALL) {
353
				tmpOutput.append("      <permission>all</permission>\n");
354
			}
355
			if ((permission & CHMOD) == CHMOD) {
356
				tmpOutput.append("      <permission>chmod</permission>\n");
357
			}
358

    
359
			tmpOutput.append("    </" + permType + ">\n");
360
			
361
			if (permType.equals(ALLOW)) {
362
				allowOutput.append(tmpOutput);
363
			} else if (permType.equals(DENY)) {
364
				denyOutput.append(tmpOutput);
365
			}
366
			tmpOutput = new StringBuffer();
367
		}
368
		
369
		// This just orders the allow/deny sections based on the permOrder.  Not 
370
		// required, but convenient later when parsing the output.
371
		if (permOrder.equals(ALLOWFIRST)) {
372
			output.append(allowOutput);
373
			output.append(denyOutput);
374
		} else if (permOrder.equals(DENYFIRST)) {
375
			output.append(denyOutput);
376
			output.append(allowOutput);
377
		}
378
		
379
		output.append("</access>");
380
					
381
		return output.toString();
382
	}
383
	
384
	/**
385
	 * check if the docid represented in this class is owned by the user
386
	 * 
387
	 * @param user
388
	 *            the user credentials
389
	 * @return true if doc is owned by user, false otherwise
390
	 */
391
	private boolean isOwned(String user) throws SQLException {
392
		PreparedStatement pstmt = null;
393
		DBConnection conn = null;
394
		int serialNumber = -1;
395
		try {
396
			// check out DBConnection
397
			conn = DBConnectionPool.getDBConnection("AccessControlList.isOwned");
398
			serialNumber = conn.getCheckOutSerialNumber();
399
			pstmt = conn.prepareStatement("SELECT 'x' FROM xml_documents "
400
					+ "WHERE docid = ? " + "AND user_owner = ?");
401
			pstmt.setString(1, _docId);
402
			pstmt.setString(2, user);
403
			pstmt.execute();
404
			ResultSet rs = pstmt.getResultSet();
405
			boolean hasRow = rs.next();
406
			return hasRow;
407
		} finally {
408
			try {
409
				if (pstmt != null) {
410
					pstmt.close();
411
				}
412
			} finally {
413
				DBConnectionPool.returnDBConnection(conn, serialNumber);
414
			}
415
		}
416
	}
417
}
(2-2/9)