Project

General

Profile

1 1425 tao
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A class that handles checking permssision for a document
4 2245 sgarg
               and subtree in a document
5
 *
6 1425 tao
 *  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$'
11
 *     '$Date$'
12
 * '$Revision$'
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 2245 sgarg
30 1425 tao
import java.sql.*;
31 1485 tao
import java.util.Enumeration;
32 1434 tao
import java.util.Hashtable;
33 1425 tao
import java.util.Stack;
34
import java.util.Vector;
35 2245 sgarg
import java.util.Iterator;
36 1425 tao
37 2663 sgarg
import org.apache.log4j.Logger;
38
39 1425 tao
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 2245 sgarg
46 1527 tao
   private long TOPLEVELSTARTNODEID = 0; //if start node is 0, means it is top
47
                                         //level document
48 2245 sgarg
49 2663 sgarg
   private static Logger logMetacat = Logger.getLogger(PermissionController.class);
50 2245 sgarg
51 1425 tao
   /**
52
    * Constructor for PermissionController
53
    * @param myDocid      the docid need to access
54
    */
55 1434 tao
   public PermissionController(String myDocid) throws McdbException
56 1425 tao
   {
57
     // Get rid of rev number
58 2045 tao
     docId = MetaCatUtil.getSmartDocId(myDocid);
59 2245 sgarg
     //hasSubTreeAccessControl = checkSubTreeAccessControl();
60 1425 tao
   }
61 2245 sgarg
62 1485 tao
   /**
63 2245 sgarg
    * 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 1485 tao
    * Return if a document has subtree access control
81
    */
82
   public boolean hasSubTreeAccessControl()
83
   {
84
     return hasSubTreeAccessControl;
85
   }
86 2245 sgarg
87
88 1425 tao
  /**
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 2245 sgarg
  public boolean hasPermission(String user, String[]groups, String myPermission)
95 1425 tao
                              throws SQLException, Exception
96
  {
97
    boolean hasPermission=false;
98
    String [] userPackage=null;
99
    int permission =AccessControlList.intValue(myPermission);
100 2245 sgarg
101 1425 tao
    //for the commnad line invocation
102
    if ((user==null) && (groups==null || groups.length==0))
103
    {
104
      return true;
105
    }
106 2245 sgarg
107 1425 tao
    //create a userpackage including user, public and group member
108
    userPackage=createUsersPackage(user, groups);
109 2245 sgarg
110 1425 tao
    //if the requested document is access documents and requested permission
111
    //is "write", the user should have "all" right
112 2245 sgarg
113 1425 tao
    if (isAccessDocument(docId) && (permission == AccessControlInterface.WRITE))
114
    {
115 2245 sgarg
116 1425 tao
      hasPermission = hasPermission(userPackage,docId, 7);// 7 is all permission
117
    }//if
118
    else //in other situation, just check the request permission
119
    {
120 2245 sgarg
121
122 1425 tao
      // Check for @permission on @docid for @user and/or @groups
123
      hasPermission = hasPermission(userPackage,docId, permission);
124 2245 sgarg
125 1425 tao
    }//else
126 2245 sgarg
127 1425 tao
    return hasPermission;
128
  }
129 2245 sgarg
130
131 1425 tao
  /**
132
    * Check from db connection if the users in String array @principals has
133 2245 sgarg
    * @permission on @docid*
134 1425 tao
    * @param principals, names in userPakcage need to check for @permission
135
    * @param docid, document identifier to check on
136 2245 sgarg
    * @param permission, permission (write or all...) to check for
137 1425 tao
    */
138
  private boolean hasPermission(String [] principals, String docId,
139
                                           int permission)
140
                         throws SQLException
