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