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
 *
10
 *   '$Author: jones $'
11
 *     '$Date: 2006-11-10 10:25:38 -0800 (Fri, 10 Nov 2006) $'
12
 * '$Revision: 3077 $'
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 */
28
package edu.ucsb.nceas.metacat;
29

    
30
import java.sql.*;
31
import java.util.Enumeration;
32
import java.util.Hashtable;
33
import java.util.Stack;
34
import java.util.Vector;
35
import java.util.Iterator;
36

    
37
import org.apache.log4j.Logger;
38

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

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

    
49
   private static Logger logMetacat = Logger.getLogger(PermissionController.class);
50

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

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

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

    
87

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

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

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

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

    
113
    if (isAccessDocument(docId) && (permission == AccessControlInterface.WRITE))
114
    {
115

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

    
121

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

    
125
    }//else
126

    
127
    return hasPermission;
128
  }
129

    
130

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

    
150
          return true;
151
      }
152

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

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

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

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

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

    
199
    return false;
200
  }//hasPermission
201

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

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

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

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

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

    
299

    
300
        try
301
        {
302
          if (isAllowFirst(principals, docId, startId))
303
          {
304

    
305
            if (hasExplicitDenyRule(principals, docId, permission, startId ))
306
            {
307

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

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

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

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

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

    
362

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

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

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

    
448
        }
449
        pStmt.close();
450

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

    
456
          return true;
457
        }
458

    
459
      }
460
      catch(SQLException e)
461
      {
462

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

    
479
      return false;
480
    }//isAccessDocument
481

    
482

    
483

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

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

    
512
        // Bind the values to the query
513
        pStmt.setString(1, docId);
514
        pStmt.setString(2, principals[i]);
515
        logMetacat.info("the principle stack is : " +
516
                                  principals[i]);
517

    
518
        pStmt.execute();
519
        ResultSet rs = pStmt.getResultSet();
520
        hasRow = rs.next();
521
        if (hasRow)
522
        {
523
          pStmt.close();
524
           logMetacat.info("find the owner");
525
          return true;
526
        }//if
527

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

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

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

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

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

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

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

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

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

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

    
648
  }//isAllowFirst
649

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

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

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

    
717
        //permission is ok
718
        //the user have a permission to access the file
719
        if (( permissionValueInTable & permissionValue )== permissionValue )
720
        {
721

    
722
           allow=true;//has allow rule entry
723
        }//if
724
      }//while
725
    }//for
726
   }//try
727
   catch (SQLException sqlE)
728
   {
729
     throw sqlE;
730
   }
731
   catch (Exception e)
732
   {
733
     throw e;
734
   }
735
   finally
736
   {
737
     try
738
     {
739
       pStmt.close();
740
     }
741
     finally
742
     {
743
       DBConnectionPool.returnDBConnection(conn, serialNumber);
744
     }
745
   }
746
    return allow;
747
 }//hasAllowRule
748

    
749

    
750

    
751
   /**
752
    * Check if the users array has explicit deny rules for given users, docid
753
    * and permission. That means the perm_type is deny and current time is
754
    * less than end_time and greater than begin time, or no time limit.
755
    * @param principals, list of names of principals to check for
756
    * @param docid, document identifier to check for
757
    * @param permission, the permssion need to check
758
    */
759
  private boolean hasExplicitDenyRule(String [] principals, String docId,
760
                                      int permission, long startId)
761
                  throws SQLException
