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