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: 2004-03-15 14:08:39 -0800 (Mon, 15 Mar 2004) $'
13
 * '$Revision: 2045 $'
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.getSmartDocId(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 lower(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
        MetaCatUtil.debugMessage("the principle stack is : " +  
536
                                  principals[i], 40);
537

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

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