762
 {
763
   int lengthOfArray=principals.length;
764
   ResultSet rs;
765
   PreparedStatement pStmt = null;
766
   int permissionValue=permission;
767
   int permissionValueInTable;
768
   DBConnection conn = null;
769
   int serialNumber = -1;
770
   String sql = null;
771
   boolean topLevel = false;
772

    
773
   // decide top level or subtree level
774
   if (startId == TOPLEVELSTARTNODEID)
775
   {
776
     topLevel = true;
777
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
778
    "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid is NULL";
779
   }
780
   else
781
   {
782
     topLevel = false;
783
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
784
     "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid = ?";
785
   }
786

    
787
   try
788
   {
789
     //check out DBConnection
790
     conn=DBConnectionPool.getDBConnection("PermissionControl.hasExplicitDeny");
791
     serialNumber=conn.getCheckOutSerialNumber();
792

    
793
     pStmt = conn.prepareStatement(sql);
794
    //bind docid, perm_type
795
    pStmt.setString(1, docId);
796
    pStmt.setString(3, AccessControlInterface.DENY);
797

    
798
    // subtree level need to set up subtreeid
799
    if (!topLevel)
800
    {
801
      pStmt.setLong(4, startId);
802
    }
803

    
804
    //bind every elenment in user name array
805
    for (int i=0;i<lengthOfArray; i++)
806
    {
807
      pStmt.setString(2, principals[i]);
808
      pStmt.execute();
809
      rs=pStmt.getResultSet();
810
      while (rs.next())//check every entry for one user
811
      {
812
        permissionValueInTable=rs.getInt(1);
813

    
814
        //permission is ok the user doesn't have permission to access the file
815
        if (( permissionValueInTable & permissionValue )== permissionValue )
816

    
817
        {
818
           pStmt.close();
819
           return true;
820
         }//if
821
      }//while
822
    }//for
823
   }//try
824
   catch (SQLException e)
825
   {
826
     throw e;
827
   }//catch
828
   finally
829
   {
830
     try
831
     {
832
       pStmt.close();
833
     }
834
     finally
835
     {
836
       DBConnectionPool.returnDBConnection(conn, serialNumber);
837
     }
838
   }//finally
839
   return false;//no deny rule
840
  }//hasExplicitDenyRule
841

    
842

    
843
  /**
844
    * Creat a users pakages to check permssion rule, user itself, public and
845
    * the gourps the user belong will be include in this package
846
    * @param user, the name of user
847
    * @param groups, the string array of the groups that user belong to
848
    */
849
  private String[] createUsersPackage(String user, String [] groups)
850
  {
851
    String [] usersPackage=null;
852
    int lengthOfPackage;
853

    
854
    if (groups!=null)
855
    {
856
      //if gouprs is not null and user is not public, we should create a array
857
      //to store the groups and user and public.
858
      //So the length of userPackage is the length of group plus two
859
      if (!user.equalsIgnoreCase(AccessControlInterface.PUBLIC))
860
      {
861
        lengthOfPackage=(groups.length)+2;
862
        usersPackage=new String [lengthOfPackage];
863
        //the first two elements is user self and public
864
        //in order to ignore case sensitive, we transfer user to lower case
865
        if (user != null)
866
        {
867
          usersPackage[0]= user.toLowerCase();
868
          logMetacat.info("after transfer to lower case(not null): "+
869
                                     usersPackage[0]);
870
        }
871
        else
872
        {
873
          usersPackage[0] = user;
874
          usersPackage[0]= user.toLowerCase();
875
          logMetacat.info("after transfer to lower case(null): "+
876
                                     usersPackage[0]);
877
        }
878
        usersPackage[1]=AccessControlInterface.PUBLIC;
879
        //put groups element from index 0 to lengthOfPackage-3 into userPackage
880
        //from index 2 to lengthOfPackage-1
881
        for (int i=2; i<lengthOfPackage; i++)
882
        {
883
          //tansfer group to lower case too
884
          if (groups[i-2] != null)
885
          {
886
            usersPackage[i]=groups[i-2].toLowerCase();
887
          }
888
        } //for
889
      }//if user!=public
890
      else//use=public
891
      {
892
        lengthOfPackage=(groups.length)+1;
893
        usersPackage=new String [lengthOfPackage];
894
        //the first lements is public
895
        usersPackage[0]=AccessControlInterface.PUBLIC;
896
        //put groups element from index 0 to lengthOfPackage-2 into userPackage
897
        //from index 1 to lengthOfPackage-1
898
        for (int i=1; i<lengthOfPackage; i++)
899
        {
900
          if (groups[i-1] != null)
901
          {
902
            usersPackage[i]=groups[i-1].toLowerCase();
903
          }
904
        } //for
905
      }//else user=public
906

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

    
937

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

    
957
     return inlineDataList;
958
   }
959

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

    
979
    return inlineDataList;
980
  }
