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-08 16:30:15 -0700 (Tue, 08 Apr 2003) $'
13
 * '$Revision: 1527 $'
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
    if (isAccessDocument(docId) && (permission == AccessControlInterface.WRITE))
162
    {
163
      hasPermission = hasPermission(userPackage,docId, 7);// 7 is all permission
164
    }//if
165
    else //in other situation, just check the request permission
166
    {
167
    
168
      // Check for @permission on @docid for @user and/or @groups
169
      hasPermission = hasPermission(userPackage,docId, permission);
170
     
171
    }//else
172
    
173
    return hasPermission;
174
  }
175
  
176
 
177
  /**
178
    * Check from db connection if the users in String array @principals has
179
    * @permission on @docid* 
180
    * @param principals, names in userPakcage need to check for @permission
181
    * @param docid, document identifier to check on
182
    * @param permission, permission (write or all...) to check for 
183
    */
184
  private boolean hasPermission(String [] principals, String docId,
185
                                           int permission)
186
                         throws SQLException
187
  {
188
    long startId = TOPLEVELSTARTNODEID;// this is for top level, so startid is 0
189
    try 
190
    {
191
      //first, if there is a docid owner in user package, return true
192
      //because doc owner has all permssion 
193
      if (containDocumentOwner(principals, docId))
194
      {
195
          
196
          return true;
197
      }
198
      
199
      //If there is no owner in user package, checking the table
200
      //check perm_order
201
      if (isAllowFirst(principals, docId, startId))
202
      {
203
        
204
        if (hasExplicitDenyRule(principals, docId, permission, startId))
205
        {
206
          //if it is allowfirst and has deny rule(either explicit )
207
          //deny access
208
          return false;
209
        }//if
210
        else if ( hasAllowRule(principals, docId, permission, startId))
211
        {
212
          //if it is allowfirst and hasn't deny rule and has allow rule
213
          //allow access
214
          return true;
215
        }//else if
216
        else
217
        {
218
          //other situation deny access
219
          return false;
220
        }//else
221
     }//if isAllowFirst
222
     else //denyFirst
223
     {
224
       if (hasAllowRule(principals, docId, permission, startId))
225
       {
226
         //if it is denyFirst and has allow rule, allow access
227
         return true;
228
       }
229
       else
230
       {
231
         //if it is denyfirst but no allow rule, deny access
232
         return false;
233
       }
234
     }//else denyfirst
235
    }//try
236
    catch (Exception e)
237
    {
238
      MetaCatUtil.debugMessage("There is a exception in hasPermission method: "
239
                         +e.getMessage(), 50);
240
    }
241
   
242
    return false;
243
  }//hasPermission
244
  
245
  /**
246
   * The method to determine of a node can be access by a user just by subtree
247
   * access control
248
   */
249
  public boolean hasPermissionForSubTreeNode(String user, String[] groups,
250
                                             String myPermission, long nodeId)
251
                                             throws McdbException
252
  {
253
    boolean flag = true;
254
    // Get unaccessble subtree for this user
255
    Hashtable unaccessableSubTree = hasUnaccessableSubTree(user, groups, 
256
                                                           myPermission);
257
    Enumeration en = unaccessableSubTree.elements();
258
    while (en.hasMoreElements())
259
    {
260
      SubTree tree = (SubTree)en.nextElement();
261
      long start = tree.getStartNodeId();
262
      long stop  = tree.getEndNodeId();
263
      // nodeid in unaccessablesubtree, return false
264
      if ( nodeId >= start && nodeId <= stop)
265
      {
266
        flag = false;
267
        break;
268
      }
269
    }
270
    return flag;
271
  }
272
  /**
273
   * This method will return a hasTable of subtree which user doesn't has the 
274
   * permssion to access
275
   * @param user  the user name
276
   * @param groups  the groups which the use is in
277
   * @param myPermission  permission type to check for
278
   */
279
  public Hashtable hasUnaccessableSubTree(String user, String[] groups, 
280
                                       String myPermission) throws McdbException
