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-06 14:44:09 -0800 (Fri, 06 Nov 2009) $'
11
 * '$Revision: 5109 $'
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.
70
   * @param myAccessNumber  the docid or docid with dev will be controlled
71
   */
72
  public AccessControlForSingleFile(String accessionNumber) throws AccessControlException
73
  {
74
	  
75
      //Get rid of dev if myaccessNumber has one;
76
	  _docId = DocumentUtil.getDocIdFromString(accessionNumber);
77
      if (_docId == null || _docId.equals(""))
78
      {
79
        throw new AccessControlException("AccessControlForSingleFile() - Accession number " + 
80
        		"can't be null in constructor");
81
      }
82
      
83
      logMetacat.debug("AccessControlForSingleFile() - docid: " + _docId);
84

    
85
  }
86
  
87
  	/**
88
	 * Insert a single access record into the database based on access DAO
89
	 * object
90
	 * 
91
	 * @param xmlAccessDAO
92
	 *            dao object holding info to insert
93
	 */
94
	public void insertPermissions(XMLAccessDAO xmlAccessDAO) 
95
			throws AccessControlException, PermOrderException{
96
		insertPermissions(xmlAccessDAO.getPrincipalName(), xmlAccessDAO.getPermission(), 
97
				xmlAccessDAO.getPermType(), xmlAccessDAO.getPermOrder());
98
	}
99

    
100
	/**
101
	 * Insert a single access record into the database.
102
	 * 
103
	 * @param principalName
104
	 * @param permission
105
	 * @param permType
106
	 * @param permOrder
107
	 * @throws AccessControlException
108
	 */
109
	public void insertPermissions(String principalName, Long permission, String permType, String permOrder) 
110
			throws AccessControlException, PermOrderException {
111
		try {
112
			// The addXMLAccess method will create the permission record if it does not exist.  
113
			// It will bitwise OR to permissions if the principal already has a record for this
114
			// doc id.
115
			XMLAccessAccess xmlAccessAccess = new XMLAccessAccess();
116
			xmlAccessAccess.addXMLAccess(_docId, principalName, new Long(permission), permType, permOrder);
117
		} catch (AccessException ae) {
118
			throw new AccessControlException("AccessControlForSingleFile.insertPermissions - "
119
					+ "DB access error when inserting permissions: " + ae.getMessage());
120
		} 
121
	}
122
  
123
	/**
124
	 * Replace existing permissions with a given block of permissions for this
125
	 * document.
126
	 * 
127
	 * @param accessBlock
128
	 *            the xml access block. This is the same structure as that
129
	 *            returned by the getdocumentinfo action in metacat.
130
	 */
