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: daigle $'
10
 *     '$Date: 2009-11-09 10:07:41 -0800 (Mon, 09 Nov 2009) $'
11
 * '$Revision: 5115 $'
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
			xmlAccessAccess.addXMLAccess(_docId, principalName, new Long(permission), permType, permOrder);
121
		} catch (AccessException ae) {
122
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
123
					+ "DB access error when inserting permissions: " + ae.getMessage());
124
		} 
125
	}
126
  
127
	/**
128
	 * Replace existing permissions with a given block of permissions for this
129
	 * document.
130
	 * 
131
	 * @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
		try {	
137
			// use DocInfoHandler to parse the access section into DAO objects
138
			XMLReader parser = null;
139
			DocInfoHandler docInfoHandler = new DocInfoHandler(_docId); 
140
			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
			XMLAccessAccess xmlAccessAccess = new XMLAccessAccess();
154
				
155
			// replace all access on the document
156
	        Vector<XMLAccessDAO> accessControlList = docInfoHandler.getAccessControlList();
157
	        xmlAccessAccess.replaceAccess(_docId, accessControlList);
158

    
159
		} catch (PropertyNotFoundException pnfe) {
160
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
161
					+ "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
		} catch (SAXException se) {
166
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
167
					+ "SAX error when replacing permissions: " + se.getMessage());
168
		} catch(IOException ioe) {
169
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
170
					+ "I/O error when replacing permissions: " + ioe.getMessage());
171
		}
172
	}
173
  
174
	/**
175
	 * Check if access control comination for
176
	 * docid/principal/permission/permorder/permtype already exists.
177
	 * 
178
	 * @param xmlAccessDAO
179
	 *            the dao object holding the access we want to check for.
180
	 * @return true if the Access Control for this file already exists in the DB
181
	 */
182
	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
                               ("AccessControlForSingleFiel.accessControlExists");
191
			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
     
200
			// Bind the values to the query
201
			pstmt.setString(1, _docId);
202
			pstmt.setString(2, xmlAccessDAO.getPrincipalName());
203
			pstmt.setLong(3, xmlAccessDAO.getPermission());
204
			pstmt.setString(4, xmlAccessDAO.getPermType());
205
			pstmt.setString(5, xmlAccessDAO.getPermOrder());
206
      
207
			pstmt.execute();
208
			ResultSet rs = pstmt.getResultSet();
209
			exists = rs.next();
210
      
211
		} 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
    
227
		return exists;  
228
	}
229
  
230
	/**
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
	public String getACL(String user, String[] groups)
241
			throws AccessControlException {
242
		StringBuffer output = new StringBuffer();
243
		boolean hasPermission = false;
244

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

    
253
			// 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
			if (hasPermission) {
257
				// 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
			}
264

    
265
			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
	/**
280
	 * Get the access xml for all access on this docid
281
	 * 
282
	 * @return string representation of access
283
	 */
284
	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
			xmlAccessDAOList = xmlAccessAccess.getXMLAccessForDoc(_docId);
291
		} catch (AccessException ae) {
292
				throw new AccessControlException("AccessControlForSingleFile.getAccessString() - DB access error when " + 
293
						"getting access string: " + ae.getMessage());
294
		} 
295
		
296
		return getAccessString(xmlAccessDAOList);
297
	}
298
	
299
	/**
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
	public String getAccessString(Vector<XMLAccessDAO> xmlAccessDAOList) throws AccessControlException {
305
			
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
		output.append("<access authSystem=\"knb\" order=\"" + permOrder + "\" id=\"" + _docId + "\" scope=\"document\"");
323
		
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
		output.append("</access>");
368
					
369
		return output.toString();
370
	}
371
	
372
	/**
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
		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
			pstmt.setString(1, _docId);
390
			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
}
(2-2/9)