281
  {
282
    Hashtable resultUnaccessableSubTree = new Hashtable();
283
    String [] principals=null;
284
    int permission =AccessControlList.intValue(myPermission);
285
    
286
    //for the commnad line invocation return null(no unaccessable subtree)
287
    if ((user==null) && (groups==null || groups.length==0))
288
    {
289
      return resultUnaccessableSubTree;
290
    }
291
    
292
    //create a userpackage including user, public and group member
293
    principals=createUsersPackage(user, groups);
294
    //for the document owner return null(no unaccessable subtree)
295
    try
296
    {
297
      if (containDocumentOwner(principals, docId))
298
      {
299
       return resultUnaccessableSubTree;
300
      }
301
    }
302
    catch (SQLException ee)
303
    {
304
      throw new McdbException(ee);
305
    }
306
    
307
    // go through every subtree which has access control
308
    for (int i = 0; i< subTreeList.size(); i++)
309
    {
310
      SubTree tree = (SubTree)subTreeList.elementAt(i);
311
      long startId = tree.getStartNodeId();
312
     
313
     
314
        try
315
        {
316
          if (isAllowFirst(principals, docId, startId))
317
          {
318
           
319
            if (hasExplicitDenyRule(principals, docId, permission, startId ))
320
            {
321
             
322
             //if it is allowfirst and has deny rule
323
              // put the subtree into unaccessable vector
324
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
325
              {
326
                resultUnaccessableSubTree.put(new Long(startId), tree);
327
              }
328
            }//if
329
            else if ( hasAllowRule(principals, docId, permission, startId))
330
            {
331
              //if it is allowfirst and hasn't deny rule and has allow rule
332
              //allow access do nothing
333
              
334
            }//else if
335
            else
336
            {
337
              //other situation deny access
338
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
339
              {
340
                resultUnaccessableSubTree.put(new Long(startId), tree);
341
              }
342
             
343
            }//else
344
          }//if isAllowFirst
345
          else //denyFirst
346
          {
347
            if (hasAllowRule(principals, docId, permission,startId))
348
            {
349
              //if it is denyFirst and has allow rule, allow access, do nothing
350
           
351
            }
352
            else
353
            {
354
              //if it is denyfirst but no allow rule, deny access
355
              // add into vector
356
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
357
              {
358
                resultUnaccessableSubTree.put(new Long(startId), tree);
359
              }
360
            }
361
          }//else denyfirst
362
        }//try
363
        catch( Exception e)
364
        {
365
          MetaCatUtil.debugMessage("error in PermissionControl.has" +
366
                                   "UnaccessableSubTree "+e.getMessage(), 30);
367
          throw new McdbException(e);
368
        }
369
     
370
    }//for
371
    // merge the subtree if a subtree is another subtree'subtree    
372
    resultUnaccessableSubTree = mergeEquivalentSubtree(resultUnaccessableSubTree);
373
    return resultUnaccessableSubTree;
374
  }//hasUnaccessableSubtree
375
  
376
  
377
  /* 
378
   * A method to merge nested subtree into bigger one. For example subtree b
379
   * is a subtree of subtree a. And user doesn't have read permission for both
380
   * so we only use subtree a is enough.
381
   */
382
  private Hashtable mergeEquivalentSubtree(Hashtable unAccessSubTree)
