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