Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A class that handles checking permssision for a document
4
               and subtree in a document 
5
 *             
6
 *  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: tao $'
12
 *     '$Date: 2003-04-11 09:23:17 -0700 (Fri, 11 Apr 2003) $'
13
 * '$Revision: 1541 $'
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
 
31
import java.sql.*;
32
import java.util.Enumeration;
33
import java.util.Hashtable;
34
import java.util.Stack;
35
import java.util.Vector;
36

    
37
public class PermissionController
38
{
39
   private String docId = null;
40
   private boolean hasSubTreeAccessControl = false; // flag if has a subtree
41
                                                    // access for this docid
42
   private Vector subTreeList = new Vector();
43
   
44
   private long TOPLEVELSTARTNODEID = 0; //if start node is 0, means it is top
45
                                         //level document
46
   
47
   
48
   /**
49
    * Constructor for PermissionController
50
    * @param myDocid      the docid need to access
51
    */
52
   public PermissionController(String myDocid) throws McdbException
53
   {
54
     // Get rid of rev number
55
     docId = MetaCatUtil.getDocIdFromString(myDocid);
56
     hasSubTreeAccessControl = checkSubTreeAccessControl();
57
   }
58
   
59
   /**
60
    * Return if a document has subtree access control
61
    */
62
   public boolean hasSubTreeAccessControl()
63
   {
64
     return hasSubTreeAccessControl;
65
   }
66
   
67
   /*
68
    * Go through the access table and find if has subtree access control
69
    * if has, store the subtree into list and return true. Otherwise, 
70
    * return false
71
    */
72
  private boolean checkSubTreeAccessControl() throws McdbException
73
  {
74
    boolean flag = false;
75
    PreparedStatement pStmt=null;
76
    ResultSet rs=null;
77
    DBConnection conn=null;
78
    int serialNumber=-1;
79
    String query="SELECT subtreeid, startnodeid, endnodeid from xml_access " +
80
                 "where docid =? ";
81
    
82
    try
83
    {
84
      //check out DBConnection
85
      conn=DBConnectionPool.getDBConnection("PermissionController.hasSubTreeA");
86
      serialNumber=conn.getCheckOutSerialNumber();
87
      
88
      pStmt=conn.prepareStatement(query);
89
      //bind the value to query
90
      pStmt.setString(1, docId);
91
      //execute the query
92
      pStmt.execute();
93
      rs=pStmt.getResultSet();
94
      //process the result
95
      while (rs.next()) //
96
      {
97
        String subTreeId = rs.getString(1);
98
        MetaCatUtil.debugMessage("subtreeid: "+subTreeId, 35);
99
        long startNodeId = rs.getLong(2);
100
        MetaCatUtil.debugMessage("subtree startNodeId: "+startNodeId, 35);
101
        long endNodeId = rs.getLong(3);
102
        MetaCatUtil.debugMessage("subtree endNodeId: "+endNodeId, 35);
103
        // if startnodeid field in table is empty,startNodeId will be 0
104
        if (subTreeId != null && startNodeId != 0 && startNodeId != 0)
105
        {
106
          flag = true;// has subtree control
107
          SubTree tree = new SubTree();
108
          tree.setSubTreeId(subTreeId);
109
          tree.setStartNodeId(startNodeId);
110
          tree.setEndNodeId(endNodeId);
111
          subTreeList.add(tree);
112
         }
113
      }
114
    }//try
115
    catch (SQLException e)
116
    {
117
      throw new McdbException(e);
118
    }
119
    finally
120
    {
121
      try
122
      {
123
        pStmt.close();
124
      }
125
      catch(SQLException ee)
126
      {
127
        throw new McdbException(ee);
128
      }
129
      finally
130
      {
131
        DBConnectionPool.returnDBConnection(conn, serialNumber);
132
      }
133
    }
134
    return flag;
135
  }
136
   
137
  /**
138
    * Check from db connection if at least one of the list of @principals
139
    * @param user  the user name
140
    * @param groups  the groups which the use is in
141
    * @param myPermission  permission type to check for
142
    */
143
  public boolean hasPermission(String user, String[]groups, String myPermission) 
144
                              throws SQLException, Exception
145
  {
146
    boolean hasPermission=false;
147
    String [] userPackage=null;
148
    int permission =AccessControlList.intValue(myPermission);
149
       
150
    //for the commnad line invocation
151
    if ((user==null) && (groups==null || groups.length==0))
152
    {
153
      return true;
154
    }
155
   
156
    //create a userpackage including user, public and group member
157
    userPackage=createUsersPackage(user, groups);
158
    
159
    //if the requested document is access documents and requested permission
160
    //is "write", the user should have "all" right
161
    
162
    if (isAccessDocument(docId) && (permission == AccessControlInterface.WRITE))
163
    {
164
      
165
      hasPermission = hasPermission(userPackage,docId, 7);// 7 is all permission
166
    }//if
167
    else //in other situation, just check the request permission
168
    {
169
    
170
      
171
      // Check for @permission on @docid for @user and/or @groups
172
      hasPermission = hasPermission(userPackage,docId, permission);
173
     
174
    }//else
175
    
176
    return hasPermission;
177
  }
178
  
179
 
180
  /**
181
    * Check from db connection if the users in String array @principals has
182
    * @permission on @docid* 
183
    * @param principals, names in userPakcage need to check for @permission
184
    * @param docid, document identifier to check on
185
    * @param permission, permission (write or all...) to check for 
186
    */
187
  private boolean hasPermission(String [] principals, String docId,
188
                                           int permission)
189
                         throws SQLException
190
  {
191
    long startId = TOPLEVELSTARTNODEID;// this is for top level, so startid is 0
192
    try 
193
    {
194
      //first, if there is a docid owner in user package, return true
195
      //because doc owner has all permssion 
196
      if (containDocumentOwner(principals, docId))
197
      {
198
          
199
          return true;
200
      }
201
      
202
      //If there is no owner in user package, checking the table
203
      //check perm_order
204
      if (isAllowFirst(principals, docId, startId))
205
      {
206
        
207
        if (hasExplicitDenyRule(principals, docId, permission, startId))
208
        {
209
          //if it is allowfirst and has deny rule(either explicit )
210
          //deny access
211
         
212
          return false;
213
        }//if
214
        else if ( hasAllowRule(principals, docId, permission, startId))
215
        {
216
          //if it is allowfirst and hasn't deny rule and has allow rule
217
          //allow access
218
          
219
          return true;
220
        }//else if
221
        else
222
        {
223
          //other situation deny access
224
         
225
          return false;
226
        }//else
227
     }//if isAllowFirst
228
     else //denyFirst
229
     {
230
       if (hasAllowRule(principals, docId, permission, startId))
231
       {
232
         //if it is denyFirst and has allow rule, allow access
233
         return true;
234
       }
235
       else
236
       {
237
         //if it is denyfirst but no allow rule, deny access
238
         return false;
239
       }
240
     }//else denyfirst
241
    }//try
242
    catch (Exception e)
243
    {
244
      MetaCatUtil.debugMessage("There is a exception in hasPermission method: "
245
                         +e.getMessage(), 50);
246
    }
247
   
248
    return false;
249
  }//hasPermission
250
  
251
  /**
252
   * The method to determine of a node can be access by a user just by subtree
253
   * access control
254
   */
255
  public boolean hasPermissionForSubTreeNode(String user, String[] groups,
256
                                             String myPermission, long nodeId)
257
                                             throws McdbException
258
  {
259
    boolean flag = true;
260
    // Get unaccessble subtree for this user
261
    Hashtable unaccessableSubTree = hasUnaccessableSubTree(user, groups, 
262
                                                           myPermission);
263
    Enumeration en = unaccessableSubTree.elements();
264
    while (en.hasMoreElements())
265
    {
266
      SubTree tree = (SubTree)en.nextElement();
267
      long start = tree.getStartNodeId();
268
      long stop  = tree.getEndNodeId();
269
      // nodeid in unaccessablesubtree, return false
270
      if ( nodeId >= start && nodeId <= stop)
271
      {
272
        flag = false;
273
        break;
274
      }
275
    }
276
    return flag;
277
  }
278
  /**
279
   * This method will return a hasTable of subtree which user doesn't has the 
280
   * permssion to access
281
   * @param user  the user name
282
   * @param groups  the groups which the use is in
283
   * @param myPermission  permission type to check for
284
   */
285
  public Hashtable hasUnaccessableSubTree(String user, String[] groups, 
286
                                       String myPermission) throws McdbException
287
  {
288
    Hashtable resultUnaccessableSubTree = new Hashtable();
289
    String [] principals=null;
290
    int permission =AccessControlList.intValue(myPermission);
291
    
292
    //for the commnad line invocation return null(no unaccessable subtree)
293
    if ((user==null) && (groups==null || groups.length==0))
294
    {
295
      return resultUnaccessableSubTree;
296
    }
297
    
298
    //create a userpackage including user, public and group member
299
    principals=createUsersPackage(user, groups);
300
    //for the document owner return null(no unaccessable subtree)
301
    try
302
    {
303
      if (containDocumentOwner(principals, docId))
304
      {
305
       return resultUnaccessableSubTree;
306
      }
307
    }
308
    catch (SQLException ee)
309
    {
310
      throw new McdbException(ee);
311
    }
312
    
313
    // go through every subtree which has access control
314
    for (int i = 0; i< subTreeList.size(); i++)
315
    {
316
      SubTree tree = (SubTree)subTreeList.elementAt(i);
317
      long startId = tree.getStartNodeId();
318
     
319
     
320
        try
321
        {
322
          if (isAllowFirst(principals, docId, startId))
323
          {
324
           
325
            if (hasExplicitDenyRule(principals, docId, permission, startId ))
326
            {
327
             
328
             //if it is allowfirst and has deny rule
329
              // put the subtree into unaccessable vector
330
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
331
              {
332
                resultUnaccessableSubTree.put(new Long(startId), tree);
333
              }
334
            }//if
335
            else if ( hasAllowRule(principals, docId, permission, startId))
336
            {
337
              //if it is allowfirst and hasn't deny rule and has allow rule
338
              //allow access do nothing
339
              
340
            }//else if
341
            else
342
            {
343
              //other situation deny access
344
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
345
              {
346
                resultUnaccessableSubTree.put(new Long(startId), tree);
347
              }
348
             
349
            }//else
350
          }//if isAllowFirst
351
          else //denyFirst
352
          {
353
            if (hasAllowRule(principals, docId, permission,startId))
354
            {
355
              //if it is denyFirst and has allow rule, allow access, do nothing
356
           
357
            }
358
            else
359
            {
360
              //if it is denyfirst but no allow rule, deny access
361
              // add into vector
362
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
363
              {
364
                resultUnaccessableSubTree.put(new Long(startId), tree);
365
              }
366
            }
367
          }//else denyfirst
368
        }//try
369
        catch( Exception e)
370
        {
371
          MetaCatUtil.debugMessage("error in PermissionControl.has" +
372
                                   "UnaccessableSubTree "+e.getMessage(), 30);
373
          throw new McdbException(e);
374
        }
375
     
376
    }//for
377
    // merge the subtree if a subtree is another subtree'subtree    
378
    resultUnaccessableSubTree = mergeEquivalentSubtree(resultUnaccessableSubTree);
379
    return resultUnaccessableSubTree;
380
  }//hasUnaccessableSubtree
381
  
382
  
383
  /* 
384
   * A method to merge nested subtree into bigger one. For example subtree b
385
   * is a subtree of subtree a. And user doesn't have read permission for both
386
   * so we only use subtree a is enough.
387
   */
388
  private Hashtable mergeEquivalentSubtree(Hashtable unAccessSubTree)
389
  {
390
    Hashtable newSubTreeHash = new Hashtable();
391
    boolean   needDelete = false;
392
    // check the parameters
393
    if (unAccessSubTree == null || unAccessSubTree.isEmpty())
394
    {
395
      return newSubTreeHash;
396
    }
397
    else
398
    {
399
      // look every subtree start point and stop point, to see if it is embedded
400
      // in another one. If embedded, they are equavelent and we can use bigger
401
      // one to replace smaller one
402
      Enumeration en = unAccessSubTree.elements();
403
      while (en.hasMoreElements())
404
      {
405
        SubTree tree    = (SubTree)en.nextElement();
406
        String  treeId  = tree.getSubTreeId();
407
        long    startId = tree.getStartNodeId();
408
        long    endId   = tree.getEndNodeId();
409
        
410
        Enumeration enu = unAccessSubTree.elements();
411
        while (enu.hasMoreElements())
412
        {
413
          SubTree subTree = (SubTree)enu.nextElement();
414
          String subTreeId= subTree.getSubTreeId();
415
          long   subTreeStartId = subTree.getStartNodeId();
416
          long   subTreeEndId   = subTree.getEndNodeId();
417
          //compare and if the first subtree is a subtree of the second
418
          // one, set neeDelete true
419
          if (startId > subTreeStartId && endId < subTreeEndId)
420
          {
421
            needDelete = true;
422
            MetaCatUtil.debugMessage("the subtree: "+ treeId + 
423
                                     " need to be get rid of from unaccessable"+
424
                                     " subtree list becuase it is a subtree of"+
425
                                     " another subtree in the list", 45);
426
            break;
427
          }//if
428
        }//while
429
        // if not need to delete, put the subtree into hash
430
        if (!needDelete)
431
        {
432
          newSubTreeHash.put(new Long(startId), tree);
433
        }
434
        //reset needDelete
435
        needDelete = false;
436
      }//while
437
      return newSubTreeHash;
438
    }//else
439
  }
440
  
441
  /**
442
    * Check if a document id is a access document. Access document need user
443
    * has "all" permission to access it.
444
    * @param docId, the document id need to be checked
445
    */
446
    private boolean isAccessDocument(String docId) throws SQLException
447
    {
448
      //detele the rev number if docid contains it
449
      docId=MetaCatUtil.getDocIdFromString(docId);
450
      PreparedStatement pStmt=null;
451
      DBConnection conn = null;
452
      int serialNumber = -1;
453
      try
454
      {
455
        //check out DBConnection
456
        conn=DBConnectionPool.getDBConnection("PermissionControl.isAccessDoc");
457
        serialNumber=conn.getCheckOutSerialNumber();
458
        pStmt = conn.prepareStatement("select doctype from xml_documents where " +
459
                                      "docid like '" + docId +  "'");
460
        pStmt.execute();
461
        ResultSet rs = pStmt.getResultSet();
462
        boolean hasRow = rs.next();
463
        String doctype = null;
464
        if (hasRow) 
465
        {
466
          doctype = rs.getString(1);
467
         
468
        }
469
        pStmt.close();
470
      
471
        // if it is an access document
472
        if (doctype != null && ((MetaCatUtil.getOptionList(MetaCatUtil.
473
           getOption("accessdoctype")).contains(doctype))))
474
        {
475
          
476
          return true;
477
        }
478
        
479
      }
480
      catch(SQLException e)
481
      {
482
       
483
        throw new SQLException("PermissionControl.isAccessDocument " +
484
                     "Error checking" +
485
                     " on document " + docId + ". " + e.getMessage());
486
      }
487
      finally
488
      {
489
        try
490
        {
491
           pStmt.close();
492
        }
493
        finally
494
        {
495
          DBConnectionPool.returnDBConnection(conn, serialNumber);
496
        }
497
      }
498
      
499
      return false;
500
    }//isAccessDocument
501
     
502
  
503
  
504
  /**
505
    * Check if a stirng array contains a given documents' owner
506
    * @param principals, a string array storing the username, groups name and
507
    * public.
508
    * @param docid, the id of given documents 
509
    */ 
510
  private boolean containDocumentOwner( String[] principals, String docId)
511
                    throws SQLException
512
  {
513
    int lengthOfArray=principals.length;
514
    boolean hasRow; 
515
    PreparedStatement pStmt=null;
516
    DBConnection conn = null;
517
    int serialNumber = -1;
518
    
519
    try
520
    {
521
      //check out DBConnection
522
     conn=DBConnectionPool.getDBConnection("PermissionControl.containDocOnwer");
523
      serialNumber=conn.getCheckOutSerialNumber();
524
      pStmt = conn.prepareStatement(
525
                "SELECT 'x' FROM xml_documents " +
526
                "WHERE docid = ? AND user_owner = ?"); 
527
      //check every element in the string array too see if it conatains
528
      //the owner of document
529
      for (int i=0; i<lengthOfArray; i++)
530
      {
531
             
532
        // Bind the values to the query
533
        pStmt.setString(1, docId);
534
        pStmt.setString(2, principals[i]);
535

    
536
        pStmt.execute();
537
        ResultSet rs = pStmt.getResultSet();
538
        hasRow = rs.next();
539
        if (hasRow) 
540
        {
541
          pStmt.close();
542
          return true;
543
        }//if    
544
     
545
      }//for
546
    }//try
547
    catch (SQLException e) 
548
    {
549
        pStmt.close();
550
       
551
        throw new 
552
        SQLException("PermissionControl.hasPermission(). " +
553
                     "Error checking ownership for " + principals[0] +
554
                     " on document #" + docId + ". " + e.getMessage());
555
    }//catch
556
    finally
557
    {
558
      try
559
      {
560
        pStmt.close();
561
      }
562
      finally
563
      {
564
        DBConnectionPool.returnDBConnection(conn, serialNumber);
565
      }
566
    }
567
    return false; 
568
  }//containDocumentOwner
569
  
570
  /**
571
    * Check if the permission order for user at that documents is allowFirst
572
    * @param principals, list of names of principals to check for 
573
    * @param docid, document identifier to check for
574
    */
575
  private boolean isAllowFirst(String [] principals, String docId, 
576
                               long startId)
577
                  throws SQLException, Exception
578
  {
579
    int lengthOfArray=principals.length;
580
    boolean hasRow;
581
    PreparedStatement pStmt = null;
582
    DBConnection conn = null;
583
    int serialNumber = -1;
584
    String sql = null;
585
    boolean topLever =false;
586
    if (startId == TOPLEVELSTARTNODEID)
587
    {
588
      //top level
589
      topLever = true;
590
      sql = "SELECT perm_order FROM xml_access " +
591
            "WHERE principal_name= ? AND docid = ? AND startnodeid is NULL";
592
    }
593
    else
594
    {
595
      //sub tree level
596
      sql = "SELECT perm_order FROM xml_access " +
597
            "WHERE principal_name= ? AND docid = ? AND startnodeid = ?";
598
    }
599
    
600
    try
601
    {
602
      //check out DBConnection
603
      conn=DBConnectionPool.getDBConnection("AccessControlList.isAllowFirst");
604
      serialNumber=conn.getCheckOutSerialNumber();
605
    
606
      //select permission order from database
607
      pStmt = conn.prepareStatement(sql);
608
   
609
      //check every name in the array
610
      for (int i=0; i<lengthOfArray;i++)
611
      {
612
        //bind value
613
        pStmt.setString(1, principals[i]);//user name
614
        pStmt.setString(2, docId);//docid
615
        
616
        // if subtree, we need set subtree id 
617
        if (!topLever)
618
        {
619
          pStmt.setLong(3, startId);
620
        }
621
    
622
        pStmt.execute();
623
        ResultSet rs = pStmt.getResultSet();
624
        hasRow=rs.next();
625
        if (hasRow)
626
        {
627
          //get the permission order from data base
628
          String permissionOrder=rs.getString(1);
629
          //if the permission order is "allowFirst
630
          if (permissionOrder.equalsIgnoreCase(AccessControlInterface.ALLOWFIRST))
631
          {
632
            pStmt.close();
633
            return true;
634
          }
635
          else
636
          {
637
            pStmt.close();
638
            return false;
639
          }
640
        }//if
641
      }//for
642
    }//try
643
    catch (SQLException e)
644
    {
645
      throw e;
646
    }
647
    finally
648
    {
649
      try
650
      {
651
        pStmt.close();
652
      }
653
      finally
654
      {
655
        DBConnectionPool.returnDBConnection(conn, serialNumber);
656
      }
657
    }
658
    
659
    //if reach here, means there is no permssion record for given names and 
660
    //docid. So throw a exception.
661
    
662
    throw new Exception("There is no permission record for user"+principals[0]+
663
                        "at document "+docId);
664
        
665
  }//isAllowFirst
666
  
667
  /**
668
    * Check if the users array has allow rules for given users, docid and 
669
    * permission.
670
    * If it has permission rule and ticket count is greater than 0, the ticket
671
    * number will decrease one for every allow rule
672
    * @param principals, list of names of principals to check for 
673
    * @param docid, document identifier to check for
674
    * @param permission, the permssion need to check
675
    */
676
  private boolean hasAllowRule(String [] principals, String docId, 
677
                                  int permission, long startId)
678
                  throws SQLException, Exception
679
 {
680
   int lengthOfArray=principals.length;
681
   boolean allow=false;//initial value is no allow rule
682
   ResultSet rs;
683
   PreparedStatement pStmt = null;
684
   int permissionValue=permission;
685
   int permissionValueInTable;
686
   int ticketCount;
687
   DBConnection conn = null;
688
   int serialNumber = -1;
689
   boolean topLever = false;
690
   String sql = null;
691
   if (startId == TOPLEVELSTARTNODEID)
692
   {
693
     // for toplevel
694
     topLever = true;
695
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +  
696
           "AND principal_name = ? AND perm_type = ? AND startnodeid is NULL";
697
   }
698
   else
699
   {
700
     topLever =false;
701
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +  
702
           "AND principal_name = ? AND perm_type = ? AND startnodeid = ?";
703
   }
704
   try
705
   {
706
     //check out DBConnection
707
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasAllowRule");
708
     serialNumber=conn.getCheckOutSerialNumber();
709
    //This sql statement will select entry with 
710
    //begin_time<=currentTime<=end_time in xml_access table
711
    //If begin_time or end_time is null in table, isnull(begin_time, sysdate)
712
    //function will assign begin_time=sysdate
713
    pStmt = conn.prepareStatement(sql);
714
    //bind docid, perm_type
715
    pStmt.setString(1, docId);
716
    pStmt.setString(3, AccessControlInterface.ALLOW);
717
    
718
    // if subtree lever, need to set subTreeId
719
    if (!topLever)
720
    {
721
      pStmt.setLong(4, startId);
722
    }
723
   
724
    //bind every elenment in user name array
725
    for (int i=0;i<lengthOfArray; i++)
726
    {
727
      pStmt.setString(2, principals[i]);
728
      pStmt.execute();
729
      rs=pStmt.getResultSet();
730
      while (rs.next())//check every entry for one user
731
      {
732
        permissionValueInTable=rs.getInt(1);
733
    
734
        //permission is ok  
735
        //the user have a permission to access the file
736
        if (( permissionValueInTable & permissionValue )== permissionValue )
737
        {
738
           
739
           allow=true;//has allow rule entry
740
        }//if
741
      }//while
742
    }//for
743
   }//try
744
   catch (SQLException sqlE)
745
   {
746
     throw sqlE;
747
   }
748
   catch (Exception e)
749
   {
750
     throw e;
751
   }
752
   finally
753
   {
754
     try
755
     {
756
       pStmt.close();
757
     }
758
     finally
759
     {
760
       DBConnectionPool.returnDBConnection(conn, serialNumber);
761
     }
762
   }
763
    return allow;
764
 }//hasAllowRule
765
 
766
 
767
   
768
   /**
769
    * Check if the users array has explicit deny rules for given users, docid 
770
    * and permission. That means the perm_type is deny and current time is
771
    * less than end_time and greater than begin time, or no time limit.
772
    * @param principals, list of names of principals to check for 
773
    * @param docid, document identifier to check for
774
    * @param permission, the permssion need to check
775
    */
776
  private boolean hasExplicitDenyRule(String [] principals, String docId, 
777
                                      int permission, long startId)
778
                  throws SQLException
779
 {
780
   int lengthOfArray=principals.length;
781
   ResultSet rs;
782
   PreparedStatement pStmt = null;
783
   int permissionValue=permission;
784
   int permissionValueInTable;
785
   DBConnection conn = null;
786
   int serialNumber = -1;
787
   String sql = null;
788
   boolean topLevel = false;
789
   
790
   // decide top level or subtree level
791
   if (startId == TOPLEVELSTARTNODEID)
792
   {
793
     topLevel = true;
794
     sql = "SELECT permission FROM xml_access WHERE docid = ? " + 
795
            "AND principal_name = ? AND perm_type = ? AND startnodeid is NULL";
796
   }
797
   else
798
   {
799
     topLevel = false;
800
     sql = "SELECT permission FROM xml_access WHERE docid = ? " + 
801
            "AND principal_name = ? AND perm_type = ? AND startnodeid = ?";
802
   }
803
   
804
   try
805
   {
806
     //check out DBConnection
807
     conn=DBConnectionPool.getDBConnection("PermissionControl.hasExplicitDeny");
808
     serialNumber=conn.getCheckOutSerialNumber();
809
   
810
     pStmt = conn.prepareStatement(sql);
811
    //bind docid, perm_type
812
    pStmt.setString(1, docId);
813
    pStmt.setString(3, AccessControlInterface.DENY);
814
    
815
    // subtree level need to set up subtreeid
816
    if (!topLevel)
817
    {
818
      pStmt.setLong(4, startId);
819
    }
820
   
821
    //bind every elenment in user name array
822
    for (int i=0;i<lengthOfArray; i++)
823
    {
824
      pStmt.setString(2, principals[i]);
825
      pStmt.execute();
826
      rs=pStmt.getResultSet();
827
      while (rs.next())//check every entry for one user
828
      {
829
        permissionValueInTable=rs.getInt(1);
830
        
831
        //permission is ok the user doesn't have permission to access the file
832
        if (( permissionValueInTable & permissionValue )== permissionValue )
833
             
834
        {
835
           pStmt.close();
836
           return true;
837
         }//if
838
      }//while
839
    }//for
840
   }//try
841
   catch (SQLException e)
842
   {
843
     throw e;
844
   }//catch
845
   finally
846
   {
847
     try
848
     {
849
       pStmt.close();
850
     }
851
     finally
852
     {
853
       DBConnectionPool.returnDBConnection(conn, serialNumber);
854
     }
855
   }//finally
856
   return false;//no deny rule
857
  }//hasExplicitDenyRule 
858
   
859

    
860
  /**
861
    * Creat a users pakages to check permssion rule, user itself, public and
862
    * the gourps the user belong will be include in this package
863
    * @param user, the name of user
864
    * @param groups, the string array of the groups that user belong to
865
    */
866
  private String[] createUsersPackage(String user, String [] groups)
867
  {
868
    String [] usersPackage=null;
869
    int lengthOfPackage;
870
    
871
    if (groups!=null)
872
    {
873
      //if gouprs is not null and user is not public, we should create a array 
874
      //to store the groups and user and public. 
875
      //So the length of userPackage is the length of group plus two
876
      if (!user.equalsIgnoreCase(AccessControlInterface.PUBLIC))
877
      {
878
        lengthOfPackage=(groups.length)+2;
879
        usersPackage=new String [lengthOfPackage];
880
        //the first two elements is user self and public
881
        usersPackage[0]=user;
882
        usersPackage[1]=AccessControlInterface.PUBLIC;
883
        //put groups element from index 0 to lengthOfPackage-3 into userPackage
884
        //from index 2 to lengthOfPackage-1
885
        for (int i=2; i<lengthOfPackage; i++)
886
        {
887
          usersPackage[i]=groups[i-2];
888
        } //for
889
      }//if user!=public
890
      else//use=public
891
      {
892
        lengthOfPackage=(groups.length)+1;
893
        usersPackage=new String [lengthOfPackage];
894
        //the first lements is public
895
        usersPackage[0]=AccessControlInterface.PUBLIC;
896
        //put groups element from index 0 to lengthOfPackage-2 into userPackage
897
        //from index 1 to lengthOfPackage-1
898
        for (int i=1; i<lengthOfPackage; i++)
899
        {
900
          usersPackage[i]=groups[i-1];
901
        } //for
902
      }//else user=public
903
       
904
    }//if groups!=null
905
    else
906
    {
907
      //because no groups, the userPackage only need two elements
908
      //one is for user, the other is for public
909
      if (!user.equalsIgnoreCase(AccessControlInterface.PUBLIC))
910
      {
911
        lengthOfPackage=2;
912
        usersPackage=new String [lengthOfPackage];
913
        usersPackage[0]=user;
914
        usersPackage[1]=AccessControlInterface.PUBLIC;
915
      }//if user!=public
916
      else //user==public
917
      {
918
        //only put public into array
919
        lengthOfPackage=1;
920
        usersPackage=new String [lengthOfPackage];
921
        usersPackage[0]=AccessControlInterface.PUBLIC;
922
      }
923
    }//else groups==null
924
    return usersPackage;
925
  }//createUsersPackage
926
 
927
  /**
928
    * This method will return a data set id for given access id.
929
    * @param accessDocId, the accessDocId which need to be found data set id
930
   */
931
  private String getDataSetId(String accessDocId) 
932
                              throws SQLException
933
  {
934
    String dataSetId=null;
935
    PreparedStatement pStmt=null;
936
    ResultSet rs=null;
937
    DBConnection conn=null;
938
    int serialNumber=-1;
939
    String query="SELECT docId from xml_relation where subject = ? or "
940
                                                +"object = ?";
941
    
942
    try
943
    {
944
      //check out DBConnection
945
      conn=DBConnectionPool.getDBConnection("PermissionControl.getDataSetId");
946
      serialNumber=conn.getCheckOutSerialNumber();
947
      
948
      pStmt=conn.prepareStatement(query);
949
      //bind the value to query
950
      pStmt.setString(1, accessDocId);
951
      pStmt.setString(2, accessDocId);
952
      //execute the query
953
      pStmt.execute();
954
      rs=pStmt.getResultSet();
955
      //process the result
956
      if (rs.next()) //There are some records for the data set id for access id
957
      {
958
        dataSetId=rs.getString(1);
959
      }
960
      else //No data set id for the given access id in xml_relation table
961
      {
962
        dataSetId=null;
963
      }
964
    }//try
965
    finally
966
    {
967
      try
968
      {
969
        pStmt.close();
970
      }
971
      finally
972
      {
973
        DBConnectionPool.returnDBConnection(conn, serialNumber);
974
      }
975
    }
976
    return dataSetId;
977
  }//getDataPackageId() 
978
  
979
  /**
980
    * To create a part of query: "docid like '" +str1+ "', " +"docid like '" 
981
    * +str2+"'" ... We need to check user, group and public together for the 
982
    * permission. So we need the principal in an array and according the array
983
    * to create a part of query which will be used in other methods
984
    * @param principals, a string array storing the username, groups name and
985
    * public.
986
    */
987
   private String partQueryAboutDocId( String [] principals)
988
   {
989
     String partQuery="";
990
     int lengthOfArray=principals.length;
991
     
992
     for (int i=0;i<(lengthOfArray-1);i++)
993
     {
994
        partQuery=partQuery+"docid like '"+principals[i]+"',";
995
     }
996
     
997
     //the last one dosen't has "'"
998
     partQuery=partQuery+"docid like '"+principals[(lengthOfArray-1)]+"'";
999
     return partQuery;
1000
     
1001
   }
1002
}
(46-46/56)