383
  {
384
    Hashtable newSubTreeHash = new Hashtable();
385
    boolean   needDelete = false;
386
    // check the parameters
387
    if (unAccessSubTree == null || unAccessSubTree.isEmpty())
388
    {
389
      return newSubTreeHash;
390
    }
391
    else
392
    {
393
      // look every subtree start point and stop point, to see if it is embedded
394
      // in another one. If embedded, they are equavelent and we can use bigger
395
      // one to replace smaller one
396
      Enumeration en = unAccessSubTree.elements();
397
      while (en.hasMoreElements())
398
      {
399
        SubTree tree    = (SubTree)en.nextElement();
400
        String  treeId  = tree.getSubTreeId();
401
        long    startId = tree.getStartNodeId();
402
        long    endId   = tree.getEndNodeId();
403
        
404
        Enumeration enu = unAccessSubTree.elements();
405
        while (enu.hasMoreElements())
406
        {
407
          SubTree subTree = (SubTree)enu.nextElement();
408
          String subTreeId= subTree.getSubTreeId();
409
          long   subTreeStartId = subTree.getStartNodeId();
410
          long   subTreeEndId   = subTree.getEndNodeId();
411
          //compare and if the first subtree is a subtree of the second
412
          // one, set neeDelete true
413
          if (startId > subTreeStartId && endId < subTreeEndId)
414
          {
415
            needDelete = true;
416
            MetaCatUtil.debugMessage("the subtree: "+ treeId + 
417
                                     " need to be get rid of from unaccessable"+
418
                                     " subtree list becuase it is a subtree of"+
419
                                     " another subtree in the list", 45);
420
            break;
421
          }//if
422
        }//while
423
        // if not need to delete, put the subtree into hash
424
        if (!needDelete)
425
        {
426
          newSubTreeHash.put(new Long(startId), tree);
427
        }
428
        //reset needDelete
429
        needDelete = false;
430
      }//while
431
      return newSubTreeHash;
432
    }//else
433
  }
434
  
435
  /**
436
    * Check if a document id is a access document. Access document need user
437
    * has "all" permission to access it.
438
    * @param docId, the document id need to be checked
439
    */
440
    private boolean isAccessDocument(String docId) throws SQLException
441
    {
442
      //detele the rev number if docid contains it
443
      docId=MetaCatUtil.getDocIdFromString(docId);
444
      PreparedStatement pStmt=null;
445
      DBConnection conn = null;
446
      int serialNumber = -1;
447
      try
448
      {
449
        //check out DBConnection
450
        conn=DBConnectionPool.getDBConnection("PermissionControl.isAccessDoc");
451
        serialNumber=conn.getCheckOutSerialNumber();
452
        pStmt = conn.prepareStatement("select 'x' from xml_access where " +
453
                                      "accessfileid like '" + docId +  "'");
454
        pStmt.execute();
455
        ResultSet rs = pStmt.getResultSet();
456
        boolean hasRow = rs.next();
457
        pStmt.close();
458
        if(hasRow)
459
        {
460
          return true;
461
        }
462
      }
463
      catch(SQLException e)
464
      {
465
       
466
        throw new SQLException("PermissionControl.isAccessDocument " +
467
                     "Error checking" +
468
                     " on document " + docId + ". " + e.getMessage());
469
      }
470
      finally
471
      {
472
        try
473
        {
474
           pStmt.close();
475
        }
476
        finally
477
        {
478
          DBConnectionPool.returnDBConnection(conn, serialNumber);
479
        }
480
      }
481
      return false;
482
    }//isAccessDocument
483
     
484
  
485
  
486
  /**
487
    * Check if a stirng array contains a given documents' owner
488
    * @param principals, a string array storing the username, groups name and
489
    * public.
490
    * @param docid, the id of given documents 
491
    */ 
492
  private boolean containDocumentOwner( String[] principals, String docId)
493
                    throws SQLException
494
  {
495
    int lengthOfArray=principals.length;
496
    boolean hasRow; 
497
    PreparedStatement pStmt=null;
498
    DBConnection conn = null;
499
    int serialNumber = -1;
500
    
501
    try
502
    {
503
      //check out DBConnection
504
     conn=DBConnectionPool.getDBConnection("PermissionControl.containDocOnwer");
505
      serialNumber=conn.getCheckOutSerialNumber();
506
      pStmt = conn.prepareStatement(
507
                "SELECT 'x' FROM xml_documents " +
508
                "WHERE docid = ? AND user_owner = ?"); 
509
      //check every element in the string array too see if it conatains
510
      //the owner of document
511
      for (int i=0; i<lengthOfArray; i++)
512
      {
513
             
514
        // Bind the values to the query
515
        pStmt.setString(1, docId);
516
        pStmt.setString(2, principals[i]);
517

    
518
        pStmt.execute();
519
        ResultSet rs = pStmt.getResultSet();
520
        hasRow = rs.next();
521
        if (hasRow) 
522
        {
523
          pStmt.close();
524
          return true;
525
        }//if    
526
     
527
      }//for
528
    }//try
529
    catch (SQLException e) 
530
    {
531
        pStmt.close();
532
       
533
        throw new 
534
        SQLException("PermissionControl.hasPermission(). " +
535
                     "Error checking ownership for " + principals[0] +
536
                     " on document #" + docId + ". " + e.getMessage());
537
    }//catch
538
    finally
539
    {
540
      try
541
      {
542
        pStmt.close();
543
      }
544
      finally
545
      {
546
        DBConnectionPool.returnDBConnection(conn, serialNumber);
547
      }
548
    }
549
    return false; 
550
  }//containDocumentOwner