981

    
982

    
983
   /*
984
    * This method will get hashtable which contains a unaccessable distribution
985
    * inlinedata object list
986
    *
987
    * withRevision is used to get inline id list with or without revision number
988
    * e.g. when withRevision is true, temp.1.1.1, temp.1.1.2 would be returned
989
    * otherwise temp.1.1 and temp.1.2 would be returned.
990
    */
991
   private static Hashtable getUnAccessableInlineDataIdList(String docid,
992
                               String user, String[] groups, String permission,
993
                               boolean withRevision)
994
                             throws SQLException,McdbException, Exception
995
   {
996
      Hashtable unAccessbleIdList = new Hashtable();
997
      Hashtable allIdList = getAllInlineDataIdList(docid);
998
      Enumeration en = allIdList.keys();
999
      while (en.hasMoreElements())
1000
      {
1001
        String subTreeId = (String) en.nextElement();
1002
        String fileId = (String) allIdList.get(subTreeId);
1003
        //Here fileid is internal file id for line data. It stored in docid
1004
        // field in xml_access table. so we don't need to delete rev
1005
        PermissionController controller = new PermissionController(docid, false);
1006
        if (!controller.hasPermissionForInlineData(user, groups, permission, fileId))
1007
        {
1008
            if(withRevision)
1009
            {
1010
                logMetacat.info("Put subtree id " + subTreeId +
1011
                                         " and " + "inline data file name " +
1012
                                         fileId + " into " + "un" + permission +
1013
                                         " hash");
1014
                unAccessbleIdList.put(subTreeId, fileId);
1015

    
1016
            }
1017
            else
1018
            {
1019
                logMetacat.info("Put subtree id " + subTreeId +
1020
                                         " and " + "inline data file name " +
1021
                                         MetaCatUtil.
1022
                                         getInlineDataIdWithoutRev(fileId) +
1023
                                         " into " + "un" + permission +
1024
                                         " hash");
1025
                unAccessbleIdList.put(subTreeId, MetaCatUtil.
1026
                                      getInlineDataIdWithoutRev(fileId));
1027
            }
1028
        }
1029
      }
1030
      return unAccessbleIdList;
1031
   }
1032

    
1033

    
1034
   /*
1035
    * This method will get a hash table from xml_access table for all records
1036
    * about the inline data. The key is subtree id and data is a inline internal
1037
    * file name
1038
    */
1039
   private static Hashtable getAllInlineDataIdList(String docid) throws SQLException
1040
   {
1041
     Hashtable inlineDataList = new Hashtable();
1042
     String sql = "SELECT subtreeid, docid FROM xml_access WHERE " +
1043
                   "accessfileid = ? AND subtreeid  IS NOT NULL";
1044
     PreparedStatement pStmt=null;
1045
     ResultSet rs=null;
1046
     DBConnection conn=null;
1047
     int serialNumber=-1;
1048
     try
1049
     {
1050
       //check out DBConnection
1051
       conn=DBConnectionPool.getDBConnection("PermissionControl.getDataSetId");
1052
       serialNumber=conn.getCheckOutSerialNumber();
1053
       pStmt=conn.prepareStatement(sql);
1054
       //bind the value to query
1055
       pStmt.setString(1, docid);
1056
       //execute the query
1057
       pStmt.execute();
1058
       rs=pStmt.getResultSet();
1059
       //process the result
1060
       while(rs.next())
1061
       {
1062
         String subTreeId = rs.getString(1);
1063
         String inlineDataId = rs.getString(2);
1064
         if (subTreeId != null && !subTreeId.trim().equals("") &&
1065
            inlineDataId != null && !inlineDataId.trim().equals(""))
1066
         {
1067
           inlineDataList.put(subTreeId, inlineDataId);
1068
         }
1069
      }//while
1070
     }//try
1071
     finally
1072
     {
1073
       try
1074
       {
1075
         pStmt.close();
1076
       }
1077
       finally
1078
       {
1079
         DBConnectionPool.returnDBConnection(conn, serialNumber);
1080
       }
1081
     }//finally
1082
     return inlineDataList;
1083
   }//getAllInlineDataIdList
1084
}
(53-53/66)