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: 2005-10-10 11:06:55 -0700 (Mon, 10 Oct 2005) $'
13
 * '$Revision: 2663 $'
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
import org.apache.log4j.Logger;
39

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

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

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

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

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

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

    
88

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

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

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

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

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

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

    
122

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

    
126
    }//else
127

    
128
    return hasPermission;
129
  }
130

    
131

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

    
151
          return true;
152
      }
153

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

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

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

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

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

    
200
    return false;
201
  }//hasPermission
202

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

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

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

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

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

    
300

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

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

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

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

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

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

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

    
363

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

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

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

    
449
        }
450
        pStmt.close();
451

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

    
457
          return true;
458
        }
459

    
460
      }
461
      catch(SQLException e)
462
      {
463

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

    
480
      return false;
481
    }//isAccessDocument
482

    
483

    
484

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
649
  }//isAllowFirst
650

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

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

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

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

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

    
750

    
751

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

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

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

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

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

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

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

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

    
843

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

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

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

    
938

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

    
958
     return inlineDataList;
959
   }
960

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

    
980
    return inlineDataList;
981
  }
982

    
983

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

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

    
1034

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