551
  
552
  /**
553
    * Check if the permission order for user at that documents is allowFirst
554
    * @param principals, list of names of principals to check for 
555
    * @param docid, document identifier to check for
556
    */
557
  private boolean isAllowFirst(String [] principals, String docId, 
558
                               long startId)
559
                  throws SQLException, Exception
560
  {
561
    int lengthOfArray=principals.length;
562
    boolean hasRow;
563
    PreparedStatement pStmt = null;
564
    DBConnection conn = null;
565
    int serialNumber = -1;
566
    String sql = null;
567
    boolean topLever =false;
568
    if (startId == TOPLEVELSTARTNODEID)
569
    {
570
      //top level
571
      topLever = true;
572
      sql = "SELECT perm_order FROM xml_access " +
573
            "WHERE principal_name= ? AND docid = ? AND startnodeid is NULL";
574
    }
575
    else
576
    {
577
      //sub tree level
578
      sql = "SELECT perm_order FROM xml_access " +
579
            "WHERE principal_name= ? AND docid = ? AND startnodeid = ?";
580
    }
581
    
582
    try
583
    {
584
      //check out DBConnection
585
      conn=DBConnectionPool.getDBConnection("AccessControlList.isAllowFirst");
586
      serialNumber=conn.getCheckOutSerialNumber();
587
    
588
      //select permission order from database
589
      pStmt = conn.prepareStatement(sql);
590
   
591
      //check every name in the array
592
      for (int i=0; i<lengthOfArray;i++)
593
      {
594
        //bind value
595
        pStmt.setString(1, principals[i]);//user name
596
        pStmt.setString(2, docId);//docid
597
        
598
        // if subtree, we need set subtree id 
599
        if (!topLever)
600
        {
601
          pStmt.setLong(3, startId);
602
        }
603
    
604
        pStmt.execute();
605
        ResultSet rs = pStmt.getResultSet();
606
        hasRow=rs.next();
607
        if (hasRow)
608
        {
609
          //get the permission order from data base
610
          String permissionOrder=rs.getString(1);
611
          //if the permission order is "allowFirst
612
          if (permissionOrder.equalsIgnoreCase(AccessControlInterface.ALLOWFIRST))
613
          {
614
            pStmt.close();
615
            return true;
616
          }
617
          else
618
          {
619
            pStmt.close();
620
            return false;
621
          }
622
        }//if
623
      }//for
624
    }//try
625
    catch (SQLException e)
626
    {
627
      throw e;
628
    }
629
    finally
630
    {
631
      try
632
      {
633
        pStmt.close();
634
      }
635
      finally
636
      {
637
        DBConnectionPool.returnDBConnection(conn, serialNumber);
638
      }
639
    }
640
    
641
    //if reach here, means there is no permssion record for given names and 
642
    //docid. So throw a exception.
643
    
644
    throw new Exception("There is no permission record for user"+principals[0]+
645
                        "at document "+docId);
646
        
647
  }//isAllowFirst
648
  
649
  /**
650
    * Check if the users array has allow rules for given users, docid and 
651
    * permission.
652
    * If it has permission rule and ticket count is greater than 0, the ticket
653
    * number will decrease one for every allow rule
654
    * @param principals, list of names of principals to check for 
655
    * @param docid, document identifier to check for
656
    * @param permission, the permssion need to check
657
    */
