Project

General

Profile

Revision 1425

Added by Jing Tao over 18 years ago

Add a file to handle permission checking.

View differences:

src/edu/ucsb/nceas/metacat/PermissionController.java
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$'
12
 *     '$Date$'
13
 * '$Revision$'
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.Stack;
33
import java.util.Vector;
34

  
35
public class PermissionController
36
{
37
   private String docId = null;
38
   private boolean hasSubTreeAccessControl = false; // flag if has a subtree
39
                                                    // access for this docid
40
   private Vector subTreeList = new Vector();
41
   
42
   
43
   /**
44
    * Constructor for PermissionController
45
    * @param myDocid      the docid need to access
46
    */
47
   public PermissionController(String myDocid) throws SQLException
48
   {
49
     // Get rid of rev number
50
     docId = MetaCatUtil.getDocIdFromString(myDocid);
51
     hasSubTreeAccessControl = checkSubTreeAccessControl();
52
   }
53
   
54
   /*
55
    * Go through the access table and find if has subtree access control
56
    * if has, store the subtree into list and return true. Otherwise, 
57
    * return false
58
    */
59
  private boolean checkSubTreeAccessControl() throws SQLException
60
  {
61
    boolean flag = false;
62
    PreparedStatement pStmt=null;
63
    ResultSet rs=null;
64
    DBConnection conn=null;
65
    int serialNumber=-1;
66
    String query="SELECT subtreeid, startnodeid, endnodeid from xml_access " +
67
                 "where docid =? ";
68
    
69
    try
70
    {
71
      //check out DBConnection
72
      conn=DBConnectionPool.getDBConnection("PermissionController.hasSubTreeA");
73
      serialNumber=conn.getCheckOutSerialNumber();
74
      
75
      pStmt=conn.prepareStatement(query);
76
      //bind the value to query
77
      pStmt.setString(1, docId);
78
      //execute the query
79
      pStmt.execute();
80
      rs=pStmt.getResultSet();
81
      //process the result
82
      while (rs.next()) //
83
      {
84
        String subTreeId = rs.getString(1);
85
        MetaCatUtil.debugMessage("subtreeid: "+subTreeId, 25);
86
        long startNodeId = rs.getLong(2);
87
        MetaCatUtil.debugMessage("subtree startNodeId: "+startNodeId, 25);
88
        long endNodeId = rs.getLong(3);
89
        MetaCatUtil.debugMessage("subtree endNodeId: "+endNodeId, 25);
90
        // if startnodeid field in table is empty,startNodeId will be 0
91
        if (subTreeId != null && startNodeId != 0 && startNodeId != 0)
92
        {
93
          flag = true;// has subtree control
94
          SubTree tree = new SubTree();
95
          tree.setSubTreeId(subTreeId);
96
          tree.setStartNodeId(startNodeId);
97
          tree.setEndNodeId(endNodeId);
98
          subTreeList.add(tree);
99
         }
100
      }
101
    }//try
102
    finally
103
    {
104
      try
105
      {
106
        pStmt.close();
107
      }
108
      finally
109
      {
110
        DBConnectionPool.returnDBConnection(conn, serialNumber);
111
      }
112
    }
113
    return flag;
114
  }
115
   
116
  /**
117
    * Check from db connection if at least one of the list of @principals
118
    * @param user  the user name
119
    * @param groups  the groups which the use is in
120
    * @param myPermission  permission type to check for
121
    * @param principals list of names of principals to check for @permission
122
    */
123
  public boolean hasPermission(String user, String[]groups, String myPermission) 
124
                              throws SQLException, Exception
125
  {
126
    boolean hasPermission=false;
127
    String [] userPackage=null;
128
    int permission =AccessControlList.intValue(myPermission);
129
    
130
    //for the commnad line invocation
131
    if ((user==null) && (groups==null || groups.length==0))
132
    {
133
      return true;
134
    }
135
   
136
    //create a userpackage including user, public and group member
137
    userPackage=createUsersPackage(user, groups);
138
    
139
    //if the requested document is access documents and requested permission
140
    //is "write", the user should have "all" right
141
    if (isAccessDocument(docId) && (permission == AccessControlInterface.WRITE))
142
    {
143
      hasPermission = hasPermission(userPackage,docId, 7);// 7 is all permission
144
    }//if
145
    else //in other situation, just check the request permission
146
    {
147
    
148
      // Check for @permission on @docid for @user and/or @groups
149
      hasPermission = hasPermission(userPackage,docId, permission);
150
     
151
    }//else
152
    
153
    return hasPermission;
154
  }
155
 
156
  /**
157
    * Check from db connection if the users in String array @principals has
158
    * @permission on @docid* 
159
    * @param principals, names in userPakcage need to check for @permission
160
    * @param docid, document identifier to check on
161
    * @param permission, permission (write or all...) to check for 
162
    */
163
  private boolean hasPermission(String [] principals, String docId,
164
                                           int permission)
165
                         throws SQLException
166
  {
167
    try 
168
    {
169
      //first, if there is a docid owner in user package, return true
170
      //because doc owner has all permssion 
171
      if (containDocumentOwner(principals, docId))
172
      {
173
          
174
          return true;
175
      }
176
      
177
      //If there is no owner in user package, checking the table
178
      //check perm_order
179
      if (isAllowFirst(principals, docId))
180
      {
181
        
182
        if (hasExplicitDenyRule(principals, docId, permission))
183
        {
184
          //if it is allowfirst and has deny rule(either explicit )
185
          //deny access
186
          return false;
187
        }//if
188
        else if ( hasAllowRule(principals, docId, permission))
189
        {
190
          //if it is allowfirst and hasn't deny rule and has allow rule
191
          //allow access
192
          return true;
193
        }//else if
194
        else
195
        {
196
          //other situation deny access
197
          return false;
198
        }//else
199
     }//if isAllowFirst
200
     else //denyFirst
201
     {
202
       if (hasAllowRule(principals, docId, permission))
203
       {
204
         //if it is denyFirst and has allow rule, allow access
205
         return true;
206
       }
207
       else
208
       {
209
         //if it is denyfirst but no allow rule, deny access
210
         return false;
211
       }
212
     }//else denyfirst
213
    }//try
214
    catch (Exception e)
215
    {
216
      MetaCatUtil.debugMessage("There is a exception in hasPermission method: "
217
                         +e.getMessage(), 50);
218
    }
219
   
220
    return false;
221
  }//hasPermission
222
  
223
  /**
224
    * Check if a document id is a access document. Access document need user
225
    * has "all" permission to access it.
226
    * @param docId, the document id need to be checked
227
    */
228
    private boolean isAccessDocument(String docId) throws SQLException
229
    {
230
      //detele the rev number if docid contains it
231
      docId=MetaCatUtil.getDocIdFromString(docId);
232
      PreparedStatement pStmt=null;
233
      DBConnection conn = null;
234
      int serialNumber = -1;
235
      try
236
      {
237
        //check out DBConnection
238
        conn=DBConnectionPool.getDBConnection("AccessControlList.isAccessDoc");
239
        serialNumber=conn.getCheckOutSerialNumber();
240
        pStmt = conn.prepareStatement("select 'x' from xml_access where " +
241
                                      "accessfileid like '" + docId +  "'");
242
        pStmt.execute();
243
        ResultSet rs = pStmt.getResultSet();
244
        boolean hasRow = rs.next();
245
        pStmt.close();
246
        if(hasRow)
247
        {
248
          return true;
249
        }
250
      }
251
      catch(SQLException e)
252
      {
253
       
254
        throw new SQLException("AccessControlList.isAccessDocument " +
255
                     "Error checking" +
256
                     " on document " + docId + ". " + e.getMessage());
257
      }
258
      finally
259
      {
260
        try
261
        {
262
           pStmt.close();
263
        }
264
        finally
265
        {
266
          DBConnectionPool.returnDBConnection(conn, serialNumber);
267
        }
268
      }
269
      return false;
270
    }//isAccessDocument
271
     
272
  
273
  
274
  /**
275
    * Check if a stirng array contains a given documents' owner
276
    * @param principals, a string array storing the username, groups name and
277
    * public.
278
    * @param docid, the id of given documents 
279
    */ 
280
  private boolean containDocumentOwner( String [] principals, 
281
                                                              String docId)
282
                    throws SQLException
283
  {
284
    int lengthOfArray=principals.length;
285
    boolean hasRow; 
286
    PreparedStatement pStmt=null;
287
    DBConnection conn = null;
288
    int serialNumber = -1;
289
    
290
    try
291
    {
292
      //check out DBConnection
293
     conn=DBConnectionPool.getDBConnection("AccessControlList.containDocOnwer");
294
      serialNumber=conn.getCheckOutSerialNumber();
295
      pStmt = conn.prepareStatement(
296
                "SELECT 'x' FROM xml_documents " +
297
                "WHERE docid = ? AND user_owner = ?"); 
298
      //check every element in the string array too see if it conatains
299
      //the owner of document
300
      for (int i=0; i<lengthOfArray; i++)
301
      {
302
             
303
        // Bind the values to the query
304
        pStmt.setString(1, docId);
305
        pStmt.setString(2, principals[i]);
306

  
307
        pStmt.execute();
308
        ResultSet rs = pStmt.getResultSet();
309
        hasRow = rs.next();
310
        if (hasRow) 
311
        {
312
          pStmt.close();
313
          return true;
314
        }//if    
315
     
316
      }//for
317
    }//try
318
    catch (SQLException e) 
319
    {
320
        pStmt.close();
321
       
322
        throw new 
323
        SQLException("AccessControlList.hasPermission(). " +
324
                     "Error checking ownership for " + principals[0] +
325
                     " on document #" + docId + ". " + e.getMessage());
326
    }//catch
327
    finally
328
    {
329
      try
330
      {
331
        pStmt.close();
332
      }
333
      finally
334
      {
335
        DBConnectionPool.returnDBConnection(conn, serialNumber);
336
      }
337
    }
338
    return false; 
339
  }//containDocumentOwner
340
  
341
  /**
342
    * Check if the permission order for user at that documents is allowFirst
343
    * @param principals, list of names of principals to check for 
344
    * @param docid, document identifier to check for
345
    */
346
  private boolean isAllowFirst(String [] principals, String docId)
347
                  throws SQLException, Exception
348
  {
349
    int lengthOfArray=principals.length;
350
    boolean hasRow;
351
    PreparedStatement pStmt = null;
352
    DBConnection conn = null;
353
    int serialNumber = -1;
354
    try
355
    {
356
      //check out DBConnection
357
      conn=DBConnectionPool.getDBConnection("AccessControlList.isAllowFirst");
358
      serialNumber=conn.getCheckOutSerialNumber();
359
    
360
      //select permission order from database
361
      pStmt = conn.prepareStatement(
362
                "SELECT perm_order FROM xml_access " +
363
                "WHERE principal_name= ? AND docid = ?");
364
   
365
      //check every name in the array
366
      for (int i=0; i<lengthOfArray;i++)
367
      {
368
        //bind value
369
        pStmt.setString(1, principals[i]);//user name
370
        pStmt.setString(2, docId);//docid
371
    
372
        pStmt.execute();
373
        ResultSet rs = pStmt.getResultSet();
374
        hasRow=rs.next();
375
        if (hasRow)
376
        {
377
          //get the permission order from data base
378
          String permissionOrder=rs.getString(1);
379
          //if the permission order is "allowFirst
380
          if (permissionOrder.equalsIgnoreCase(AccessControlInterface.ALLOWFIRST))
381
          {
382
            pStmt.close();
383
            return true;
384
          }
385
          else
386
          {
387
            pStmt.close();
388
            return false;
389
          }
390
        }//if
391
      }//for
392
    }//try
393
    catch (SQLException e)
394
    {
395
      throw e;
396
    }
397
    finally
398
    {
399
      try
400
      {
401
        pStmt.close();
402
      }
403
      finally
404
      {
405
        DBConnectionPool.returnDBConnection(conn, serialNumber);
406
      }
407
    }
408
    
409
    //if reach here, means there is no permssion record for given names and 
410
    //docid. So throw a exception.
411
    
412
    throw new Exception("There is no permission record for user"+principals[0]+
413
                        "at document "+docId);
414
        
415
  }//isAllowFirst
416
  
417
  /**
418
    * Check if the users array has allow rules for given users, docid and 
419
    * permission.
420
    * If it has permission rule and ticket count is greater than 0, the ticket
421
    * number will decrease one for every allow rule
422
    * @param principals, list of names of principals to check for 
423
    * @param docid, document identifier to check for
424
    * @param permission, the permssion need to check
425
    */
426
  private boolean hasAllowRule(String [] principals, String docId, 
427
                                  int permission)
428
                  throws SQLException, Exception
429
 {
430
   int lengthOfArray=principals.length;
431
   boolean allow=false;//initial value is no allow rule
432
   ResultSet rs;
433
   PreparedStatement pStmt = null;
434
   int permissionValue=permission;
435
   int permissionValueInTable;
436
   int ticketCount;
437
   DBConnection conn = null;
438
   int serialNumber = -1;
439
   try
440
   {
441
     //check out DBConnection
442
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasAllowRule");
443
     serialNumber=conn.getCheckOutSerialNumber();
444
    //This sql statement will select entry with 
445
    //begin_time<=currentTime<=end_time in xml_access table
446
    //If begin_time or end_time is null in table, isnull(begin_time, sysdate)
447
    //function will assign begin_time=sysdate
448
    pStmt = conn.prepareStatement(
449
                "SELECT permission " +
450
                "FROM xml_access " +
451
                "WHERE docid = ? " + 
452
                "AND principal_name = ? " +
453
                "AND perm_type = ? ");
454
    //bind docid, perm_type
455
    pStmt.setString(1, docId);
456
    pStmt.setString(3, AccessControlInterface.ALLOW);
457
   
458
    //bind every elenment in user name array
459
    for (int i=0;i<lengthOfArray; i++)
460
    {
461
      pStmt.setString(2, principals[i]);
462
      pStmt.execute();
463
      rs=pStmt.getResultSet();
464
      while (rs.next())//check every entry for one user
465
      {
466
        permissionValueInTable=rs.getInt(1);
467
            
468
        //permission is ok  
469
        //the user have a permission to access the file
470
        if (( permissionValueInTable & permissionValue )== permissionValue )
471
        {
472
           allow=true;//has allow rule entry
473
        }//if
474
      }//while
475
    }//for
476
   }//try
477
   catch (SQLException sqlE)
478
   {
479
     throw sqlE;
480
   }
481
   catch (Exception e)
482
   {
483
     throw e;
484
   }
485
   finally
486
   {
487
     try
488
     {
489
       pStmt.close();
490
     }
491
     finally
492
     {
493
       DBConnectionPool.returnDBConnection(conn, serialNumber);
494
     }
495
   }
496
    return allow;
497
 }//hasAllowRule
498
 
499
 
500
   
501
   /**
502
    * Check if the users array has explicit deny rules for given users, docid 
503
    * and permission. That means the perm_type is deny and current time is
504
    * less than end_time and greater than begin time, or no time limit.
505
    * @param principals, list of names of principals to check for 
506
    * @param docid, document identifier to check for
507
    * @param permission, the permssion need to check
508
    */
509
  private boolean hasExplicitDenyRule(String [] principals, String docId, 
510
                                            int permission)
511
                  throws SQLException
512
 {
513
   int lengthOfArray=principals.length;
514
   ResultSet rs;
515
   PreparedStatement pStmt = null;
516
   int permissionValue=permission;
517
   int permissionValueInTable;
518
   DBConnection conn = null;
519
   int serialNumber = -1;
520
   
521
   try
522
   {
523
     //check out DBConnection
524
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasExplicitDeny");
525
     serialNumber=conn.getCheckOutSerialNumber();
526
   
527
     pStmt = conn.prepareStatement(
528
                "SELECT permission " +
529
                "FROM xml_access " +
530
                "WHERE docid = ? " + 
531
                "AND principal_name = ? " +
532
                "AND perm_type = ? ");
533
    //bind docid, perm_type
534
    pStmt.setString(1, docId);
535
    pStmt.setString(3, AccessControlInterface.DENY);
536
   
537
    //bind every elenment in user name array
538
    for (int i=0;i<lengthOfArray; i++)
539
    {
540
      pStmt.setString(2, principals[i]);
541
      pStmt.execute();
542
      rs=pStmt.getResultSet();
543
      while (rs.next())//check every entry for one user
544
      {
545
        permissionValueInTable=rs.getInt(1);
546
        
547
        //permission is ok the user doesn't have permission to access the file
548
        if (( permissionValueInTable & permissionValue )== permissionValue )
549
             
550
        {
551
           pStmt.close();
552
           return true;
553
         }//if
554
      }//while
555
    }//for
556
   }//try
557
   catch (SQLException e)
558
   {
559
     throw e;
560
   }//catch
561
   finally
562
   {
563
     try
564
     {
565
       pStmt.close();
566
     }
567
     finally
568
     {
569
       DBConnectionPool.returnDBConnection(conn, serialNumber);
570
     }
571
   }//finally
572
   return false;//no deny rule
573
  }//hasExplicitDenyRule 
574
   
575

  
576
  /**
577
    * Creat a users pakages to check permssion rule, user itself, public and
578
    * the gourps the user belong will be include in this package
579
    * @param user, the name of user
580
    * @param groups, the string array of the groups that user belong to
581
    */
582
  private String[] createUsersPackage(String user, String [] groups)
583
  {
584
    String [] usersPackage=null;
585
    int lengthOfPackage;
586
    
587
    if (groups!=null)
588
    {
589
      //if gouprs is not null and user is not public, we should create a array 
590
      //to store the groups and user and public. 
591
      //So the length of userPackage is the length of group plus two
592
      if (!user.equalsIgnoreCase(AccessControlInterface.PUBLIC))
593
      {
594
        lengthOfPackage=(groups.length)+2;
595
        usersPackage=new String [lengthOfPackage];
596
        //the first two elements is user self and public
597
        usersPackage[0]=user;
598
        usersPackage[1]=AccessControlInterface.PUBLIC;
599
        //put groups element from index 0 to lengthOfPackage-3 into userPackage
600
        //from index 2 to lengthOfPackage-1
601
        for (int i=2; i<lengthOfPackage; i++)
602
        {
603
          usersPackage[i]=groups[i-2];
604
        } //for
605
      }//if user!=public
606
      else//use=public
607
      {
608
        lengthOfPackage=(groups.length)+1;
609
        usersPackage=new String [lengthOfPackage];
610
        //the first lements is public
611
        usersPackage[0]=AccessControlInterface.PUBLIC;
612
        //put groups element from index 0 to lengthOfPackage-2 into userPackage
613
        //from index 1 to lengthOfPackage-1
614
        for (int i=1; i<lengthOfPackage; i++)
615
        {
616
          usersPackage[i]=groups[i-1];
617
        } //for
618
      }//else user=public
619
       
620
    }//if groups!=null
621
    else
622
    {
623
      //because no groups, the userPackage only need two elements
624
      //one is for user, the other is for public
625
      if (!user.equalsIgnoreCase(AccessControlInterface.PUBLIC))
626
      {
627
        lengthOfPackage=2;
628
        usersPackage=new String [lengthOfPackage];
629
        usersPackage[0]=user;
630
        usersPackage[1]=AccessControlInterface.PUBLIC;
631
      }//if user!=public
632
      else //user==public
633
      {
634
        //only put public into array
635
        lengthOfPackage=1;
636
        usersPackage=new String [lengthOfPackage];
637
        usersPackage[0]=AccessControlInterface.PUBLIC;
638
      }
639
    }//else groups==null
640
    return usersPackage;
641
  }//createUsersPackage
642
 
643
  /**
644
    * This method will return a data set id for given access id.
645
    * @param accessDocId, the accessDocId which need to be found data set id
646
   */
647
  private String getDataSetId(String accessDocId) 
648
                              throws SQLException
649
  {
650
    String dataSetId=null;
651
    PreparedStatement pStmt=null;
652
    ResultSet rs=null;
653
    DBConnection conn=null;
654
    int serialNumber=-1;
655
    String query="SELECT docId from xml_relation where subject = ? or "
656
                                                +"object = ?";
657
    
658
    try
659
    {
660
      //check out DBConnection
661
      conn=DBConnectionPool.getDBConnection("AccessControlList.getDataSetId");
662
      serialNumber=conn.getCheckOutSerialNumber();
663
      
664
      pStmt=conn.prepareStatement(query);
665
      //bind the value to query
666
      pStmt.setString(1, accessDocId);
667
      pStmt.setString(2, accessDocId);
668
      //execute the query
669
      pStmt.execute();
670
      rs=pStmt.getResultSet();
671
      //process the result
672
      if (rs.next()) //There are some records for the data set id for access id
673
      {
674
        dataSetId=rs.getString(1);
675
      }
676
      else //No data set id for the given access id in xml_relation table
677
      {
678
        dataSetId=null;
679
      }
680
    }//try
681
    finally
682
    {
683
      try
684
      {
685
        pStmt.close();
686
      }
687
      finally
688
      {
689
        DBConnectionPool.returnDBConnection(conn, serialNumber);
690
      }
691
    }
692
    return dataSetId;
693
  }//getDataPackageId() 
694
  
695
  /**
696
    * To create a part of query: "docid like '" +str1+ "', " +"docid like '" 
697
    * +str2+"'" ... We need to check user, group and public together for the 
698
    * permission. So we need the principal in an array and according the array
699
    * to create a part of query which will be used in other methods
700
    * @param principals, a string array storing the username, groups name and
701
    * public.
702
    */
703
   private String partQueryAboutDocId( String [] principals)
704
   {
705
     String partQuery="";
706
     int lengthOfArray=principals.length;
707
     
708
     for (int i=0;i<(lengthOfArray-1);i++)
709
     {
710
        partQuery=partQuery+"docid like '"+principals[i]+"',";
711
     }
712
     
713
     //the last one dosen't has "'"
714
     partQuery=partQuery+"docid like '"+principals[(lengthOfArray-1)]+"'";
715
     return partQuery;
716
     
717
   }
718
}
0 719

  

Also available in: Unified diff