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: sgarg $'
12
 *     '$Date: 2004-08-19 18:09:25 -0700 (Thu, 19 Aug 2004) $'
13
 * '$Revision: 2245 $'
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
import java.util.Iterator;
37

    
38
public class PermissionController
39
{
40
   private String docId = null;
41
   private boolean hasSubTreeAccessControl = false; // flag if has a subtree
42
                                                    // access for this docid
43
   private Vector subTreeList = new Vector();
44

    
45
   private long TOPLEVELSTARTNODEID = 0; //if start node is 0, means it is top
46
                                         //level document
47

    
48

    
49
   /**
50
    * Constructor for PermissionController
51
    * @param myDocid      the docid need to access
52
    */
53
   public PermissionController(String myDocid) throws McdbException
54
   {
55
     // Get rid of rev number
56
     docId = MetaCatUtil.getSmartDocId(myDocid);
57
     //hasSubTreeAccessControl = checkSubTreeAccessControl();
58
   }
59

    
60
   /**
61
    * Constructor for PermssionController
62
    * @param myDocid String
63
    * @param needDeleteRev boolean
64
    */
65
   public PermissionController(String myDocid, boolean needDeleteRevFromDocid)
66
   {
67
     if (!needDeleteRevFromDocid)
68
     {
69
       docId = myDocid;
70
     }
71
     else
72
     {
73
         docId = MetaCatUtil.getDocIdFromAccessionNumber(myDocid);
74
     }
75
   }
76

    
77
   /**
78
    * Return if a document has subtree access control
79
    */
80
   public boolean hasSubTreeAccessControl()
81
   {
82
     return hasSubTreeAccessControl;
83
   }
84

    
85

    
86
  /**
87
    * Check from db connection if at least one of the list of @principals
88
    * @param user  the user name
89
    * @param groups  the groups which the use is in
90
    * @param myPermission  permission type to check for
91
    */
92
  public boolean hasPermission(String user, String[]groups, String myPermission)
93
                              throws SQLException, Exception
94
  {
95
    boolean hasPermission=false;
96
    String [] userPackage=null;
97
    int permission =AccessControlList.intValue(myPermission);
98

    
99
    //for the commnad line invocation
100
    if ((user==null) && (groups==null || groups.length==0))
101
    {
102
      return true;
103
    }
104

    
105
    //create a userpackage including user, public and group member
106
    userPackage=createUsersPackage(user, groups);
107

    
108
    //if the requested document is access documents and requested permission
109
    //is "write", the user should have "all" right
110

    
111
    if (isAccessDocument(docId) && (permission == AccessControlInterface.WRITE))
112
    {
113

    
114
      hasPermission = hasPermission(userPackage,docId, 7);// 7 is all permission
115
    }//if
116
    else //in other situation, just check the request permission
117
    {
118

    
119

    
120
      // Check for @permission on @docid for @user and/or @groups
121
      hasPermission = hasPermission(userPackage,docId, permission);
122

    
123
    }//else
124

    
125
    return hasPermission;
126
  }
127

    
128

    
129
  /**
130
    * Check from db connection if the users in String array @principals has
131
    * @permission on @docid*
132
    * @param principals, names in userPakcage need to check for @permission
133
    * @param docid, document identifier to check on
134
    * @param permission, permission (write or all...) to check for
135
    */
136
  private boolean hasPermission(String [] principals, String docId,
137
                                           int permission)
138
                         throws SQLException
139
  {
140
    long startId = TOPLEVELSTARTNODEID;// this is for top level, so startid is 0
141
    try
142
    {
143
      //first, if there is a docid owner in user package, return true
144
      //because doc owner has all permssion
145
      if (containDocumentOwner(principals, docId))
146
      {
147

    
148
          return true;
149
      }
150

    
151
      //If there is no owner in user package, checking the table
152
      //check perm_order
153
      if (isAllowFirst(principals, docId, startId))
154
      {
155

    
156
        if (hasExplicitDenyRule(principals, docId, permission, startId))
157
        {
158
          //if it is allowfirst and has deny rule(either explicit )
159
          //deny access
160

    
161
          return false;
162
        }//if
163
        else if ( hasAllowRule(principals, docId, permission, startId))
164
        {
165
          //if it is allowfirst and hasn't deny rule and has allow rule
166
          //allow access
167

    
168
          return true;
169
        }//else if
170
        else
171
        {
172
          //other situation deny access
173

    
174
          return false;
175
        }//else
176
     }//if isAllowFirst
177
     else //denyFirst
178
     {
179
       if (hasAllowRule(principals, docId, permission, startId))
180
       {
181
         //if it is denyFirst and has allow rule, allow access
182
         return true;
183
       }
184
       else
185
       {
186
         //if it is denyfirst but no allow rule, deny access
187
         return false;
188
       }
189
     }//else denyfirst
190
    }//try
191
    catch (Exception e)
192
    {
193
      MetaCatUtil.debugMessage("There is a exception in hasPermission method: "
194
                         +e.getMessage(), 50);
195
    }
196

    
197
    return false;
198
  }//hasPermission
199

    
200
  /**
201
   *  Method to check if a person has permission to a inline data file
202
   * @param user String
203
   * @param groups String[]
204
   * @param myPermission String
205
   * @param inlineDataId String
206
   * @throws McdbException
207
   * @return boolean
208
   */
209
  private boolean hasPermissionForInlineData(String user, String[] groups,
210
                                      String myPermission, String inlineDataId)
211
                                      throws Exception
212
  {
213
     // this method can call the public method - hasPermission(...)
214
     // the only difference is about the ownership, you couldn't find the owner
215
     // from inlinedataId directly. You should get it from eml document itself
216
     String []userPackage = createUsersPackage(user, groups);
217
     if (containDocumentOwner(userPackage, docId))
218
     {
219
       return true;
220
     }
221
     else
222
     {
223
         PermissionController controller =
224
                               new PermissionController(inlineDataId, false);
225
         return controller.hasPermission(user, groups, myPermission);
226
     }
227
  }
228

    
229
  /**
230
   * The method to determine of a node can be access by a user just by subtree
231
   * access control
232
   */
233
  public boolean hasPermissionForSubTreeNode(String user, String[] groups,
234
                                             String myPermission, long nodeId)
235
                                             throws McdbException
236
  {
237
    boolean flag = true;
238
    // Get unaccessble subtree for this user
239
    Hashtable unaccessableSubTree = hasUnaccessableSubTree(user, groups,
240
                                                           myPermission);
241
    Enumeration en = unaccessableSubTree.elements();
242
    while (en.hasMoreElements())
243
    {
244
      SubTree tree = (SubTree)en.nextElement();
245
      long start = tree.getStartNodeId();
246
      long stop  = tree.getEndNodeId();
247
      // nodeid in unaccessablesubtree, return false
248
      if ( nodeId >= start && nodeId <= stop)
249
      {
250
        flag = false;
251
        break;
252
      }
253
    }
254
    return flag;
255
  }
256
  /**
257
   * This method will return a hasTable of subtree which user doesn't has the
258
   * permssion to access
259
   * @param user  the user name
260
   * @param groups  the groups which the use is in
261
   * @param myPermission  permission type to check for
262
   */
263
  public Hashtable hasUnaccessableSubTree(String user, String[] groups,
264
                                       String myPermission) throws McdbException
265
  {
266
    Hashtable resultUnaccessableSubTree = new Hashtable();
267
    String [] principals=null;
268
    int permission =AccessControlList.intValue(myPermission);
269

    
270
    //for the commnad line invocation return null(no unaccessable subtree)
271
    if ((user==null) && (groups==null || groups.length==0))
272
    {
273
      return resultUnaccessableSubTree;
274
    }
275

    
276
    //create a userpackage including user, public and group member
277
    principals=createUsersPackage(user, groups);
278
    //for the document owner return null(no unaccessable subtree)
279
    try
280
    {
281
      if (containDocumentOwner(principals, docId))
282
      {
283
       return resultUnaccessableSubTree;
284
      }
285
    }
286
    catch (SQLException ee)
287
    {
288
      throw new McdbException(ee);
289
    }
290

    
291
    // go through every subtree which has access control
292
    for (int i = 0; i< subTreeList.size(); i++)
293
    {
294
      SubTree tree = (SubTree)subTreeList.elementAt(i);
295
      long startId = tree.getStartNodeId();
296

    
297

    
298
        try
299
        {
300
          if (isAllowFirst(principals, docId, startId))
301
          {
302

    
303
            if (hasExplicitDenyRule(principals, docId, permission, startId ))
304
            {
305

    
306
             //if it is allowfirst and has deny rule
307
              // put the subtree into unaccessable vector
308
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
309
              {
310
                resultUnaccessableSubTree.put(new Long(startId), tree);
311
              }
312
            }//if
313
            else if ( hasAllowRule(principals, docId, permission, startId))
314
            {
315
              //if it is allowfirst and hasn't deny rule and has allow rule
316
              //allow access do nothing
317

    
318
            }//else if
319
            else
320
            {
321
              //other situation deny access
322
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
323
              {
324
                resultUnaccessableSubTree.put(new Long(startId), tree);
325
              }
326

    
327
            }//else
328
          }//if isAllowFirst
329
          else //denyFirst
330
          {
331
            if (hasAllowRule(principals, docId, permission,startId))
332
            {
333
              //if it is denyFirst and has allow rule, allow access, do nothing
334

    
335
            }
336
            else
337
            {
338
              //if it is denyfirst but no allow rule, deny access
339
              // add into vector
340
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
341
              {
342
                resultUnaccessableSubTree.put(new Long(startId), tree);
343
              }
344
            }
345
          }//else denyfirst
346
        }//try
347
        catch( Exception e)
348
        {
349
          MetaCatUtil.debugMessage("error in PermissionControl.has" +
350
                                   "UnaccessableSubTree "+e.getMessage(), 30);
351
          throw new McdbException(e);
352
        }
353

    
354
    }//for
355
    // merge the subtree if a subtree is another subtree'subtree
356
    resultUnaccessableSubTree = mergeEquivalentSubtree(resultUnaccessableSubTree);
357
    return resultUnaccessableSubTree;
358
  }//hasUnaccessableSubtree
359

    
360

    
361
  /*
362
   * A method to merge nested subtree into bigger one. For example subtree b
363
   * is a subtree of subtree a. And user doesn't have read permission for both
364
   * so we only use subtree a is enough.
365
   */
366
  private Hashtable mergeEquivalentSubtree(Hashtable unAccessSubTree)
367
  {
368
    Hashtable newSubTreeHash = new Hashtable();
369
    boolean   needDelete = false;
370
    // check the parameters
371
    if (unAccessSubTree == null || unAccessSubTree.isEmpty())
372
    {
373
      return newSubTreeHash;
374
    }
375
    else
376
    {
377
      // look every subtree start point and stop point, to see if it is embedded
378
      // in another one. If embedded, they are equavelent and we can use bigger
379
      // one to replace smaller one
380
      Enumeration en = unAccessSubTree.elements();
381
      while (en.hasMoreElements())
382
      {
383
        SubTree tree    = (SubTree)en.nextElement();
384
        String  treeId  = tree.getSubTreeId();
385
        long    startId = tree.getStartNodeId();
386
        long    endId   = tree.getEndNodeId();
387

    
388
        Enumeration enu = unAccessSubTree.elements();
389
        while (enu.hasMoreElements())
390
        {
391
          SubTree subTree = (SubTree)enu.nextElement();
392
          String subTreeId= subTree.getSubTreeId();
393
          long   subTreeStartId = subTree.getStartNodeId();
394
          long   subTreeEndId   = subTree.getEndNodeId();
395
          //compare and if the first subtree is a subtree of the second
396
          // one, set neeDelete true
397
          if (startId > subTreeStartId && endId < subTreeEndId)
398
          {
399
            needDelete = true;
400
            MetaCatUtil.debugMessage("the subtree: "+ treeId +
401
                                     " need to be get rid of from unaccessable"+
402
                                     " subtree list becuase it is a subtree of"+
403
                                     " another subtree in the list", 45);
404
            break;
405
          }//if
406
        }//while
407
        // if not need to delete, put the subtree into hash
408
        if (!needDelete)
409
        {
410
          newSubTreeHash.put(new Long(startId), tree);
411
        }
412
        //reset needDelete
413
        needDelete = false;
414
      }//while
415
      return newSubTreeHash;
416
    }//else
417
  }
418

    
419
  /**
420
    * Check if a document id is a access document. Access document need user
421
    * has "all" permission to access it.
422
    * @param docId, the document id need to be checked
423
    */
424
    private boolean isAccessDocument(String docId) throws SQLException
425
    {
426
      //detele the rev number if docid contains it
427
      docId=MetaCatUtil.getDocIdFromString(docId);
428
      PreparedStatement pStmt=null;
429
      DBConnection conn = null;
430
      int serialNumber = -1;
431
      try
432
      {
433
        //check out DBConnection
434
        conn=DBConnectionPool.getDBConnection("PermissionControl.isAccessDoc");
435
        serialNumber=conn.getCheckOutSerialNumber();
436
        pStmt = conn.prepareStatement("select doctype from xml_documents where " +
437
                                      "docid like '" + docId +  "'");
438
        pStmt.execute();
439
        ResultSet rs = pStmt.getResultSet();
440
        boolean hasRow = rs.next();
441
        String doctype = null;
442
        if (hasRow)
443
        {
444
          doctype = rs.getString(1);
445

    
446
        }
447
        pStmt.close();
448

    
449
        // if it is an access document
450
        if (doctype != null && ((MetaCatUtil.getOptionList(MetaCatUtil.
451
           getOption("accessdoctype")).contains(doctype))))
452
        {
453

    
454
          return true;
455
        }
456

    
457
      }
458
      catch(SQLException e)
459
      {
460

    
461
        throw new SQLException("PermissionControl.isAccessDocument " +
462
                     "Error checking" +
463
                     " on document " + docId + ". " + e.getMessage());
464
      }
465
      finally
466
      {
467
        try
468
        {
469
           pStmt.close();
470
        }
471
        finally
472
        {
473
          DBConnectionPool.returnDBConnection(conn, serialNumber);
474
        }
475
      }
476

    
477
      return false;
478
    }//isAccessDocument
479

    
480

    
481

    
482
  /**
483
    * Check if a stirng array contains a given documents' owner
484
    * @param principals, a string array storing the username, groups name and
485
    * public.
486
    * @param docid, the id of given documents
487
    */
488
  private boolean containDocumentOwner( String[] principals, String docId)
489
                    throws SQLException
490
  {
491
    int lengthOfArray=principals.length;
492
    boolean hasRow;
493
    PreparedStatement pStmt=null;
494
    DBConnection conn = null;
495
    int serialNumber = -1;
496

    
497
    try
498
    {
499
      //check out DBConnection
500
     conn=DBConnectionPool.getDBConnection("PermissionControl.containDocOnwer");
501
      serialNumber=conn.getCheckOutSerialNumber();
502
      pStmt = conn.prepareStatement(
503
                "SELECT 'x' FROM xml_documents " +
504
                "WHERE docid = ? AND lower(user_owner) = ?");
505
      //check every element in the string array too see if it conatains
506
      //the owner of document
507
      for (int i=0; i<lengthOfArray; i++)
508
      {
509

    
510
        // Bind the values to the query
511
        pStmt.setString(1, docId);
512
        pStmt.setString(2, principals[i]);
513
        MetaCatUtil.debugMessage("the principle stack is : " +
514
                                  principals[i], 40);
515

    
516
        pStmt.execute();
517
        ResultSet rs = pStmt.getResultSet();
518
        hasRow = rs.next();
519
        if (hasRow)
520
        {
521
          pStmt.close();
522
           MetaCatUtil.debugMessage("find the owner", 40);
523
          return true;
524
        }//if
525

    
526
      }//for
527
    }//try
528
    catch (SQLException e)
529
    {
530
        pStmt.close();
531

    
532
        throw new
533
        SQLException("PermissionControl.hasPermission(). " +
534
                     "Error checking ownership for " + principals[0] +
535
                     " on document #" + docId + ". " + e.getMessage());
536
    }//catch
537
    finally
538
    {
539
      try
540
      {
541
        pStmt.close();
542
      }
543
      finally
544
      {
545
        DBConnectionPool.returnDBConnection(conn, serialNumber);
546
      }
547
    }
548
    return false;
549
  }//containDocumentOwner
550

    
551
  /**
552
    * Check if the permission order for user at that documents is allowFirst
553
    * @param principals, list of names of principals to check for
554
    * @param docid, document identifier to check for
555
    */
556
  private boolean isAllowFirst(String [] principals, String docId,
557
                               long startId)
558
                  throws SQLException, Exception
559
  {
560
    int lengthOfArray=principals.length;
561
    boolean hasRow;
562
    PreparedStatement pStmt = null;
563
    DBConnection conn = null;
564
    int serialNumber = -1;
565
    String sql = null;
566
    boolean topLever =false;
567
    if (startId == TOPLEVELSTARTNODEID)
568
    {
569
      //top level
570
      topLever = true;
571
      sql = "SELECT perm_order FROM xml_access " +
572
    "WHERE lower(principal_name) = ? AND docid = ? AND startnodeid is NULL";
573
    }
574
    else
575
    {
576
      //sub tree level
577
      sql = "SELECT perm_order FROM xml_access " +
578
        "WHERE lower(principal_name)= ? AND docid = ? AND startnodeid = ?";
579
    }
580

    
581
    try
582
    {
583
      //check out DBConnection
584
      conn=DBConnectionPool.getDBConnection("AccessControlList.isAllowFirst");
585
      serialNumber=conn.getCheckOutSerialNumber();
586

    
587
      //select permission order from database
588
      pStmt = conn.prepareStatement(sql);
589

    
590
      //check every name in the array
591
      for (int i=0; i<lengthOfArray;i++)
592
      {
593
        //bind value
594
        pStmt.setString(1, principals[i]);//user name
595
        pStmt.setString(2, docId);//docid
596

    
597
        // if subtree, we need set subtree id
598
        if (!topLever)
599
        {
600
          pStmt.setLong(3, startId);
601
        }
602

    
603
        pStmt.execute();
604
        ResultSet rs = pStmt.getResultSet();
605
        hasRow=rs.next();
606
        if (hasRow)
607
        {
608
          //get the permission order from data base
609
          String permissionOrder=rs.getString(1);
610
          //if the permission order is "allowFirst
611
          if (permissionOrder.equalsIgnoreCase(AccessControlInterface.ALLOWFIRST))
612
          {
613
            pStmt.close();
614
            return true;
615
          }
616
          else
617
          {
618
            pStmt.close();
619
            return false;
620
          }
621
        }//if
622
      }//for
623
    }//try
624
    catch (SQLException e)
625
    {
626
      throw e;
627
    }
628
    finally
629
    {
630
      try
631
      {
632
        pStmt.close();
633
      }
634
      finally
635
      {
636
        DBConnectionPool.returnDBConnection(conn, serialNumber);
637
      }
638
    }
639

    
640
    //if reach here, means there is no permssion record for given names and
641
    //docid. So throw a exception.
642

    
643
    throw new Exception("There is no permission record for user"+principals[0]+
644
                        "at document "+docId);
645

    
646
  }//isAllowFirst
647

    
648
  /**
649
    * Check if the users array has allow rules for given users, docid and
650
    * permission.
651
    * If it has permission rule and ticket count is greater than 0, the ticket
652
    * number will decrease one for every allow rule
653
    * @param principals, list of names of principals to check for
654
    * @param docid, document identifier to check for
655
    * @param permission, the permssion need to check
656
    */
657
  private boolean hasAllowRule(String [] principals, String docId,
658
                                  int permission, long startId)
659
                  throws SQLException, Exception
660
 {
661
   int lengthOfArray=principals.length;
662
   boolean allow=false;//initial value is no allow rule
663
   ResultSet rs;
664
   PreparedStatement pStmt = null;
665
   int permissionValue=permission;
666
   int permissionValueInTable;
667
   int ticketCount;
668
   DBConnection conn = null;
669
   int serialNumber = -1;
670
   boolean topLever = false;
671
   String sql = null;
672
   if (startId == TOPLEVELSTARTNODEID)
673
   {
674
     // for toplevel
675
     topLever = true;
676
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
677
   "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid is NULL";
678
   }
679
   else
680
   {
681
     topLever =false;
682
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
683
      "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid = ?";
684
   }
685
   try
686
   {
687
     //check out DBConnection
688
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasAllowRule");
689
     serialNumber=conn.getCheckOutSerialNumber();
690
    //This sql statement will select entry with
691
    //begin_time<=currentTime<=end_time in xml_access table
692
    //If begin_time or end_time is null in table, isnull(begin_time, sysdate)
693
    //function will assign begin_time=sysdate
694
    pStmt = conn.prepareStatement(sql);
695
    //bind docid, perm_type
696
    pStmt.setString(1, docId);
697
    pStmt.setString(3, AccessControlInterface.ALLOW);
698

    
699
    // if subtree lever, need to set subTreeId
700
    if (!topLever)
701
    {
702
      pStmt.setLong(4, startId);
703
    }
704

    
705
    //bind every elenment in user name array
706
    for (int i=0;i<lengthOfArray; i++)
707
    {
708
      pStmt.setString(2, principals[i]);
709
      pStmt.execute();
710
      rs=pStmt.getResultSet();
711
      while (rs.next())//check every entry for one user
712
      {
713
        permissionValueInTable=rs.getInt(1);
714

    
715
        //permission is ok
716
        //the user have a permission to access the file
717
        if (( permissionValueInTable & permissionValue )== permissionValue )
718
        {
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 lower(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 lower(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
        //in order to ignore case sensitive, we transfer user to lower case
863
        if (user != null)
864
        {
865
          usersPackage[0]= user.toLowerCase();
866
          MetaCatUtil.debugMessage("after transfer to lower case(not null): "+
867
                                     usersPackage[0], 45);
868
        }
869
        else
870
        {
871
          usersPackage[0] = user;
872
          usersPackage[0]= user.toLowerCase();
873
          MetaCatUtil.debugMessage("after transfer to lower case(null): "+
874
                                     usersPackage[0], 45);
875
        }
876
        usersPackage[1]=AccessControlInterface.PUBLIC;
877
        //put groups element from index 0 to lengthOfPackage-3 into userPackage
878
        //from index 2 to lengthOfPackage-1
879
        for (int i=2; i<lengthOfPackage; i++)
880
        {
881
          //tansfer group to lower case too
882
          if (groups[i-2] != null)
883
          {
884
            usersPackage[i]=groups[i-2].toLowerCase();
885
          }
886
        } //for
887
      }//if user!=public
888
      else//use=public
889
      {
890
        lengthOfPackage=(groups.length)+1;
891
        usersPackage=new String [lengthOfPackage];
892
        //the first lements is public
893
        usersPackage[0]=AccessControlInterface.PUBLIC;
894
        //put groups element from index 0 to lengthOfPackage-2 into userPackage
895
        //from index 1 to lengthOfPackage-1
896
        for (int i=1; i<lengthOfPackage; i++)
897
        {
898
          if (groups[i-1] != null)
899
          {
900
            usersPackage[i]=groups[i-1].toLowerCase();
901
          }
902
        } //for
903
      }//else user=public
904

    
905
    }//if groups!=null
906
    else
907
    {
908
      //because no groups, the userPackage only need two elements
909
      //one is for user, the other is for public
910
      if (!user.equalsIgnoreCase(AccessControlInterface.PUBLIC))
911
      {
912
        lengthOfPackage=2;
913
        usersPackage=new String [lengthOfPackage];
914
        if (user != null)
915
        {
916
          usersPackage[0]=user.toLowerCase();
917
        }
918
        else
919
        {
920
          usersPackage[0]=user;
921
        }
922
        usersPackage[1]=AccessControlInterface.PUBLIC;
923
      }//if user!=public
924
      else //user==public
925
      {
926
        //only put public into array
927
        lengthOfPackage=1;
928
        usersPackage=new String [lengthOfPackage];
929
        usersPackage[0]=AccessControlInterface.PUBLIC;
930
      }
931
    }//else groups==null
932
    return usersPackage;
933
  }//createUsersPackage
934

    
935

    
936
  /**
937
   * A static method to get Hashtable which cointains a inlinedata object list that
938
   * user can't read it. The key is subtree id of inlinedata, the data is
939
   * internal file name for the inline data which is stored as docid
940
   * in xml_access table or data object doc id.
941
   * @param docidWithoutRev, metadata docid which should be the accessfileid
942
   *                         in the table
943
   * @param user , the name of user
944
   * @param groups, the group which the user belong to
945
   */
946
   public static Hashtable getUnReadableInlineDataIdList(String docidWithoutRev,
947
                                                   String user, String[] groups)
948
                                                throws Exception
949
   {
950
     Hashtable inlineDataList = getUnAccessableInlineDataIdList(docidWithoutRev,
951
                              user, groups, AccessControlInterface.READSTRING);
952

    
953
     return inlineDataList;
954
   }
955

    
956
   /**
957
  * A static method to get Hashtable which cointains a inline  data object list that
958
  * user can't overwrite it. The key is subtree id of inline data distrubition,
959
  * the value is internal file name for the inline data which is stored as docid
960
  * in xml_access table or data object doc id.
961
  * @param docidWithoutRev, metadata docid which should be the accessfileid
962
  *                         in the table
963
  * @param user , the name of user
964
  * @param groups, the group which the user belong to
965
  */
966
  public static Hashtable getUnWritableInlineDataIdList(String docidWithoutRev,
967
                                                  String user, String[] groups)
968
                                               throws Exception
969
  {
970
    Hashtable inlineDataList = getUnAccessableInlineDataIdList(docidWithoutRev,
971
                            user, groups, AccessControlInterface.WRITESTRING);
972

    
973
    return inlineDataList;
974
  }
975

    
976

    
977
   /*
978
    * This method will get hashtable which contains a unaccessable distribution
979
    * inlinedata object list
980
    */
981
   private static Hashtable getUnAccessableInlineDataIdList(String docid,
982
                               String user, String[] groups, String permission)
983
                             throws SQLException,McdbException, Exception
984
   {
985
      Hashtable unAccessbleIdList = new Hashtable();
986
      Hashtable allIdList = getAllInlineDataIdList(docid);
987
      Enumeration en = allIdList.keys();
988
      while (en.hasMoreElements())
989
      {
990
        String subTreeId = (String) en.nextElement();
991
        String fileId = (String) allIdList.get(subTreeId);
992
        //Here fileid is internal file id for line data. It stored in docid
993
        // field in xml_access table. so we don't need to delete rev
994
        PermissionController controller = new PermissionController(docid, false);
995
        if (!controller.hasPermissionForInlineData(user, groups, permission, fileId))
996
        {
997
          MetaCatUtil.debugMessage("Put subtree id " +subTreeId + " and " +
998
                                   "inline data file name " + fileId + " into "+
999
                                   "un"+permission+" hash", 20);
1000
          unAccessbleIdList.put(subTreeId, fileId);
1001
        }
1002
      }
1003
      return unAccessbleIdList;
1004
   }
1005

    
1006

    
1007
   /*
1008
    * This method will get a hash table from xml_access table for all records
1009
    * about the inline data. The key is subtree id and data is a inline internal
1010
    * file name
1011
    */
1012
   private static Hashtable getAllInlineDataIdList(String docid) throws SQLException
1013
   {
1014
     Hashtable inlineDataList = new Hashtable();
1015
     String sql = "SELECT subtreeid, docid FROM xml_access WHERE " +
1016
                   "accessfileid = ? AND subtreeid  IS NOT NULL";
1017
     PreparedStatement pStmt=null;
1018
     ResultSet rs=null;
1019
     DBConnection conn=null;
1020
     int serialNumber=-1;
1021
     try
1022
     {
1023
       //check out DBConnection
1024
       conn=DBConnectionPool.getDBConnection("PermissionControl.getDataSetId");
1025
       serialNumber=conn.getCheckOutSerialNumber();
1026
       pStmt=conn.prepareStatement(sql);
1027
       //bind the value to query
1028
       pStmt.setString(1, docid);
1029
       //execute the query
1030
       pStmt.execute();
1031
       rs=pStmt.getResultSet();
1032
       //process the result
1033
       while(rs.next())
1034
       {
1035
         String subTreeId = rs.getString(1);
1036
         String inlineDataId = rs.getString(2);
1037
         if (subTreeId != null && !subTreeId.trim().equals("") &&
1038
            inlineDataId != null && !inlineDataId.trim().equals(""))
1039
         {
1040
           inlineDataList.put(subTreeId, inlineDataId);
1041
         }
1042
      }//while
1043
     }//try
1044
     finally
1045
     {
1046
       try
1047
       {
1048
         pStmt.close();
1049
       }
1050
       finally
1051
       {
1052
         DBConnectionPool.returnDBConnection(conn, serialNumber);
1053
       }
1054
     }//finally
1055
     return inlineDataList;
1056
   }//getAllInlineDataIdList
1057
}
(49-49/62)