658
  private boolean hasAllowRule(String [] principals, String docId, 
659
                                  int permission, long startId)
660
                  throws SQLException, Exception
661
 {
662
   int lengthOfArray=principals.length;
663
   boolean allow=false;//initial value is no allow rule
664
   ResultSet rs;
665
   PreparedStatement pStmt = null;
666
   int permissionValue=permission;
667
   int permissionValueInTable;
668
   int ticketCount;
669
   DBConnection conn = null;
670
   int serialNumber = -1;
671
   boolean topLever = false;
672
   String sql = null;
673
   if (startId == TOPLEVELSTARTNODEID)
674
   {
675
     // for toplevel
676
     topLever = true;
677
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +  
678
           "AND principal_name = ? AND perm_type = ? AND startnodeid is NULL";
679
   }
680
   else
681
   {
682
     topLever =false;
683
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +  
684
           "AND principal_name = ? AND perm_type = ? AND startnodeid = ?";
685
   }
686
   try
687
   {
688
     //check out DBConnection
689
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasAllowRule");
690
     serialNumber=conn.getCheckOutSerialNumber();
691
    //This sql statement will select entry with 
692
    //begin_time<=currentTime<=end_time in xml_access table
693
    //If begin_time or end_time is null in table, isnull(begin_time, sysdate)
694
    //function will assign begin_time=sysdate
695
    pStmt = conn.prepareStatement(sql);
696
    //bind docid, perm_type
697
    pStmt.setString(1, docId);
698
    pStmt.setString(3, AccessControlInterface.ALLOW);
699
    
700
    // if subtree lever, need to set subTreeId
701
    if (!topLever)
702
    {
703
      pStmt.setLong(4, startId);
704
    }
705
   
706
    //bind every elenment in user name array
707
    for (int i=0;i<lengthOfArray; i++)
708
    {
709
      pStmt.setString(2, principals[i]);
710
      pStmt.execute();
711
      rs=pStmt.getResultSet();
712
      while (rs.next())//check every entry for one user
713
      {
714
        permissionValueInTable=rs.getInt(1);
715
            
716
        //permission is ok  
717
        //the user have a permission to access the file
718
        if (( permissionValueInTable & permissionValue )== permissionValue )
719
        {
720
           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
 
747
 
748
   
749
   /**
750
    * Check if the users array has explicit deny rules for given users, docid 
751
    * 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
    * @param principals, list of names of principals to check for 
754
    * @param docid, document identifier to check for
755
    * @param permission, the permssion need to check
756
    */
757
  private boolean hasExplicitDenyRule(String [] principals, String docId, 
758
                                      int permission, long startId)
759
                  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
   String sql = null;
769
   boolean topLevel = false;
770
   
771
   // decide top level or subtree level
772
   if (startId == TOPLEVELSTARTNODEID)
773
   {
774
     topLevel = true;
775
     sql = "SELECT permission FROM xml_access WHERE docid = ? " + 
776
            "AND principal_name = ? AND perm_type = ? AND startnodeid is NULL";
777
   }
778
   else
779
   {
780
     topLevel = false;
781
     sql = "SELECT permission FROM xml_access WHERE docid = ? " + 
782
            "AND principal_name = ? AND perm_type = ? AND startnodeid = ?";
783
   }
784
   
785
   try
786
   {
787
     //check out DBConnection
788
     conn=DBConnectionPool.getDBConnection("PermissionControl.hasExplicitDeny");
789
     serialNumber=conn.getCheckOutSerialNumber();
790
   
791
     pStmt = conn.prepareStatement(sql);
792
    //bind docid, perm_type
793
    pStmt.setString(1, docId);
794
    pStmt.setString(3, AccessControlInterface.DENY);
795
    
796
    // subtree level need to set up subtreeid
797
    if (!topLevel)
798
    {
799
      pStmt.setLong(4, startId);
800
    }
801
   
802
    //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
        
812
        //permission is ok the user doesn't have permission to access the file
813
        if (( permissionValueInTable & permissionValue )== permissionValue )
814
             
815
        {
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
  }//hasExplicitDenyRule 
839
   
840

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