131
	public void insertPermissions(String accessBlock) throws AccessControlException {
132
		try {			
133
			XMLReader parser = null;
134
			DocInfoHandler docInfoHandler = new DocInfoHandler(_docId); 
135
			ContentHandler chandler = docInfoHandler;
136

    
137
			// Get an instance of the parser
138
			String parserName = PropertyService.getProperty("xml.saxparser");
139
			parser = XMLReaderFactory.createXMLReader(parserName);
140

    
141
			// Turn off validation
142
			parser.setFeature("http://xml.org/sax/features/validation", false);
143
			parser.setContentHandler((ContentHandler)chandler);
144
			parser.setErrorHandler((ErrorHandler)chandler);
145

    
146
			parser.parse(new InputSource(new StringReader(accessBlock)));
147
			
148
			XMLAccessAccess xmlAccessAccess = new XMLAccessAccess();
149
					
150
	        Vector<XMLAccessDAO> accessControlList = docInfoHandler.getAccessControlList();
151
	        xmlAccessAccess.replaceAccess(_docId, accessControlList);
152

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

    
239
		try {   
240
			hasPermission = isOwned(_docId, user);
241
			if (!hasPermission) {
242
				PermissionController controller = new PermissionController(_docId);
243
				hasPermission = 
244
					controller.hasPermission(user, groups, READSTRING);
245
			}
246

    
247
			if (hasPermission) {
248
				// Get a list of all access dao objects for this docid
249
				XMLAccessAccess xmlAccessAccess = new XMLAccessAccess();
250
				Vector<XMLAccessDAO> xmlAccessDAOList = xmlAccessAccess.getXMLAccessForDoc(_docId);
251
				output.append(getAccessString(xmlAccessDAOList));
252
			} else {
253
				output.append(getAccessString(new Vector<XMLAccessDAO>()));
254
			}
255

    
256
			return output.toString();
257

    
258
		} catch (SQLException sqle) {
259
			throw new AccessControlException("AccessControlForSingleFile.getACL() - SQL error when " + 
260
					"getting ACL: " + sqle.getMessage());
261
		} catch (AccessException ae) {
262
			throw new AccessControlException("AccessControlForSingleFile.getACL() - DB access error when " + 
263
					"getting ACL: " + ae.getMessage());
264
		} catch (McdbException mcdb) {
265
			throw new AccessControlException("AccessControlForSingleFile.getACL() - MCDB error when " + 
266
					"getting ACL: " + mcdb.getMessage());
267
		}
268
	}
269
	
270
	public String getAccessString() throws AccessControlException {
271
		Vector<XMLAccessDAO> xmlAccessDAOList = null;
272
		
273
		try {
274
			// Get a list of all access dao objects for this docid
275
			XMLAccessAccess xmlAccessAccess = new XMLAccessAccess();
276
			xmlAccessDAOList = xmlAccessAccess.getXMLAccessForDoc(_docId);
277
		} catch (AccessException ae) {
278
				throw new AccessControlException("AccessControlForSingleFile.getAccessString() - DB access error when " + 
279
						"getting access string: " + ae.getMessage());
280
		} 
281
		
282
		return getAccessString(xmlAccessDAOList);
283
	}
284
	
285
	public String getAccessString(Vector<XMLAccessDAO> xmlAccessDAOList) throws AccessControlException {
286
			
287
		StringBuffer output = new StringBuffer();
288
		StringBuffer tmpOutput = new StringBuffer();
289
		StringBuffer allowOutput = new StringBuffer();
290
		StringBuffer denyOutput = new StringBuffer();
291
		
292
		String principal = null;
293
		int permission = -1;
294
		String permOrder = ALLOWFIRST;
295
		String permType = null;
296
		
297
		// We assume that all the records will have the same permission order, so we can just
298
		// grab the perm order from the first one.
299
		if (xmlAccessDAOList.size() > 0) {
300
			permOrder = xmlAccessDAOList.get(0).getPermOrder();
301
		}
302

    
303
		output.append("<access authSystem=\"knb\" order=\"" + permOrder + "\" id=\"" + _docId + "\" scope=\"document\"");
304
		
305
		output.append(">\n");
306
		
307
		if (xmlAccessDAOList.size() > 0) {
308
			// Since there should only be one permission order allowed per document,
309
			// we can just grab the order off of the first xml access dao object
310
			permOrder = xmlAccessDAOList.get(0).getPermOrder();
311
		}
312
		
313
		for (XMLAccessDAO xmlAccessDAO : xmlAccessDAOList) {
314
			principal = xmlAccessDAO.getPrincipalName();
315
			permission = xmlAccessDAO.getPermission().intValue();
316
			permType = xmlAccessDAO.getPermType();
317
			
318
			tmpOutput.append("    <" + permType + ">\n");
319
			tmpOutput.append("      <principal>" + principal + "</principal>\n");
320
	
321
			if ((permission & READ) == READ) {
322
				tmpOutput.append("      <permission>read</permission>\n");
323
			}
324
			if ((permission & WRITE) == WRITE) {
325
				tmpOutput.append("      <permission>write</permission>\n");
326
			}
327
			if ((permission & ALL) == ALL) {
328
				tmpOutput.append("      <permission>all</permission>\n");
329
			}
330
			if ((permission & CHMOD) == CHMOD) {
331
				tmpOutput.append("      <permission>chmod</permission>\n");
332
			}
333

    
334
			tmpOutput.append("    </" + permType + ">\n");
335
			
336
			if (permType.equals(ALLOW)) {
337
				allowOutput.append(tmpOutput);
338
			} else if (permType.equals(DENY)) {
339
				denyOutput.append(tmpOutput);
340
			}
341
			tmpOutput = new StringBuffer();
342
		}
343
		
344
		// This just orders the allow/deny sections based on the permOrder.  Not 
345
		// required, but convenient later when parsing the output.
346
		if (permOrder.equals(ALLOWFIRST)) {
347
			output.append(allowOutput);
348
			output.append(denyOutput);
349
		} else if (permOrder.equals(DENYFIRST)) {
350
			output.append(denyOutput);
351
			output.append(allowOutput);
352
		}
353
		
354
		output.append("</access>");
355
					
356
		return output.toString();
357
	}
358
	
359
	/* Check if @user is owner of @docid from db conn. */
360
	private boolean isOwned(String docid, String user) throws SQLException {
361
		PreparedStatement pstmt = null;
362
		DBConnection conn = null;
363
		int serialNumber = -1;
364
		try {
365
			// check out DBConnection
366
			conn = DBConnectionPool.getDBConnection("AccessControlList.isOwned");
367
			serialNumber = conn.getCheckOutSerialNumber();
368
			pstmt = conn.prepareStatement("SELECT 'x' FROM xml_documents "
369
					+ "WHERE docid = ? " + "AND user_owner = ?");
370
			pstmt.setString(1, docid);
371
			pstmt.setString(2, user);
372
			pstmt.execute();
373
			ResultSet rs = pstmt.getResultSet();
374
			boolean hasRow = rs.next();
375
			return hasRow;
376
		} finally {
377
			try {
378
				if (pstmt != null) {
379
					pstmt.close();
380
				}
381
			} finally {
382
				DBConnectionPool.returnDBConnection(conn, serialNumber);
383
			}
384
		}
385
	}
386
}
(2-2/9)