141
  {
142 1527 tao
    long startId = TOPLEVELSTARTNODEID;// this is for top level, so startid is 0
143 2245 sgarg
    try
144 1425 tao
    {
145
      //first, if there is a docid owner in user package, return true
146 2245 sgarg
      //because doc owner has all permssion
147 1425 tao
      if (containDocumentOwner(principals, docId))
148
      {
149 2245 sgarg
150 1425 tao
          return true;
151
      }
152 2245 sgarg
153 1425 tao
      //If there is no owner in user package, checking the table
154
      //check perm_order
155 1527 tao
      if (isAllowFirst(principals, docId, startId))
156 1425 tao
      {
157 2245 sgarg
158 1527 tao
        if (hasExplicitDenyRule(principals, docId, permission, startId))
159 1425 tao
        {
160
          //if it is allowfirst and has deny rule(either explicit )
161
          //deny access
162 2245 sgarg
163 1425 tao
          return false;
164
        }//if
165 1527 tao
        else if ( hasAllowRule(principals, docId, permission, startId))
166 1425 tao
        {
167
          //if it is allowfirst and hasn't deny rule and has allow rule
168
          //allow access
169 2245 sgarg
170 1425 tao
          return true;
171
        }//else if
172
        else
173
        {
174
          //other situation deny access
175 2245 sgarg
176 1425 tao
          return false;
177
        }//else
178
     }//if isAllowFirst
179
     else //denyFirst
180
     {
181 1527 tao
       if (hasAllowRule(principals, docId, permission, startId))
182 1425 tao
       {
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 2663 sgarg
      logMetacat.warn("There is a exception in hasPermission method: "
196
                         +e.getMessage());
197 1425 tao
    }
198 2245 sgarg
199 1425 tao
    return false;
200
  }//hasPermission
201 2245 sgarg
202 1425 tao
  /**
203 2245 sgarg
   *  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 1485 tao
   * 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 1492 tao
    boolean flag = true;
240 1485 tao
    // Get unaccessble subtree for this user
241 2245 sgarg
    Hashtable unaccessableSubTree = hasUnaccessableSubTree(user, groups,
242 1485 tao
                                                           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 1492 tao
      // nodeid in unaccessablesubtree, return false
250 1485 tao
      if ( nodeId >= start && nodeId <= stop)
251
      {
252 1492 tao
        flag = false;
253 1485 tao
        break;
254
      }
255
    }
256
    return flag;
257
  }
258
  /**
259 2245 sgarg
   * This method will return a hasTable of subtree which user doesn't has the
260 1434 tao
   * 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 2245 sgarg
  public Hashtable hasUnaccessableSubTree(String user, String[] groups,
266 1434 tao
                                       String myPermission) throws McdbException
267
  {
268
    Hashtable resultUnaccessableSubTree = new Hashtable();
269
    String [] principals=null;
270
    int permission =AccessControlList.intValue(myPermission);
271 2245 sgarg
272 1434 tao
    //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 2245 sgarg
278 1434 tao
    //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 2245 sgarg
293 1434 tao
    // 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 1527 tao
      long startId = tree.getStartNodeId();
298 2245 sgarg
299
300 1434 tao
        try
301
        {
302 1527 tao
          if (isAllowFirst(principals, docId, startId))
303 1434 tao
          {
304 2245 sgarg
305 1527 tao
            if (hasExplicitDenyRule(principals, docId, permission, startId ))
306 1434 tao
            {
307 2245 sgarg
308 1434 tao
             //if it is allowfirst and has deny rule
309
              // put the subtree into unaccessable vector
310 1527 tao
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
311 1434 tao
              {
312 1527 tao
                resultUnaccessableSubTree.put(new Long(startId), tree);
313 1434 tao
              }
314
            }//if
315 1527 tao
            else if ( hasAllowRule(principals, docId, permission, startId))
316 1434 tao
            {
317
              //if it is allowfirst and hasn't deny rule and has allow rule
318
              //allow access do nothing
319 2245 sgarg
320 1434 tao
            }//else if
321
            else
322
            {
323
              //other situation deny access
324 1527 tao
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
325 1434 tao
              {
326 1527 tao
                resultUnaccessableSubTree.put(new Long(startId), tree);
327 1434 tao
              }
328 2245 sgarg
329 1434 tao
            }//else
330
          }//if isAllowFirst
331
          else //denyFirst
332
          {
333 1527 tao
            if (hasAllowRule(principals, docId, permission,startId))
334 1434 tao
            {
335
              //if it is denyFirst and has allow rule, allow access, do nothing
336 2245 sgarg
337 1434 tao
            }
338
            else
339
            {
340
              //if it is denyfirst but no allow rule, deny access
341
              // add into vector
342 1527 tao
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
343 1434 tao
              {
344 1527 tao
                resultUnaccessableSubTree.put(new Long(startId), tree);
345 1434 tao
              }
346
            }
347
          }//else denyfirst
348
        }//try
349
        catch( Exception e)
350
        {
351 2663 sgarg
          logMetacat.error("error in PermissionControl.has" +
352
                                   "UnaccessableSubTree "+e.getMessage());
353 1434 tao
          throw new McdbException(e);
354
        }
355 2245 sgarg
356 1434 tao
    }//for
357 2245 sgarg
    // merge the subtree if a subtree is another subtree'subtree
358 1521 tao
    resultUnaccessableSubTree = mergeEquivalentSubtree(resultUnaccessableSubTree);
359 1434 tao
    return resultUnaccessableSubTree;
360
  }//hasUnaccessableSubtree
361 2245 sgarg
362
363
  /*
364 1513 tao
   * 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 1521 tao
  private Hashtable mergeEquivalentSubtree(Hashtable unAccessSubTree)
369 1513 tao
  {
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 2245 sgarg
390 1513 tao
        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 2663 sgarg
            logMetacat.info("the subtree: "+ treeId +
403 1513 tao
                                     " need to be get rid of from unaccessable"+
404
                                     " subtree list becuase it is a subtree of"+
405 2663 sgarg
                                     " another subtree in the list");
406 1513 tao
            break;
407
          }//if
408
        }//while
409
        // if not need to delete, put the subtree into hash
410
        if (!needDelete)
411
        {
412 1527 tao
          newSubTreeHash.put(new Long(startId), tree);
413 1513 tao
        }
414
        //reset needDelete
415
        needDelete = false;
416
      }//while
417
      return newSubTreeHash;
418
    }//else
419
  }
420 2245 sgarg
421 1434 tao
  /**
422 1425 tao
    * 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 1434 tao
        conn=DBConnectionPool.getDBConnection("PermissionControl.isAccessDoc");
437 1425 tao
        serialNumber=conn.getCheckOutSerialNumber();
438 1541 tao
        pStmt = conn.prepareStatement("select doctype from xml_documents where " +
439
                                      "docid like '" + docId +  "'");
440 1425 tao
        pStmt.execute();
441
        ResultSet rs = pStmt.getResultSet();
442
        boolean hasRow = rs.next();
443 1541 tao
        String doctype = null;
444 2245 sgarg
        if (hasRow)
445 1541 tao
        {
446
          doctype = rs.getString(1);
447 2245 sgarg
448 1541 tao
        }
449 1425 tao
        pStmt.close();
450 2245 sgarg
451 1541 tao
        // if it is an access document
452
        if (doctype != null && ((MetaCatUtil.getOptionList(MetaCatUtil.
453
           getOption("accessdoctype")).contains(doctype))))
454 1425 tao
        {
455 2245 sgarg
456 1425 tao
          return true;
457
        }
458 2245 sgarg
459 1425 tao
      }
460
      catch(SQLException e)
461
      {
462 2245 sgarg
463 1434 tao
        throw new SQLException("PermissionControl.isAccessDocument " +
464 1425 tao
                     "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 2245 sgarg
479 1425 tao
      return false;
480
    }//isAccessDocument
481 2245 sgarg
482
483
484 1425 tao
  /**
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 2245 sgarg
    * @param docid, the id of given documents
489
    */
490 1434 tao
  private boolean containDocumentOwner( String[] principals, String docId)
491 1425 tao
                    throws SQLException
492
  {
493
    int lengthOfArray=principals.length;
494 2245 sgarg
    boolean hasRow;
495 1425 tao
    PreparedStatement pStmt=null;
496
    DBConnection conn = null;
497
    int serialNumber = -1;
498 2245 sgarg
499 1425 tao
    try
500
    {
501
      //check out DBConnection
502 1434 tao
     conn=DBConnectionPool.getDBConnection("PermissionControl.containDocOnwer");
503 1425 tao
      serialNumber=conn.getCheckOutSerialNumber();
504
      pStmt = conn.prepareStatement(
505
                "SELECT 'x' FROM xml_documents " +
506 2245 sgarg
                "WHERE docid = ? AND lower(user_owner) = ?");
507 1425 tao
      //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 2245 sgarg
512 1425 tao
        // Bind the values to the query
513
        pStmt.setString(1, docId);
514
        pStmt.setString(2, principals[i]);
515 2663 sgarg
        logMetacat.info("the principle stack is : " +
516
                                  principals[i]);
517 1425 tao
518
        pStmt.execute();
519
        ResultSet rs = pStmt.getResultSet();
520
        hasRow = rs.next();
521 2245 sgarg
        if (hasRow)
522 1425 tao
        {
523
          pStmt.close();
524 2663 sgarg
           logMetacat.info("find the owner");
525 1425 tao
          return true;
526 2245 sgarg
        }//if
527
528 1425 tao
      }//for
529
    }//try
530 2245 sgarg
    catch (SQLException e)
531 1425 tao
    {
532
        pStmt.close();
533 2245 sgarg
534
        throw new
535 1434 tao
        SQLException("PermissionControl.hasPermission(). " +
536 1425 tao
                     "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 2245 sgarg
    return false;
551 1425 tao
  }//containDocumentOwner
552 2245 sgarg
553 1425 tao
  /**
554
    * Check if the permission order for user at that documents is allowFirst
555 2245 sgarg
    * @param principals, list of names of principals to check for
556 1425 tao
    * @param docid, document identifier to check for
557
    */
558 2245 sgarg
  private boolean isAllowFirst(String [] principals, String docId,
559 1527 tao
                               long startId)
560 1425 tao
                  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 1434 tao
    String sql = null;
568
    boolean topLever =false;
569 1527 tao
    if (startId == TOPLEVELSTARTNODEID)
570 1434 tao
    {
571
      //top level
572
      topLever = true;
573
      sql = "SELECT perm_order FROM xml_access " +
574 2045 tao
    "WHERE lower(principal_name) = ? AND docid = ? AND startnodeid is NULL";
575 1434 tao
    }
576
    else
577
    {
578
      //sub tree level
579
      sql = "SELECT perm_order FROM xml_access " +
580 2045 tao
        "WHERE lower(principal_name)= ? AND docid = ? AND startnodeid = ?";
581 1434 tao
    }
582 2245 sgarg
583 1425 tao
    try
584
    {
585
      //check out DBConnection
586
      conn=DBConnectionPool.getDBConnection("AccessControlList.isAllowFirst");
587
      serialNumber=conn.getCheckOutSerialNumber();
588 2245 sgarg
589 1425 tao
      //select permission order from database
590 1434 tao
      pStmt = conn.prepareStatement(sql);
591 2245 sgarg
592 1425 tao
      //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 2245 sgarg
599
        // if subtree, we need set subtree id
600 1434 tao
        if (!topLever)
601
        {
602 1527 tao
          pStmt.setLong(3, startId);
603 1434 tao
        }
604 2245 sgarg
605 1425 tao
        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 2245 sgarg
642
    //if reach here, means there is no permssion record for given names and
643 1425 tao
    //docid. So throw a exception.
644 2245 sgarg
645 1425 tao
    throw new Exception("There is no permission record for user"+principals[0]+
646
                        "at document "+docId);
647 2245 sgarg
648 1425 tao
  }//isAllowFirst
649 2245 sgarg
650 1425 tao
  /**
651 2245 sgarg
    * Check if the users array has allow rules for given users, docid and
652 1425 tao
    * 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 2245 sgarg
    * @param principals, list of names of principals to check for
656 1425 tao
    * @param docid, document identifier to check for
657
    * @param permission, the permssion need to check
658
    */
659 2245 sgarg
  private boolean hasAllowRule(String [] principals, String docId,
660 1527 tao
                                  int permission, long startId)
661 1425 tao
                  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 1434 tao
   boolean topLever = false;
673
   String sql = null;
674 1527 tao
   if (startId == TOPLEVELSTARTNODEID)
675 1434 tao
   {
676
     // for toplevel
677
     topLever = true;
678 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
679 2045 tao
   "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid is NULL";
680 1434 tao
   }
681
   else
682
   {
683
     topLever =false;
684 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
685 2045 tao
      "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid = ?";
686 1434 tao
   }
687 1425 tao
   try
688
   {
689
     //check out DBConnection
690
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasAllowRule");
691
     serialNumber=conn.getCheckOutSerialNumber();
692 2245 sgarg
    //This sql statement will select entry with
693 1425 tao
    //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 1434 tao
    pStmt = conn.prepareStatement(sql);
697 1425 tao
    //bind docid, perm_type
698
    pStmt.setString(1, docId);
699
    pStmt.setString(3, AccessControlInterface.ALLOW);
700 2245 sgarg
701 1434 tao
    // if subtree lever, need to set subTreeId
702
    if (!topLever)
703
    {
704 1527 tao
      pStmt.setLong(4, startId);
705 1434 tao
    }
706 2245 sgarg
707 1425 tao
    //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 2245 sgarg
717
        //permission is ok
718 1425 tao
        //the user have a permission to access the file
719
        if (( permissionValueInTable & permissionValue )== permissionValue )
720
        {
721 2245 sgarg
722 1425 tao
           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 2245 sgarg
749
750
751 1425 tao
   /**
752 2245 sgarg
    * Check if the users array has explicit deny rules for given users, docid
753 1425 tao
    * 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 2245 sgarg
    * @param principals, list of names of principals to check for
756 1425 tao
    * @param docid, document identifier to check for
757
    * @param permission, the permssion need to check
758
    */
759 2245 sgarg
  private boolean hasExplicitDenyRule(String [] principals, String docId,
760 1527 tao
                                      int permission, long startId)
761 1425 tao
                  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 1434 tao
   String sql = null;
771
   boolean topLevel = false;
772 2245 sgarg
773 1434 tao
   // decide top level or subtree level
774 1527 tao
   if (startId == TOPLEVELSTARTNODEID)
775 1434 tao
   {
776
     topLevel = true;
777 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
778 2045 tao
    "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid is NULL";
779 1434 tao
   }
780
   else
781
   {
782
     topLevel = false;
783 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
784 2045 tao
     "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid = ?";
785 1434 tao
   }
786 2245 sgarg
787 1425 tao
   try
788
   {
789
     //check out DBConnection
790 1434 tao
     conn=DBConnectionPool.getDBConnection("PermissionControl.hasExplicitDeny");
791 1425 tao
     serialNumber=conn.getCheckOutSerialNumber();
792 2245 sgarg
793 1434 tao
     pStmt = conn.prepareStatement(sql);
794 1425 tao
    //bind docid, perm_type
795
    pStmt.setString(1, docId);
796
    pStmt.setString(3, AccessControlInterface.DENY);
797 2245 sgarg
798 1434 tao
    // subtree level need to set up subtreeid
799
    if (!topLevel)
800
    {
801 1527 tao
      pStmt.setLong(4, startId);
802 1434 tao
    }
803 2245 sgarg
804 1425 tao
    //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 2245 sgarg
814 1425 tao
        //permission is ok the user doesn't have permission to access the file
815
        if (( permissionValueInTable & permissionValue )== permissionValue )
816 2245 sgarg
817 1425 tao
        {
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 2245 sgarg
  }//hasExplicitDenyRule
841 1425 tao
842 2245 sgarg
843 1425 tao
  /**
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 2245 sgarg
854 1425 tao
    if (groups!=null)
855
    {
856 2245 sgarg
      //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 1425 tao
      //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 2045 tao
        //in order to ignore case sensitive, we transfer user to lower case
865
        if (user != null)
866
        {
867
          usersPackage[0]= user.toLowerCase();
868 2663 sgarg
          logMetacat.info("after transfer to lower case(not null): "+
869
                                     usersPackage[0]);
870 2045 tao
        }
871
        else
872
        {
873
          usersPackage[0] = user;
874
          usersPackage[0]= user.toLowerCase();
875 2663 sgarg
          logMetacat.info("after transfer to lower case(null): "+
876
                                     usersPackage[0]);
877 2045 tao
        }
878 1425 tao
        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 2045 tao
          //tansfer group to lower case too
884
          if (groups[i-2] != null)
885
          {
886
            usersPackage[i]=groups[i-2].toLowerCase();
887
          }
888 1425 tao
        } //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 2045 tao
          if (groups[i-1] != null)
901
          {
902
            usersPackage[i]=groups[i-1].toLowerCase();
903
          }
904 1425 tao
        } //for
905
      }//else user=public
906 2245 sgarg
907 1425 tao
    }//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 2045 tao
        if (user != null)
917
        {
918
          usersPackage[0]=user.toLowerCase();
919
        }
920
        else
921
        {
922
          usersPackage[0]=user;
923
        }
924 1425 tao
        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 2245 sgarg
937
938 1425 tao
  /**
939 2245 sgarg
   * 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 1425 tao
   */
948 2245 sgarg
   public static Hashtable getUnReadableInlineDataIdList(String docidWithoutRev,
949 2291 sgarg
                                                   String user, String[] groups,
950
                                                   boolean withRevision)
951 2245 sgarg
                                                throws Exception
952
   {
953
     Hashtable inlineDataList = getUnAccessableInlineDataIdList(docidWithoutRev,
954 2291 sgarg
                              user, groups, AccessControlInterface.READSTRING,
955
                              withRevision);
956 2245 sgarg
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 2291 sgarg
                                                  String user, String[] groups,
972
                                                  boolean withRevision)
973 2245 sgarg
                                               throws Exception
974 1425 tao
  {
975 2245 sgarg
    Hashtable inlineDataList = getUnAccessableInlineDataIdList(docidWithoutRev,
976 2291 sgarg
                            user, groups, AccessControlInterface.WRITESTRING,
977
                            withRevision);
978 2245 sgarg
979
    return inlineDataList;
980
  }
981
982
983
   /*
984
    * This method will get hashtable which contains a unaccessable distribution
985
    * inlinedata object list
986 2291 sgarg
    *
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 2245 sgarg
    */
991
   private static Hashtable getUnAccessableInlineDataIdList(String docid,
992 2291 sgarg
                               String user, String[] groups, String permission,
993
                               boolean withRevision)
994 2245 sgarg
                             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 1425 tao
      {
1001 2245 sgarg
        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 2291 sgarg
            if(withRevision)
1009
            {
1010 2663 sgarg
                logMetacat.info("Put subtree id " + subTreeId +
1011 2291 sgarg
                                         " and " + "inline data file name " +
1012
                                         fileId + " into " + "un" + permission +
1013 2663 sgarg
                                         " hash");
1014 2291 sgarg
                unAccessbleIdList.put(subTreeId, fileId);
1015
1016
            }
1017
            else
1018
            {
1019 2663 sgarg
                logMetacat.info("Put subtree id " + subTreeId +
1020 2291 sgarg
                                         " and " + "inline data file name " +
1021
                                         MetaCatUtil.
1022
                                         getInlineDataIdWithoutRev(fileId) +
1023
                                         " into " + "un" + permission +
1024 2663 sgarg
                                         " hash");
1025 2291 sgarg
                unAccessbleIdList.put(subTreeId, MetaCatUtil.
1026
                                      getInlineDataIdWithoutRev(fileId));
1027
            }
1028 2245 sgarg
        }
1029 1425 tao
      }
1030 2245 sgarg
      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 1425 tao
}