Project

General

Profile

1 1425 tao
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A class that handles checking permssision for a document
4 2245 sgarg
               and subtree in a document
5
 *
6 1425 tao
 *  Copyright: 2000 Regents of the University of California and the
7
 *             National Center for Ecological Analysis and Synthesis
8
 *    Authors: Chad Berkley
9
 *
10
 *   '$Author$'
11
 *     '$Date$'
12
 * '$Revision$'
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 */
28
package edu.ucsb.nceas.metacat;
29 2245 sgarg
30 1425 tao
import java.sql.*;
31 1485 tao
import java.util.Enumeration;
32 1434 tao
import java.util.Hashtable;
33 4861 daigle
import java.util.Stack;
34 1425 tao
import java.util.Vector;
35 4861 daigle
import java.util.Iterator;
36 1425 tao
37 2663 sgarg
import org.apache.log4j.Logger;
38
39 5090 daigle
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlForSingleFile;
40
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlInterface;
41
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlList;
42 5015 daigle
import edu.ucsb.nceas.metacat.database.DBConnection;
43
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
44 5030 daigle
import edu.ucsb.nceas.metacat.properties.PropertyService;
45 5072 daigle
import edu.ucsb.nceas.metacat.service.SessionService;
46 6675 leinfelder
import edu.ucsb.nceas.metacat.util.AuthUtil;
47 5025 daigle
import edu.ucsb.nceas.metacat.util.DocumentUtil;
48 4698 daigle
import edu.ucsb.nceas.metacat.util.MetacatUtil;
49 5072 daigle
import edu.ucsb.nceas.metacat.util.SessionData;
50 4080 daigle
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
51 6675 leinfelder
import edu.ucsb.nceas.metacat.shared.MetacatUtilException;
52 5374 berkley
import edu.ucsb.nceas.metacat.shared.ServiceException;
53 4080 daigle
54 1425 tao
public class PermissionController
55
{
56
   private String docId = null;
57
   private boolean hasSubTreeAccessControl = false; // flag if has a subtree
58
                                                    // access for this docid
59 4861 daigle
   private Vector subTreeList = new Vector();
60 2245 sgarg
61 5098 daigle
   private static final long TOPLEVELSTARTNODEID = 0; //if start node is 0, means it is top
62 1527 tao
                                         //level document
63 2245 sgarg
64 2663 sgarg
   private static Logger logMetacat = Logger.getLogger(PermissionController.class);
65 2245 sgarg
66 1425 tao
   /**
67
    * Constructor for PermissionController
68
    * @param myDocid      the docid need to access
69
    */
70 1434 tao
   public PermissionController(String myDocid) throws McdbException
71 1425 tao
   {
72
     // Get rid of rev number
73 5025 daigle
     docId = DocumentUtil.getSmartDocId(myDocid);
74 2245 sgarg
     //hasSubTreeAccessControl = checkSubTreeAccessControl();
75 1425 tao
   }
76 2245 sgarg
77 1485 tao
   /**
78 2245 sgarg
    * Constructor for PermssionController
79
    * @param myDocid String
80
    * @param needDeleteRev boolean
81
    */
82
   public PermissionController(String myDocid, boolean needDeleteRevFromDocid)
83
   {
84
     if (!needDeleteRevFromDocid)
85
     {
86
       docId = myDocid;
87
     }
88
     else
89
     {
90 5025 daigle
         docId = DocumentUtil.getDocIdFromAccessionNumber(myDocid);
91 2245 sgarg
     }
92
   }
93
94
   /**
95 1485 tao
    * Return if a document has subtree access control
96
    */
97
   public boolean hasSubTreeAccessControl()
98
   {
99
     return hasSubTreeAccessControl;
100
   }
101 2245 sgarg
102 5072 daigle
   public boolean hasPermission(String sessionId, String myPermission) throws SQLException {
103 5374 berkley
       SessionData sessionData = null;
104
       sessionData = SessionService.getInstance().getRegisteredSession(sessionId);
105
       if (sessionData == null) {
106
           return false;
107
       }
108 5072 daigle
109
	   return hasPermission(sessionData.getUserName(), sessionData.getGroupNames(), myPermission);
110
   }
111
112 2245 sgarg
113 1425 tao
  /**
114
    * Check from db connection if at least one of the list of @principals
115 6675 leinfelder
    * Administrators are allowed all permission
116 1425 tao
    * @param user  the user name
117
    * @param groups  the groups which the use is in
118
    * @param myPermission  permission type to check for
119
    */
120 2245 sgarg
  public boolean hasPermission(String user, String[]groups, String myPermission)
121 4950 daigle
                              throws SQLException //, Exception
122 1425 tao
  {
123
    boolean hasPermission=false;
124
    String [] userPackage=null;
125 5742 berkley
    int permission = AccessControlList.intValue(myPermission);
126 2245 sgarg
127 6675 leinfelder
    //for the command line invocation and replication
128 1425 tao
    if ((user==null) && (groups==null || groups.length==0))
129
    {
130
      return true;
131
    }
132 6675 leinfelder
133
    // for administrators
134
    //see http://bugzilla.ecoinformatics.org/show_bug.cgi?id=4728
135
    try {
136
		if (AuthUtil.isAdministrator(user, groups)) {
137
			return true;
138
		}
139
	} catch (MetacatUtilException e) {
140
		// not much we can do here, except treat them as normal
141
		logMetacat.warn("Error checking for administrator: " + e.getMessage(), e);
142
	}
143 2245 sgarg
144 1425 tao
    //create a userpackage including user, public and group member
145
    userPackage=createUsersPackage(user, groups);
146 2245 sgarg
147 1425 tao
    //if the requested document is access documents and requested permission
148
    //is "write", the user should have "all" right
149 2245 sgarg
150 1425 tao
    if (isAccessDocument(docId) && (permission == AccessControlInterface.WRITE))
151
    {
152 2245 sgarg
153 1425 tao
      hasPermission = hasPermission(userPackage,docId, 7);// 7 is all permission
154
    }//if
155
    else //in other situation, just check the request permission
156
    {
157
      // Check for @permission on @docid for @user and/or @groups
158
      hasPermission = hasPermission(userPackage,docId, permission);
159
    }//else
160 2245 sgarg
161 1425 tao
    return hasPermission;
162
  }
163 2245 sgarg
164
165 1425 tao
  /**
166
    * Check from db connection if the users in String array @principals has
167 2245 sgarg
    * @permission on @docid*
168 1425 tao
    * @param principals, names in userPakcage need to check for @permission
169
    * @param docid, document identifier to check on
170 2245 sgarg
    * @param permission, permission (write or all...) to check for
171 1425 tao
    */
172
  private boolean hasPermission(String [] principals, String docId,
173
                                           int permission)
174
                         throws SQLException
175
  {
176 1527 tao
    long startId = TOPLEVELSTARTNODEID;// this is for top level, so startid is 0
177 2245 sgarg
    try
178 1425 tao
    {
179
      //first, if there is a docid owner in user package, return true
180 2245 sgarg
      //because doc owner has all permssion
181 1425 tao
      if (containDocumentOwner(principals, docId))
182
      {
183 2245 sgarg
184 1425 tao
          return true;
185
      }
186 2245 sgarg
187 1425 tao
      //If there is no owner in user package, checking the table
188
      //check perm_order
189 1527 tao
      if (isAllowFirst(principals, docId, startId))
190 1425 tao
      {
191 2245 sgarg
192 1527 tao
        if (hasExplicitDenyRule(principals, docId, permission, startId))
193 1425 tao
        {
194
          //if it is allowfirst and has deny rule(either explicit )
195
          //deny access
196 2245 sgarg
197 1425 tao
          return false;
198
        }//if
199 1527 tao
        else if ( hasAllowRule(principals, docId, permission, startId))
200 1425 tao
        {
201
          //if it is allowfirst and hasn't deny rule and has allow rule
202
          //allow access
203 2245 sgarg
204 1425 tao
          return true;
205
        }//else if
206
        else
207
        {
208
          //other situation deny access
209 2245 sgarg
210 1425 tao
          return false;
211
        }//else
212
     }//if isAllowFirst
213
     else //denyFirst
214
     {
215 1527 tao
       if (hasAllowRule(principals, docId, permission, startId))
216 1425 tao
       {
217
         //if it is denyFirst and has allow rule, allow access
218
         return true;
219
       }
220
       else
221
       {
222
         //if it is denyfirst but no allow rule, deny access
223
         return false;
224
       }
225
     }//else denyfirst
226
    }//try
227
    catch (Exception e)
228
    {
229 5311 daigle
      logMetacat.warn("PermissionController.hasPermission - There is a exception in hasPermission method: "
230 2663 sgarg
                         +e.getMessage());
231 1425 tao
    }
232 2245 sgarg
233 1425 tao
    return false;
234
  }//hasPermission
235 2245 sgarg
236 1425 tao
  /**
237 2245 sgarg
   *  Method to check if a person has permission to a inline data file
238
   * @param user String
239
   * @param groups String[]
240
   * @param myPermission String
241
   * @param inlineDataId String
242
   * @throws McdbException
243
   * @return boolean
244
   */
245
  private boolean hasPermissionForInlineData(String user, String[] groups,
246
                                      String myPermission, String inlineDataId)
247 5298 jones
      throws McdbException
248 2245 sgarg
  {
249
     // this method can call the public method - hasPermission(...)
250
     // the only difference is about the ownership, you couldn't find the owner
251
     // from inlinedataId directly. You should get it from eml document itself
252
     String []userPackage = createUsersPackage(user, groups);
253 5298 jones
     try {
254
        if (containDocumentOwner(userPackage, docId))
255
         {
256
           return true;
257
         }
258
         else
259
         {
260
             PermissionController controller =
261
                                   new PermissionController(inlineDataId, false);
262
             return controller.hasPermission(user, groups, myPermission);
263
         }
264
    } catch (SQLException e) {
265
        throw new McdbException(e.getMessage());
266
    }
267 2245 sgarg
  }
268
269
  /**
270 1485 tao
   * The method to determine of a node can be access by a user just by subtree
271
   * access control
272
   */
273
  public boolean hasPermissionForSubTreeNode(String user, String[] groups,
274
                                             String myPermission, long nodeId)
275
                                             throws McdbException
276
  {
277 1492 tao
    boolean flag = true;
278 1485 tao
    // Get unaccessble subtree for this user
279 4861 daigle
    Hashtable unaccessableSubTree = hasUnaccessableSubTree(user, groups,
280 1485 tao
                                                           myPermission);
281 4861 daigle
    Enumeration en = unaccessableSubTree.elements();
282 1485 tao
    while (en.hasMoreElements())
283
    {
284
      SubTree tree = (SubTree)en.nextElement();
285
      long start = tree.getStartNodeId();
286
      long stop  = tree.getEndNodeId();
287 1492 tao
      // nodeid in unaccessablesubtree, return false
288 1485 tao
      if ( nodeId >= start && nodeId <= stop)
289
      {
290 1492 tao
        flag = false;
291 1485 tao
        break;
292
      }
293
    }
294
    return flag;
295
  }
296
  /**
297 2245 sgarg
   * This method will return a hasTable of subtree which user doesn't has the
298 1434 tao
   * permssion to access
299
   * @param user  the user name
300
   * @param groups  the groups which the use is in
301
   * @param myPermission  permission type to check for
302
   */
303 4861 daigle
  public Hashtable hasUnaccessableSubTree(String user, String[] groups,
304 1434 tao
                                       String myPermission) throws McdbException
305
  {
306 4861 daigle
    Hashtable resultUnaccessableSubTree = new Hashtable();
307 1434 tao
    String [] principals=null;
308
    int permission =AccessControlList.intValue(myPermission);
309 2245 sgarg
310 1434 tao
    //for the commnad line invocation return null(no unaccessable subtree)
311
    if ((user==null) && (groups==null || groups.length==0))
312
    {
313
      return resultUnaccessableSubTree;
314
    }
315 2245 sgarg
316 1434 tao
    //create a userpackage including user, public and group member
317
    principals=createUsersPackage(user, groups);
318
    //for the document owner return null(no unaccessable subtree)
319
    try
320
    {
321
      if (containDocumentOwner(principals, docId))
322
      {
323
       return resultUnaccessableSubTree;
324
      }
325
    }
326
    catch (SQLException ee)
327
    {
328
      throw new McdbException(ee);
329
    }
330 2245 sgarg
331 1434 tao
    // go through every subtree which has access control
332
    for (int i = 0; i< subTreeList.size(); i++)
333
    {
334
      SubTree tree = (SubTree)subTreeList.elementAt(i);
335 1527 tao
      long startId = tree.getStartNodeId();
336 2245 sgarg
337
338 1434 tao
        try
339
        {
340 1527 tao
          if (isAllowFirst(principals, docId, startId))
341 1434 tao
          {
342 2245 sgarg
343 1527 tao
            if (hasExplicitDenyRule(principals, docId, permission, startId ))
344 1434 tao
            {
345 2245 sgarg
346 1434 tao
             //if it is allowfirst and has deny rule
347
              // put the subtree into unaccessable vector
348 1527 tao
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
349 1434 tao
              {
350 1527 tao
                resultUnaccessableSubTree.put(new Long(startId), tree);
351 1434 tao
              }
352
            }//if
353 1527 tao
            else if ( hasAllowRule(principals, docId, permission, startId))
354 1434 tao
            {
355
              //if it is allowfirst and hasn't deny rule and has allow rule
356
              //allow access do nothing
357 2245 sgarg
358 1434 tao
            }//else if
359
            else
360
            {
361
              //other situation deny access
362 1527 tao
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
363 1434 tao
              {
364 1527 tao
                resultUnaccessableSubTree.put(new Long(startId), tree);
365 1434 tao
              }
366 2245 sgarg
367 1434 tao
            }//else
368
          }//if isAllowFirst
369
          else //denyFirst
370
          {
371 1527 tao
            if (hasAllowRule(principals, docId, permission,startId))
372 1434 tao
            {
373
              //if it is denyFirst and has allow rule, allow access, do nothing
374 2245 sgarg
375 1434 tao
            }
376
            else
377
            {
378
              //if it is denyfirst but no allow rule, deny access
379
              // add into vector
380 1527 tao
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
381 1434 tao
              {
382 1527 tao
                resultUnaccessableSubTree.put(new Long(startId), tree);
383 1434 tao
              }
384
            }
385
          }//else denyfirst
386
        }//try
387
        catch( Exception e)
388
        {
389 5311 daigle
          logMetacat.error("PermissionController.hasUnaccessableSubTree - error in PermissionControl.has" +
390 2663 sgarg
                                   "UnaccessableSubTree "+e.getMessage());
391 1434 tao
          throw new McdbException(e);
392
        }
393 2245 sgarg
394 1434 tao
    }//for
395 2245 sgarg
    // merge the subtree if a subtree is another subtree'subtree
396 1521 tao
    resultUnaccessableSubTree = mergeEquivalentSubtree(resultUnaccessableSubTree);
397 1434 tao
    return resultUnaccessableSubTree;
398
  }//hasUnaccessableSubtree
399 2245 sgarg
400
401
  /*
402 1513 tao
   * A method to merge nested subtree into bigger one. For example subtree b
403
   * is a subtree of subtree a. And user doesn't have read permission for both
404
   * so we only use subtree a is enough.
405
   */
406 4861 daigle
  private Hashtable mergeEquivalentSubtree(Hashtable unAccessSubTree)
407 1513 tao
  {
408 4861 daigle
    Hashtable newSubTreeHash = new Hashtable();
409 1513 tao
    boolean   needDelete = false;
410
    // check the parameters
411
    if (unAccessSubTree == null || unAccessSubTree.isEmpty())
412
    {
413
      return newSubTreeHash;
414
    }
415
    else
416
    {
417
      // look every subtree start point and stop point, to see if it is embedded
418
      // in another one. If embedded, they are equavelent and we can use bigger
419
      // one to replace smaller one
420 4861 daigle
      Enumeration en = unAccessSubTree.elements();
421 1513 tao
      while (en.hasMoreElements())
422
      {
423
        SubTree tree    = (SubTree)en.nextElement();
424
        String  treeId  = tree.getSubTreeId();
425
        long    startId = tree.getStartNodeId();
426
        long    endId   = tree.getEndNodeId();
427 2245 sgarg
428 4861 daigle
        Enumeration enu = unAccessSubTree.elements();
429 1513 tao
        while (enu.hasMoreElements())
430
        {
431
          SubTree subTree = (SubTree)enu.nextElement();
432 4861 daigle
          String subTreeId= subTree.getSubTreeId();
433 1513 tao
          long   subTreeStartId = subTree.getStartNodeId();
434
          long   subTreeEndId   = subTree.getEndNodeId();
435
          //compare and if the first subtree is a subtree of the second
436
          // one, set neeDelete true
437
          if (startId > subTreeStartId && endId < subTreeEndId)
438
          {
439
            needDelete = true;
440 5311 daigle
            logMetacat.info("PermissionController.mergeEquivalentSubtree - the subtree: "+ treeId +
441 1513 tao
                                     " need to be get rid of from unaccessable"+
442
                                     " subtree list becuase it is a subtree of"+
443 2663 sgarg
                                     " another subtree in the list");
444 1513 tao
            break;
445
          }//if
446
        }//while
447
        // if not need to delete, put the subtree into hash
448
        if (!needDelete)
449
        {
450 1527 tao
          newSubTreeHash.put(new Long(startId), tree);
451 1513 tao
        }
452
        //reset needDelete
453
        needDelete = false;
454
      }//while
455
      return newSubTreeHash;
456
    }//else
457
  }
458 2245 sgarg
459 1434 tao
  /**
460 4080 daigle
	 * Check if a document id is a access document. Access document need user
461
	 * has "all" permission to access it.
462
	 *
463
	 * @param docId,
464
	 *            the document id need to be checked
465
	 */
466
	private boolean isAccessDocument(String docId) throws SQLException {
467
		// detele the rev number if docid contains it
468 5025 daigle
		docId = DocumentUtil.getDocIdFromString(docId);
469 4080 daigle
		PreparedStatement pStmt = null;
470
		DBConnection conn = null;
471
		int serialNumber = -1;
472
		try {
473
			// check out DBConnection
474
			conn = DBConnectionPool.getDBConnection("PermissionControl.isAccessDoc");
475
			serialNumber = conn.getCheckOutSerialNumber();
476 6595 leinfelder
			pStmt = conn.prepareStatement("select doctype from xml_documents where docid like ? ");
477
			pStmt.setString(1, docId);
478 4080 daigle
			pStmt.execute();
479
			ResultSet rs = pStmt.getResultSet();
480
			boolean hasRow = rs.next();
481
			String doctype = null;
482
			if (hasRow) {
483
				doctype = rs.getString(1);
484 2245 sgarg
485 4080 daigle
			}
486
			pStmt.close();
487 2245 sgarg
488 4080 daigle
			// if it is an access document
489
			if (doctype != null
490 4698 daigle
					&& ((MetacatUtil.getOptionList(PropertyService
491 4213 daigle
							.getProperty("xml.accessdoctype")).contains(doctype)))) {
492 2245 sgarg
493 4080 daigle
				return true;
494
			}
495 2245 sgarg
496 4080 daigle
		} catch (SQLException e) {
497
			throw new SQLException("PermissionControl.isAccessDocument "
498
					+ "Error checking" + " on document " + docId + ". " + e.getMessage());
499
		} catch (PropertyNotFoundException pnfe) {
500
			throw new SQLException("PermissionControl.isAccessDocument "
501
					+ "Error checking" + " on document " + docId + ". " + pnfe.getMessage());
502
		} finally {
503
			try {
504
				pStmt.close();
505
			} finally {
506
				DBConnectionPool.returnDBConnection(conn, serialNumber);
507
			}
508
		}
509 2245 sgarg
510 4080 daigle
		return false;
511
	}// isAccessDocument
512 2245 sgarg
513
514
515 1425 tao
  /**
516 4080 daigle
	 * Check if a stirng array contains a given documents' owner
517
	 *
518
	 * @param principals,
519
	 *            a string array storing the username, groups name and public.
520
	 * @param docid,
521
	 *            the id of given documents
522
	 */
523 1434 tao
  private boolean containDocumentOwner( String[] principals, String docId)
524 1425 tao
                    throws SQLException
525
  {
526
    int lengthOfArray=principals.length;
527 2245 sgarg
    boolean hasRow;
528 1425 tao
    PreparedStatement pStmt=null;
529
    DBConnection conn = null;
530
    int serialNumber = -1;
531 2245 sgarg
532 1425 tao
    try
533
    {
534
      //check out DBConnection
535 1434 tao
     conn=DBConnectionPool.getDBConnection("PermissionControl.containDocOnwer");
536 1425 tao
      serialNumber=conn.getCheckOutSerialNumber();
537
      pStmt = conn.prepareStatement(
538
                "SELECT 'x' FROM xml_documents " +
539 6196 leinfelder
                "WHERE docid = ? AND lower(user_owner) = ? " +
540
                "UNION ALL " +
541
                "SELECT 'x' FROM xml_revisions " +
542
                "WHERE docid = ? AND lower(user_owner) = ? ");
543 1425 tao
      //check every element in the string array too see if it conatains
544
      //the owner of document
545
      for (int i=0; i<lengthOfArray; i++)
546
      {
547 2245 sgarg
548 1425 tao
        // Bind the values to the query
549
        pStmt.setString(1, docId);
550
        pStmt.setString(2, principals[i]);
551 6196 leinfelder
        pStmt.setString(3, docId);
552
        pStmt.setString(4, principals[i]);
553 5311 daigle
        logMetacat.info("PermissionController.containDocumentOwner - the principle stack is : " +
554 2663 sgarg
                                  principals[i]);
555 1425 tao
556
        pStmt.execute();
557
        ResultSet rs = pStmt.getResultSet();
558
        hasRow = rs.next();
559 2245 sgarg
        if (hasRow)
560 1425 tao
        {
561
          pStmt.close();
562 5311 daigle
           logMetacat.info("PermissionController.containDocumentOwner - find the owner");
563 1425 tao
          return true;
564 2245 sgarg
        }//if
565
566 1425 tao
      }//for
567
    }//try
568 2245 sgarg
    catch (SQLException e)
569 1425 tao
    {
570
        pStmt.close();
571 2245 sgarg
572
        throw new
573 5099 daigle
        SQLException("PermissionControl.hasPermission - " +
574 1425 tao
                     "Error checking ownership for " + principals[0] +
575
                     " on document #" + docId + ". " + e.getMessage());
576
    }//catch
577
    finally
578
    {
579
      try
580
      {
581
        pStmt.close();
582
      }
583
      finally
584
      {
585
        DBConnectionPool.returnDBConnection(conn, serialNumber);
586
      }
587
    }
588 2245 sgarg
    return false;
589 1425 tao
  }//containDocumentOwner
590 2245 sgarg
591 1425 tao
  /**
592
    * Check if the permission order for user at that documents is allowFirst
593 2245 sgarg
    * @param principals, list of names of principals to check for
594 1425 tao
    * @param docid, document identifier to check for
595
    */
596 2245 sgarg
  private boolean isAllowFirst(String [] principals, String docId,
597 1527 tao
                               long startId)
598 1425 tao
                  throws SQLException, Exception
599
  {
600
    int lengthOfArray=principals.length;
601
    boolean hasRow;
602
    PreparedStatement pStmt = null;
603
    DBConnection conn = null;
604
    int serialNumber = -1;
605 1434 tao
    String sql = null;
606
    boolean topLever =false;
607 1527 tao
    if (startId == TOPLEVELSTARTNODEID)
608 1434 tao
    {
609
      //top level
610
      topLever = true;
611
      sql = "SELECT perm_order FROM xml_access " +
612 2045 tao
    "WHERE lower(principal_name) = ? AND docid = ? AND startnodeid is NULL";
613 1434 tao
    }
614
    else
615
    {
616
      //sub tree level
617
      sql = "SELECT perm_order FROM xml_access " +
618 2045 tao
        "WHERE lower(principal_name)= ? AND docid = ? AND startnodeid = ?";
619 1434 tao
    }
620 2245 sgarg
621 1425 tao
    try
622
    {
623
      //check out DBConnection
624
      conn=DBConnectionPool.getDBConnection("AccessControlList.isAllowFirst");
625
      serialNumber=conn.getCheckOutSerialNumber();
626 2245 sgarg
627 1425 tao
      //select permission order from database
628 1434 tao
      pStmt = conn.prepareStatement(sql);
629 2245 sgarg
630 1425 tao
      //check every name in the array
631
      for (int i=0; i<lengthOfArray;i++)
632
      {
633
        //bind value
634
        pStmt.setString(1, principals[i]);//user name
635
        pStmt.setString(2, docId);//docid
636 2245 sgarg
637
        // if subtree, we need set subtree id
638 1434 tao
        if (!topLever)
639
        {
640 1527 tao
          pStmt.setLong(3, startId);
641 1434 tao
        }
642 2245 sgarg
643 1425 tao
        pStmt.execute();
644
        ResultSet rs = pStmt.getResultSet();
645
        hasRow=rs.next();
646
        if (hasRow)
647
        {
648
          //get the permission order from data base
649
          String permissionOrder=rs.getString(1);
650
          //if the permission order is "allowFirst
651
          if (permissionOrder.equalsIgnoreCase(AccessControlInterface.ALLOWFIRST))
652
          {
653
            pStmt.close();
654
            return true;
655
          }
656
          else
657
          {
658
            pStmt.close();
659
            return false;
660
          }
661
        }//if
662
      }//for
663
    }//try
664
    catch (SQLException e)
665
    {
666
      throw e;
667
    }
668
    finally
669
    {
670
      try
671
      {
672
        pStmt.close();
673
      }
674
      finally
675
      {
676
        DBConnectionPool.returnDBConnection(conn, serialNumber);
677
      }
678
    }
679 2245 sgarg
680
    //if reach here, means there is no permssion record for given names and
681 1425 tao
    //docid. So throw a exception.
682 2245 sgarg
683 5099 daigle
    throw new Exception("PermissionController.isAllowFirst - There is no permission record for user "+ principals[0] +
684
                        " at document " + docId);
685 2245 sgarg
686 1425 tao
  }//isAllowFirst
687 2245 sgarg
688 1425 tao
  /**
689 2245 sgarg
    * Check if the users array has allow rules for given users, docid and
690 1425 tao
    * permission.
691
    * If it has permission rule and ticket count is greater than 0, the ticket
692
    * number will decrease one for every allow rule
693 2245 sgarg
    * @param principals, list of names of principals to check for
694 1425 tao
    * @param docid, document identifier to check for
695
    * @param permission, the permssion need to check
696
    */
697 2245 sgarg
  private boolean hasAllowRule(String [] principals, String docId,
698 1527 tao
                                  int permission, long startId)
699 1425 tao
                  throws SQLException, Exception
700
 {
701
   int lengthOfArray=principals.length;
702
   boolean allow=false;//initial value is no allow rule
703
   ResultSet rs;
704
   PreparedStatement pStmt = null;
705
   int permissionValue=permission;
706
   int permissionValueInTable;
707 4861 daigle
   int ticketCount;
708 1425 tao
   DBConnection conn = null;
709
   int serialNumber = -1;
710 1434 tao
   boolean topLever = false;
711
   String sql = null;
712 1527 tao
   if (startId == TOPLEVELSTARTNODEID)
713 1434 tao
   {
714
     // for toplevel
715
     topLever = true;
716 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
717 2045 tao
   "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid is NULL";
718 1434 tao
   }
719
   else
720
   {
721
     topLever =false;
722 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
723 2045 tao
      "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid = ?";
724 1434 tao
   }
725 1425 tao
   try
726
   {
727
     //check out DBConnection
728
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasAllowRule");
729
     serialNumber=conn.getCheckOutSerialNumber();
730 2245 sgarg
    //This sql statement will select entry with
731 1425 tao
    //begin_time<=currentTime<=end_time in xml_access table
732
    //If begin_time or end_time is null in table, isnull(begin_time, sysdate)
733
    //function will assign begin_time=sysdate
734 1434 tao
    pStmt = conn.prepareStatement(sql);
735 1425 tao
    //bind docid, perm_type
736
    pStmt.setString(1, docId);
737
    pStmt.setString(3, AccessControlInterface.ALLOW);
738 2245 sgarg
739 1434 tao
    // if subtree lever, need to set subTreeId
740
    if (!topLever)
741
    {
742 1527 tao
      pStmt.setLong(4, startId);
743 1434 tao
    }
744 2245 sgarg
745 1425 tao
    //bind every elenment in user name array
746
    for (int i=0;i<lengthOfArray; i++)
747
    {
748
      pStmt.setString(2, principals[i]);
749
      pStmt.execute();
750
      rs=pStmt.getResultSet();
751
      while (rs.next())//check every entry for one user
752
      {
753
        permissionValueInTable=rs.getInt(1);
754 2245 sgarg
755
        //permission is ok
756 1425 tao
        //the user have a permission to access the file
757
        if (( permissionValueInTable & permissionValue )== permissionValue )
758
        {
759 2245 sgarg
760 1425 tao
           allow=true;//has allow rule entry
761
        }//if
762
      }//while
763
    }//for
764
   }//try
765
   catch (SQLException sqlE)
766
   {
767
     throw sqlE;
768
   }
769
   catch (Exception e)
770
   {
771
     throw e;
772
   }
773
   finally
774
   {
775
     try
776
     {
777
       pStmt.close();
778
     }
779
     finally
780
     {
781
       DBConnectionPool.returnDBConnection(conn, serialNumber);
782
     }
783
   }
784
    return allow;
785
 }//hasAllowRule
786 2245 sgarg
787
788
789 1425 tao
   /**
790 2245 sgarg
    * Check if the users array has explicit deny rules for given users, docid
791 1425 tao
    * and permission. That means the perm_type is deny and current time is
792
    * less than end_time and greater than begin time, or no time limit.
793 2245 sgarg
    * @param principals, list of names of principals to check for
794 1425 tao
    * @param docid, document identifier to check for
795
    * @param permission, the permssion need to check
796
    */
797 2245 sgarg
  private boolean hasExplicitDenyRule(String [] principals, String docId,
798 1527 tao
                                      int permission, long startId)
799 1425 tao
                  throws SQLException
800
 {
801
   int lengthOfArray=principals.length;
802
   ResultSet rs;
803
   PreparedStatement pStmt = null;
804
   int permissionValue=permission;
805
   int permissionValueInTable;
806
   DBConnection conn = null;
807
   int serialNumber = -1;
808 1434 tao
   String sql = null;
809
   boolean topLevel = false;
810 2245 sgarg
811 1434 tao
   // decide top level or subtree level
812 1527 tao
   if (startId == TOPLEVELSTARTNODEID)
813 1434 tao
   {
814
     topLevel = true;
815 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
816 2045 tao
    "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid is NULL";
817 1434 tao
   }
818
   else
819
   {
820
     topLevel = false;
821 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
822 2045 tao
     "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid = ?";
823 1434 tao
   }
824 2245 sgarg
825 1425 tao
   try
826
   {
827
     //check out DBConnection
828 1434 tao
     conn=DBConnectionPool.getDBConnection("PermissionControl.hasExplicitDeny");
829 1425 tao
     serialNumber=conn.getCheckOutSerialNumber();
830 2245 sgarg
831 1434 tao
     pStmt = conn.prepareStatement(sql);
832 1425 tao
    //bind docid, perm_type
833
    pStmt.setString(1, docId);
834
    pStmt.setString(3, AccessControlInterface.DENY);
835 2245 sgarg
836 1434 tao
    // subtree level need to set up subtreeid
837
    if (!topLevel)
838
    {
839 1527 tao
      pStmt.setLong(4, startId);
840 1434 tao
    }
841 2245 sgarg
842 1425 tao
    //bind every elenment in user name array
843
    for (int i=0;i<lengthOfArray; i++)
844
    {
845
      pStmt.setString(2, principals[i]);
846
      pStmt.execute();
847
      rs=pStmt.getResultSet();
848
      while (rs.next())//check every entry for one user
849
      {
850
        permissionValueInTable=rs.getInt(1);
851 2245 sgarg
852 1425 tao
        //permission is ok the user doesn't have permission to access the file
853
        if (( permissionValueInTable & permissionValue )== permissionValue )
854 2245 sgarg
855 1425 tao
        {
856
           pStmt.close();
857
           return true;
858
         }//if
859
      }//while
860
    }//for
861
   }//try
862
   catch (SQLException e)
863
   {
864
     throw e;
865
   }//catch
866
   finally
867
   {
868
     try
869
     {
870
       pStmt.close();
871
     }
872
     finally
873
     {
874
       DBConnectionPool.returnDBConnection(conn, serialNumber);
875
     }
876
   }//finally
877
   return false;//no deny rule
878 2245 sgarg
  }//hasExplicitDenyRule
879 1425 tao
880 2245 sgarg
881 1425 tao
  /**
882
    * Creat a users pakages to check permssion rule, user itself, public and
883
    * the gourps the user belong will be include in this package
884
    * @param user, the name of user
885
    * @param groups, the string array of the groups that user belong to
886
    */
887
  private String[] createUsersPackage(String user, String [] groups)
888
  {
889
    String [] usersPackage=null;
890
    int lengthOfPackage;
891 2245 sgarg
892 1425 tao
    if (groups!=null)
893
    {
894 2245 sgarg
      //if gouprs is not null and user is not public, we should create a array
895
      //to store the groups and user and public.
896 1425 tao
      //So the length of userPackage is the length of group plus two
897
      if (!user.equalsIgnoreCase(AccessControlInterface.PUBLIC))
898
      {
899
        lengthOfPackage=(groups.length)+2;
900
        usersPackage=new String [lengthOfPackage];
901
        //the first two elements is user self and public
902 2045 tao
        //in order to ignore case sensitive, we transfer user to lower case
903
        if (user != null)
904
        {
905
          usersPackage[0]= user.toLowerCase();
906 5311 daigle
          logMetacat.info("PermissionController.createUsersPackage - after transfer to lower case(not null): "+
907 2663 sgarg
                                     usersPackage[0]);
908 2045 tao
        }
909
        else
910
        {
911
          usersPackage[0] = user;
912
          usersPackage[0]= user.toLowerCase();
913 5311 daigle
          logMetacat.info("PermissionController.createUsersPackage - after transfer to lower case(null): "+
914 2663 sgarg
                                     usersPackage[0]);
915 2045 tao
        }
916 1425 tao
        usersPackage[1]=AccessControlInterface.PUBLIC;
917
        //put groups element from index 0 to lengthOfPackage-3 into userPackage
918
        //from index 2 to lengthOfPackage-1
919
        for (int i=2; i<lengthOfPackage; i++)
920
        {
921 2045 tao
          //tansfer group to lower case too
922
          if (groups[i-2] != null)
923
          {
924
            usersPackage[i]=groups[i-2].toLowerCase();
925
          }
926 1425 tao
        } //for
927
      }//if user!=public
928
      else//use=public
929
      {
930
        lengthOfPackage=(groups.length)+1;
931
        usersPackage=new String [lengthOfPackage];
932
        //the first lements is public
933
        usersPackage[0]=AccessControlInterface.PUBLIC;
934
        //put groups element from index 0 to lengthOfPackage-2 into userPackage
935
        //from index 1 to lengthOfPackage-1
936
        for (int i=1; i<lengthOfPackage; i++)
937
        {
938 2045 tao
          if (groups[i-1] != null)
939
          {
940
            usersPackage[i]=groups[i-1].toLowerCase();
941
          }
942 1425 tao
        } //for
943
      }//else user=public
944 2245 sgarg
945 1425 tao
    }//if groups!=null
946
    else
947
    {
948
      //because no groups, the userPackage only need two elements
949
      //one is for user, the other is for public
950
      if (!user.equalsIgnoreCase(AccessControlInterface.PUBLIC))
951
      {
952
        lengthOfPackage=2;
953
        usersPackage=new String [lengthOfPackage];
954 2045 tao
        if (user != null)
955
        {
956
          usersPackage[0]=user.toLowerCase();
957
        }
958
        else
959
        {
960
          usersPackage[0]=user;
961
        }
962 1425 tao
        usersPackage[1]=AccessControlInterface.PUBLIC;
963
      }//if user!=public
964
      else //user==public
965
      {
966
        //only put public into array
967
        lengthOfPackage=1;
968
        usersPackage=new String [lengthOfPackage];
969
        usersPackage[0]=AccessControlInterface.PUBLIC;
970
      }
971
    }//else groups==null
972
    return usersPackage;
973
  }//createUsersPackage
974 2245 sgarg
975
976 1425 tao
  /**
977 2245 sgarg
   * A static method to get Hashtable which cointains a inlinedata object list that
978
   * user can't read it. The key is subtree id of inlinedata, the data is
979
   * internal file name for the inline data which is stored as docid
980
   * in xml_access table or data object doc id.
981
   * @param docidWithoutRev, metadata docid which should be the accessfileid
982
   *                         in the table
983
   * @param user , the name of user
984
   * @param groups, the group which the user belong to
985 1425 tao
   */
986 4466 daigle
   public static Hashtable<String, String> getUnReadableInlineDataIdList(String docidWithoutRev,
987 2291 sgarg
                                                   String user, String[] groups,
988
                                                   boolean withRevision)
989 5298 jones
                                                throws McdbException
990 2245 sgarg
   {
991 4466 daigle
     Hashtable<String, String> inlineDataList = getUnAccessableInlineDataIdList(docidWithoutRev,
992 2291 sgarg
                              user, groups, AccessControlInterface.READSTRING,
993
                              withRevision);
994 2245 sgarg
995
     return inlineDataList;
996
   }
997
998
   /**
999
  * A static method to get Hashtable which cointains a inline  data object list that
1000
  * user can't overwrite it. The key is subtree id of inline data distrubition,
1001
  * the value is internal file name for the inline data which is stored as docid
1002
  * in xml_access table or data object doc id.
1003
  * @param docidWithoutRev, metadata docid which should be the accessfileid
1004
  *                         in the table
1005
  * @param user , the name of user
1006
  * @param groups, the group which the user belong to
1007
  */
1008 4466 daigle
  public static Hashtable<String, String> getUnWritableInlineDataIdList(String docidWithoutRev,
1009 2291 sgarg
                                                  String user, String[] groups,
1010
                                                  boolean withRevision)
1011 2245 sgarg
                                               throws Exception
1012 1425 tao
  {
1013 4466 daigle
    Hashtable<String, String> inlineDataList = getUnAccessableInlineDataIdList(docidWithoutRev,
1014 2291 sgarg
                            user, groups, AccessControlInterface.WRITESTRING,
1015
                            withRevision);
1016 2245 sgarg
1017
    return inlineDataList;
1018
  }
1019
1020
1021
   /*
1022
    * This method will get hashtable which contains a unaccessable distribution
1023
    * inlinedata object list
1024 2291 sgarg
    *
1025
    * withRevision is used to get inline id list with or without revision number
1026
    * e.g. when withRevision is true, temp.1.1.1, temp.1.1.2 would be returned
1027
    * otherwise temp.1.1 and temp.1.2 would be returned.
1028 2245 sgarg
    */
1029 4466 daigle
   private static Hashtable<String, String> getUnAccessableInlineDataIdList(String docid,
1030 2291 sgarg
                               String user, String[] groups, String permission,
1031
                               boolean withRevision)
1032 5298 jones
                             throws McdbException
1033 2245 sgarg
   {
1034 5298 jones
       Hashtable<String, String> unAccessibleIdList = new Hashtable();
1035
       if (user == null) {
1036
           return unAccessibleIdList;
1037
       }
1038
1039
       Hashtable allIdList;
1040
       try {
1041
           allIdList = getAllInlineDataIdList(docid);
1042
       } catch (SQLException e) {
1043
           throw new McdbException(e.getMessage());
1044
       }
1045
       Enumeration<String> en = allIdList.keys();
1046 2245 sgarg
      while (en.hasMoreElements())
1047 1425 tao
      {
1048 2245 sgarg
        String subTreeId = (String) en.nextElement();
1049
        String fileId = (String) allIdList.get(subTreeId);
1050
        //Here fileid is internal file id for line data. It stored in docid
1051
        // field in xml_access table. so we don't need to delete rev
1052
        PermissionController controller = new PermissionController(docid, false);
1053
        if (!controller.hasPermissionForInlineData(user, groups, permission, fileId))
1054
        {
1055 2291 sgarg
            if(withRevision)
1056
            {
1057 5311 daigle
                logMetacat.info("PermissionController.getUnAccessableInlineDataIdList - Put subtree id " + subTreeId +
1058 2291 sgarg
                                         " and " + "inline data file name " +
1059
                                         fileId + " into " + "un" + permission +
1060 2663 sgarg
                                         " hash");
1061 4466 daigle
                unAccessibleIdList.put(subTreeId, fileId);
1062 2291 sgarg
1063
            }
1064
            else
1065
            {
1066 5311 daigle
                logMetacat.info("PermissionController.getUnAccessableInlineDataIdList - Put subtree id " + subTreeId +
1067 2291 sgarg
                                         " and " + "inline data file name " +
1068 5025 daigle
                                         DocumentUtil.getInlineDataIdWithoutRev(fileId) +
1069 2291 sgarg
                                         " into " + "un" + permission +
1070 2663 sgarg
                                         " hash");
1071 5025 daigle
                unAccessibleIdList.put(subTreeId,
1072
                		DocumentUtil.getInlineDataIdWithoutRev(fileId));
1073 2291 sgarg
            }
1074 2245 sgarg
        }
1075 1425 tao
      }
1076 4466 daigle
      return unAccessibleIdList;
1077 2245 sgarg
   }
1078
1079
1080
   /*
1081
    * This method will get a hash table from xml_access table for all records
1082
    * about the inline data. The key is subtree id and data is a inline internal
1083
    * file name
1084
    */
1085 4861 daigle
   private static Hashtable getAllInlineDataIdList(String docid) throws SQLException
1086 2245 sgarg
   {
1087 4861 daigle
     Hashtable inlineDataList = new Hashtable();
1088 2245 sgarg
     String sql = "SELECT subtreeid, docid FROM xml_access WHERE " +
1089
                   "accessfileid = ? AND subtreeid  IS NOT NULL";
1090
     PreparedStatement pStmt=null;
1091
     ResultSet rs=null;
1092
     DBConnection conn=null;
1093
     int serialNumber=-1;
1094
     try
1095
     {
1096
       //check out DBConnection
1097
       conn=DBConnectionPool.getDBConnection("PermissionControl.getDataSetId");
1098
       serialNumber=conn.getCheckOutSerialNumber();
1099
       pStmt=conn.prepareStatement(sql);
1100
       //bind the value to query
1101
       pStmt.setString(1, docid);
1102
       //execute the query
1103
       pStmt.execute();
1104
       rs=pStmt.getResultSet();
1105
       //process the result
1106
       while(rs.next())
1107
       {
1108
         String subTreeId = rs.getString(1);
1109
         String inlineDataId = rs.getString(2);
1110
         if (subTreeId != null && !subTreeId.trim().equals("") &&
1111
            inlineDataId != null && !inlineDataId.trim().equals(""))
1112
         {
1113
           inlineDataList.put(subTreeId, inlineDataId);
1114
         }
1115
      }//while
1116
     }//try
1117
     finally
1118
     {
1119
       try
1120
       {
1121
         pStmt.close();
1122
       }
1123
       finally
1124
       {
1125
         DBConnectionPool.returnDBConnection(conn, serialNumber);
1126
       }
1127
     }//finally
1128
     return inlineDataList;
1129
   }//getAllInlineDataIdList
1130 1425 tao
}