Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A class that handles checking permssision for a document
4
               and subtree in a document
5
 *
6
 *  Copyright: 2000 Regents of the University of California and the
7
 *             National Center for Ecological Analysis and Synthesis
8
 *    Authors: Chad Berkley
9
 *
10
 *   '$Author: berkley $'
11
 *     '$Date: 2010-06-08 12:34:30 -0700 (Tue, 08 Jun 2010) $'
12
 * '$Revision: 5374 $'
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 */
28
package edu.ucsb.nceas.metacat;
29

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

    
37
import org.apache.log4j.Logger;
38

    
39
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlForSingleFile;
40
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlInterface;
41
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlList;
42
import edu.ucsb.nceas.metacat.database.DBConnection;
43
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
44
import edu.ucsb.nceas.metacat.properties.PropertyService;
45
import edu.ucsb.nceas.metacat.service.SessionService;
46
import edu.ucsb.nceas.metacat.util.DocumentUtil;
47
import edu.ucsb.nceas.metacat.util.MetacatUtil;
48
import edu.ucsb.nceas.metacat.util.SessionData;
49
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
50
import edu.ucsb.nceas.metacat.shared.ServiceException;
51

    
52
public class PermissionController
53
{
54
   private String docId = null;
55
   private boolean hasSubTreeAccessControl = false; // flag if has a subtree
56
                                                    // access for this docid
57
   private Vector subTreeList = new Vector();
58

    
59
   private static final long TOPLEVELSTARTNODEID = 0; //if start node is 0, means it is top
60
                                         //level document
61

    
62
   private static Logger logMetacat = Logger.getLogger(PermissionController.class);
63

    
64
   /**
65
    * Constructor for PermissionController
66
    * @param myDocid      the docid need to access
67
    */
68
   public PermissionController(String myDocid) throws McdbException
69
   {
70
     // Get rid of rev number
71
     docId = DocumentUtil.getSmartDocId(myDocid);
72
     //hasSubTreeAccessControl = checkSubTreeAccessControl();
73
   }
74

    
75
   /**
76
    * Constructor for PermssionController
77
    * @param myDocid String
78
    * @param needDeleteRev boolean
79
    */
80
   public PermissionController(String myDocid, boolean needDeleteRevFromDocid)
81
   {
82
     if (!needDeleteRevFromDocid)
83
     {
84
       docId = myDocid;
85
     }
86
     else
87
     {
88
         docId = DocumentUtil.getDocIdFromAccessionNumber(myDocid);
89
     }
90
   }
91

    
92
   /**
93
    * Return if a document has subtree access control
94
    */
95
   public boolean hasSubTreeAccessControl()
96
   {
97
     return hasSubTreeAccessControl;
98
   }
99

    
100
   public boolean hasPermission(String sessionId, String myPermission) throws SQLException {
101
       SessionData sessionData = null;
102
       sessionData = SessionService.getInstance().getRegisteredSession(sessionId);
103
       if (sessionData == null) {
104
           return false;
105
       }
106
	   
107
	   return hasPermission(sessionData.getUserName(), sessionData.getGroupNames(), myPermission); 
108
   }
109
   
110

    
111
  /**
112
    * Check from db connection if at least one of the list of @principals
113
    * @param user  the user name
114
    * @param groups  the groups which the use is in
115
    * @param myPermission  permission type to check for
116
    */
117
  public boolean hasPermission(String user, String[]groups, String myPermission)
118
                              throws SQLException //, Exception
119
  {
120
    boolean hasPermission=false;
121
    String [] userPackage=null;
122
    int permission =AccessControlList.intValue(myPermission);
123

    
124
    //for the commnad line invocation
125
    if ((user==null) && (groups==null || groups.length==0))
126
    {
127
      return true;
128
    }
129

    
130
    //create a userpackage including user, public and group member
131
    userPackage=createUsersPackage(user, groups);
132

    
133
    //if the requested document is access documents and requested permission
134
    //is "write", the user should have "all" right
135

    
136
    if (isAccessDocument(docId) && (permission == AccessControlInterface.WRITE))
137
    {
138

    
139
      hasPermission = hasPermission(userPackage,docId, 7);// 7 is all permission
140
    }//if
141
    else //in other situation, just check the request permission
142
    {
143

    
144

    
145
      // Check for @permission on @docid for @user and/or @groups
146
      hasPermission = hasPermission(userPackage,docId, permission);
147

    
148
    }//else
149

    
150
    return hasPermission;
151
  }
152

    
153

    
154
  /**
155
    * Check from db connection if the users in String array @principals has
156
    * @permission on @docid*
157
    * @param principals, names in userPakcage need to check for @permission
158
    * @param docid, document identifier to check on
159
    * @param permission, permission (write or all...) to check for
160
    */
161
  private boolean hasPermission(String [] principals, String docId,
162
                                           int permission)
163
                         throws SQLException
164
  {
165
    long startId = TOPLEVELSTARTNODEID;// this is for top level, so startid is 0
166
    try
167
    {
168
      //first, if there is a docid owner in user package, return true
169
      //because doc owner has all permssion
170
      if (containDocumentOwner(principals, docId))
171
      {
172

    
173
          return true;
174
      }
175

    
176
      //If there is no owner in user package, checking the table
177
      //check perm_order
178
      if (isAllowFirst(principals, docId, startId))
179
      {
180

    
181
        if (hasExplicitDenyRule(principals, docId, permission, startId))
182
        {
183
          //if it is allowfirst and has deny rule(either explicit )
184
          //deny access
185

    
186
          return false;
187
        }//if
188
        else if ( hasAllowRule(principals, docId, permission, startId))
189
        {
190
          //if it is allowfirst and hasn't deny rule and has allow rule
191
          //allow access
192

    
193
          return true;
194
        }//else if
195
        else
196
        {
197
          //other situation deny access
198

    
199
          return false;
200
        }//else
201
     }//if isAllowFirst
202
     else //denyFirst
203
     {
204
       if (hasAllowRule(principals, docId, permission, startId))
205
       {
206
         //if it is denyFirst and has allow rule, allow access
207
         return true;
208
       }
209
       else
210
       {
211
         //if it is denyfirst but no allow rule, deny access
212
         return false;
213
       }
214
     }//else denyfirst
215
    }//try
216
    catch (Exception e)
217
    {
218
      logMetacat.warn("PermissionController.hasPermission - There is a exception in hasPermission method: "
219
                         +e.getMessage());
220
    }
221

    
222
    return false;
223
  }//hasPermission
224

    
225
  /**
226
   *  Method to check if a person has permission to a inline data file
227
   * @param user String
228
   * @param groups String[]
229
   * @param myPermission String
230
   * @param inlineDataId String
231
   * @throws McdbException
232
   * @return boolean
233
   */
234
  private boolean hasPermissionForInlineData(String user, String[] groups,
235
                                      String myPermission, String inlineDataId)
236
      throws McdbException
237
  {
238
     // this method can call the public method - hasPermission(...)
239
     // the only difference is about the ownership, you couldn't find the owner
240
     // from inlinedataId directly. You should get it from eml document itself
241
     String []userPackage = createUsersPackage(user, groups);
242
     try {
243
        if (containDocumentOwner(userPackage, docId))
244
         {
245
           return true;
246
         }
247
         else
248
         {
249
             PermissionController controller =
250
                                   new PermissionController(inlineDataId, false);
251
             return controller.hasPermission(user, groups, myPermission);
252
         }
253
    } catch (SQLException e) {
254
        throw new McdbException(e.getMessage());
255
    }
256
  }
257

    
258
  /**
259
   * The method to determine of a node can be access by a user just by subtree
260
   * access control
261
   */
262
  public boolean hasPermissionForSubTreeNode(String user, String[] groups,
263
                                             String myPermission, long nodeId)
264
                                             throws McdbException
265
  {
266
    boolean flag = true;
267
    // Get unaccessble subtree for this user
268
    Hashtable unaccessableSubTree = hasUnaccessableSubTree(user, groups,
269
                                                           myPermission);
270
    Enumeration en = unaccessableSubTree.elements();
271
    while (en.hasMoreElements())
272
    {
273
      SubTree tree = (SubTree)en.nextElement();
274
      long start = tree.getStartNodeId();
275
      long stop  = tree.getEndNodeId();
276
      // nodeid in unaccessablesubtree, return false
277
      if ( nodeId >= start && nodeId <= stop)
278
      {
279
        flag = false;
280
        break;
281
      }
282
    }
283
    return flag;
284
  }
285
  /**
286
   * This method will return a hasTable of subtree which user doesn't has the
287
   * permssion to access
288
   * @param user  the user name
289
   * @param groups  the groups which the use is in
290
   * @param myPermission  permission type to check for
291
   */
292
  public Hashtable hasUnaccessableSubTree(String user, String[] groups,
293
                                       String myPermission) throws McdbException
294
  {
295
    Hashtable resultUnaccessableSubTree = new Hashtable();
296
    String [] principals=null;
297
    int permission =AccessControlList.intValue(myPermission);
298

    
299
    //for the commnad line invocation return null(no unaccessable subtree)
300
    if ((user==null) && (groups==null || groups.length==0))
301
    {
302
      return resultUnaccessableSubTree;
303
    }
304

    
305
    //create a userpackage including user, public and group member
306
    principals=createUsersPackage(user, groups);
307
    //for the document owner return null(no unaccessable subtree)
308
    try
309
    {
310
      if (containDocumentOwner(principals, docId))
311
      {
312
       return resultUnaccessableSubTree;
313
      }
314
    }
315
    catch (SQLException ee)
316
    {
317
      throw new McdbException(ee);
318
    }
319

    
320
    // go through every subtree which has access control
321
    for (int i = 0; i< subTreeList.size(); i++)
322
    {
323
      SubTree tree = (SubTree)subTreeList.elementAt(i);
324
      long startId = tree.getStartNodeId();
325

    
326

    
327
        try
328
        {
329
          if (isAllowFirst(principals, docId, startId))
330
          {
331

    
332
            if (hasExplicitDenyRule(principals, docId, permission, startId ))
333
            {
334

    
335
             //if it is allowfirst and has deny rule
336
              // put the subtree into unaccessable vector
337
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
338
              {
339
                resultUnaccessableSubTree.put(new Long(startId), tree);
340
              }
341
            }//if
342
            else if ( hasAllowRule(principals, docId, permission, startId))
343
            {
344
              //if it is allowfirst and hasn't deny rule and has allow rule
345
              //allow access do nothing
346

    
347
            }//else if
348
            else
349
            {
350
              //other situation deny access
351
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
352
              {
353
                resultUnaccessableSubTree.put(new Long(startId), tree);
354
              }
355

    
356
            }//else
357
          }//if isAllowFirst
358
          else //denyFirst
359
          {
360
            if (hasAllowRule(principals, docId, permission,startId))
361
            {
362
              //if it is denyFirst and has allow rule, allow access, do nothing
363

    
364
            }
365
            else
366
            {
367
              //if it is denyfirst but no allow rule, deny access
368
              // add into vector
369
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
370
              {
371
                resultUnaccessableSubTree.put(new Long(startId), tree);
372
              }
373
            }
374
          }//else denyfirst
375
        }//try
376
        catch( Exception e)
377
        {
378
          logMetacat.error("PermissionController.hasUnaccessableSubTree - error in PermissionControl.has" +
379
                                   "UnaccessableSubTree "+e.getMessage());
380
          throw new McdbException(e);
381
        }
382

    
383
    }//for
384
    // merge the subtree if a subtree is another subtree'subtree
385
    resultUnaccessableSubTree = mergeEquivalentSubtree(resultUnaccessableSubTree);
386
    return resultUnaccessableSubTree;
387
  }//hasUnaccessableSubtree
388

    
389

    
390
  /*
391
   * A method to merge nested subtree into bigger one. For example subtree b
392
   * is a subtree of subtree a. And user doesn't have read permission for both
393
   * so we only use subtree a is enough.
394
   */
395
  private Hashtable mergeEquivalentSubtree(Hashtable unAccessSubTree)
396
  {
397
    Hashtable newSubTreeHash = new Hashtable();
398
    boolean   needDelete = false;
399
    // check the parameters
400
    if (unAccessSubTree == null || unAccessSubTree.isEmpty())
401
    {
402
      return newSubTreeHash;
403
    }
404
    else
405
    {
406
      // look every subtree start point and stop point, to see if it is embedded
407
      // in another one. If embedded, they are equavelent and we can use bigger
408
      // one to replace smaller one
409
      Enumeration en = unAccessSubTree.elements();
410
      while (en.hasMoreElements())
411
      {
412
        SubTree tree    = (SubTree)en.nextElement();
413
        String  treeId  = tree.getSubTreeId();
414
        long    startId = tree.getStartNodeId();
415
        long    endId   = tree.getEndNodeId();
416

    
417
        Enumeration enu = unAccessSubTree.elements();
418
        while (enu.hasMoreElements())
419
        {
420
          SubTree subTree = (SubTree)enu.nextElement();
421
          String subTreeId= subTree.getSubTreeId();
422
          long   subTreeStartId = subTree.getStartNodeId();
423
          long   subTreeEndId   = subTree.getEndNodeId();
424
          //compare and if the first subtree is a subtree of the second
425
          // one, set neeDelete true
426
          if (startId > subTreeStartId && endId < subTreeEndId)
427
          {
428
            needDelete = true;
429
            logMetacat.info("PermissionController.mergeEquivalentSubtree - the subtree: "+ treeId +
430
                                     " need to be get rid of from unaccessable"+
431
                                     " subtree list becuase it is a subtree of"+
432
                                     " another subtree in the list");
433
            break;
434
          }//if
435
        }//while
436
        // if not need to delete, put the subtree into hash
437
        if (!needDelete)
438
        {
439
          newSubTreeHash.put(new Long(startId), tree);
440
        }
441
        //reset needDelete
442
        needDelete = false;
443
      }//while
444
      return newSubTreeHash;
445
    }//else
446
  }
447

    
448
  /**
449
	 * Check if a document id is a access document. Access document need user
450
	 * has "all" permission to access it.
451
	 * 
452
	 * @param docId,
453
	 *            the document id need to be checked
454
	 */
455
	private boolean isAccessDocument(String docId) throws SQLException {
456
		// detele the rev number if docid contains it
457
		docId = DocumentUtil.getDocIdFromString(docId);
458
		PreparedStatement pStmt = null;
459
		DBConnection conn = null;
460
		int serialNumber = -1;
461
		try {
462
			// check out DBConnection
463
			conn = DBConnectionPool.getDBConnection("PermissionControl.isAccessDoc");
464
			serialNumber = conn.getCheckOutSerialNumber();
465
			pStmt = conn.prepareStatement("select doctype from xml_documents where "
466
					+ "docid like '" + docId + "'");
467
			pStmt.execute();
468
			ResultSet rs = pStmt.getResultSet();
469
			boolean hasRow = rs.next();
470
			String doctype = null;
471
			if (hasRow) {
472
				doctype = rs.getString(1);
473

    
474
			}
475
			pStmt.close();
476

    
477
			// if it is an access document
478
			if (doctype != null
479
					&& ((MetacatUtil.getOptionList(PropertyService
480
							.getProperty("xml.accessdoctype")).contains(doctype)))) {
481

    
482
				return true;
483
			}
484

    
485
		} catch (SQLException e) {
486
			throw new SQLException("PermissionControl.isAccessDocument "
487
					+ "Error checking" + " on document " + docId + ". " + e.getMessage());
488
		} catch (PropertyNotFoundException pnfe) {
489
			throw new SQLException("PermissionControl.isAccessDocument "
490
					+ "Error checking" + " on document " + docId + ". " + pnfe.getMessage());
491
		} finally {
492
			try {
493
				pStmt.close();
494
			} finally {
495
				DBConnectionPool.returnDBConnection(conn, serialNumber);
496
			}
497
		}
498

    
499
		return false;
500
	}// isAccessDocument
501

    
502

    
503

    
504
  /**
505
	 * Check if a stirng array contains a given documents' owner
506
	 * 
507
	 * @param principals,
508
	 *            a string array storing the username, groups name and public.
509
	 * @param docid,
510
	 *            the id of given documents
511
	 */
512
  private boolean containDocumentOwner( String[] principals, String docId)
513
                    throws SQLException
514
  {
515
    int lengthOfArray=principals.length;
516
    boolean hasRow;
517
    PreparedStatement pStmt=null;
518
    DBConnection conn = null;
519
    int serialNumber = -1;
520

    
521
    try
522
    {
523
      //check out DBConnection
524
     conn=DBConnectionPool.getDBConnection("PermissionControl.containDocOnwer");
525
      serialNumber=conn.getCheckOutSerialNumber();
526
      pStmt = conn.prepareStatement(
527
                "SELECT 'x' FROM xml_documents " +
528
                "WHERE docid = ? AND lower(user_owner) = ?");
529
      //check every element in the string array too see if it conatains
530
      //the owner of document
531
      for (int i=0; i<lengthOfArray; i++)
532
      {
533

    
534
        // Bind the values to the query
535
        pStmt.setString(1, docId);
536
        pStmt.setString(2, principals[i]);
537
        logMetacat.info("PermissionController.containDocumentOwner - the principle stack is : " +
538
                                  principals[i]);
539

    
540
        pStmt.execute();
541
        ResultSet rs = pStmt.getResultSet();
542
        hasRow = rs.next();
543
        if (hasRow)
544
        {
545
          pStmt.close();
546
           logMetacat.info("PermissionController.containDocumentOwner - find the owner");
547
          return true;
548
        }//if
549

    
550
      }//for
551
    }//try
552
    catch (SQLException e)
553
    {
554
        pStmt.close();
555

    
556
        throw new
557
        SQLException("PermissionControl.hasPermission - " +
558
                     "Error checking ownership for " + principals[0] +
559
                     " on document #" + docId + ". " + e.getMessage());
560
    }//catch
561
    finally
562
    {
563
      try
564
      {
565
        pStmt.close();
566
      }
567
      finally
568
      {
569
        DBConnectionPool.returnDBConnection(conn, serialNumber);
570
      }
571
    }
572
    return false;
573
  }//containDocumentOwner
574

    
575
  /**
576
    * Check if the permission order for user at that documents is allowFirst
577
    * @param principals, list of names of principals to check for
578
    * @param docid, document identifier to check for
579
    */
580
  private boolean isAllowFirst(String [] principals, String docId,
581
                               long startId)
582
                  throws SQLException, Exception
583
  {
584
    int lengthOfArray=principals.length;
585
    boolean hasRow;
586
    PreparedStatement pStmt = null;
587
    DBConnection conn = null;
588
    int serialNumber = -1;
589
    String sql = null;
590
    boolean topLever =false;
591
    if (startId == TOPLEVELSTARTNODEID)
592
    {
593
      //top level
594
      topLever = true;
595
      sql = "SELECT perm_order FROM xml_access " +
596
    "WHERE lower(principal_name) = ? AND docid = ? AND startnodeid is NULL";
597
    }
598
    else
599
    {
600
      //sub tree level
601
      sql = "SELECT perm_order FROM xml_access " +
602
        "WHERE lower(principal_name)= ? AND docid = ? AND startnodeid = ?";
603
    }
604

    
605
    try
606
    {
607
      //check out DBConnection
608
      conn=DBConnectionPool.getDBConnection("AccessControlList.isAllowFirst");
609
      serialNumber=conn.getCheckOutSerialNumber();
610

    
611
      //select permission order from database
612
      pStmt = conn.prepareStatement(sql);
613

    
614
      //check every name in the array
615
      for (int i=0; i<lengthOfArray;i++)
616
      {
617
        //bind value
618
        pStmt.setString(1, principals[i]);//user name
619
        pStmt.setString(2, docId);//docid
620

    
621
        // if subtree, we need set subtree id
622
        if (!topLever)
623
        {
624
          pStmt.setLong(3, startId);
625
        }
626

    
627
        pStmt.execute();
628
        ResultSet rs = pStmt.getResultSet();
629
        hasRow=rs.next();
630
        if (hasRow)
631
        {
632
          //get the permission order from data base
633
          String permissionOrder=rs.getString(1);
634
          //if the permission order is "allowFirst
635
          if (permissionOrder.equalsIgnoreCase(AccessControlInterface.ALLOWFIRST))
636
          {
637
            pStmt.close();
638
            return true;
639
          }
640
          else
641
          {
642
            pStmt.close();
643
            return false;
644
          }
645
        }//if
646
      }//for
647
    }//try
648
    catch (SQLException e)
649
    {
650
      throw e;
651
    }
652
    finally
653
    {
654
      try
655
      {
656
        pStmt.close();
657
      }
658
      finally
659
      {
660
        DBConnectionPool.returnDBConnection(conn, serialNumber);
661
      }
662
    }
663

    
664
    //if reach here, means there is no permssion record for given names and
665
    //docid. So throw a exception.
666

    
667
    throw new Exception("PermissionController.isAllowFirst - There is no permission record for user "+ principals[0] + 
668
                        " at document " + docId);
669

    
670
  }//isAllowFirst
671

    
672
  /**
673
    * Check if the users array has allow rules for given users, docid and
674
    * permission.
675
    * If it has permission rule and ticket count is greater than 0, the ticket
676
    * number will decrease one for every allow rule
677
    * @param principals, list of names of principals to check for
678
    * @param docid, document identifier to check for
679
    * @param permission, the permssion need to check
680
    */
681
  private boolean hasAllowRule(String [] principals, String docId,
682
                                  int permission, long startId)
683
                  throws SQLException, Exception
684
 {
685
   int lengthOfArray=principals.length;
686
   boolean allow=false;//initial value is no allow rule
687
   ResultSet rs;
688
   PreparedStatement pStmt = null;
689
   int permissionValue=permission;
690
   int permissionValueInTable;
691
   int ticketCount;
692
   DBConnection conn = null;
693
   int serialNumber = -1;
694
   boolean topLever = false;
695
   String sql = null;
696
   if (startId == TOPLEVELSTARTNODEID)
697
   {
698
     // for toplevel
699
     topLever = true;
700
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
701
   "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid is NULL";
702
   }
703
   else
704
   {
705
     topLever =false;
706
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
707
      "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid = ?";
708
   }
709
   try
710
   {
711
     //check out DBConnection
712
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasAllowRule");
713
     serialNumber=conn.getCheckOutSerialNumber();
714
    //This sql statement will select entry with
715
    //begin_time<=currentTime<=end_time in xml_access table
716
    //If begin_time or end_time is null in table, isnull(begin_time, sysdate)
717
    //function will assign begin_time=sysdate
718
    pStmt = conn.prepareStatement(sql);
719
    //bind docid, perm_type
720
    pStmt.setString(1, docId);
721
    pStmt.setString(3, AccessControlInterface.ALLOW);
722

    
723
    // if subtree lever, need to set subTreeId
724
    if (!topLever)
725
    {
726
      pStmt.setLong(4, startId);
727
    }
728

    
729
    //bind every elenment in user name array
730
    for (int i=0;i<lengthOfArray; i++)
731
    {
732
      pStmt.setString(2, principals[i]);
733
      pStmt.execute();
734
      rs=pStmt.getResultSet();
735
      while (rs.next())//check every entry for one user
736
      {
737
        permissionValueInTable=rs.getInt(1);
738

    
739
        //permission is ok
740
        //the user have a permission to access the file
741
        if (( permissionValueInTable & permissionValue )== permissionValue )
742
        {
743

    
744
           allow=true;//has allow rule entry
745
        }//if
746
      }//while
747
    }//for
748
   }//try
749
   catch (SQLException sqlE)
750
   {
751
     throw sqlE;
752
   }
753
   catch (Exception e)
754
   {
755
     throw e;
756
   }
757
   finally
758
   {
759
     try
760
     {
761
       pStmt.close();
762
     }
763
     finally
764
     {
765
       DBConnectionPool.returnDBConnection(conn, serialNumber);
766
     }
767
   }
768
    return allow;
769
 }//hasAllowRule
770

    
771

    
772

    
773
   /**
774
    * Check if the users array has explicit deny rules for given users, docid
775
    * and permission. That means the perm_type is deny and current time is
776
    * less than end_time and greater than begin time, or no time limit.
777
    * @param principals, list of names of principals to check for
778
    * @param docid, document identifier to check for
779
    * @param permission, the permssion need to check
780
    */
781
  private boolean hasExplicitDenyRule(String [] principals, String docId,
782
                                      int permission, long startId)
783
                  throws SQLException
784
 {
785
   int lengthOfArray=principals.length;
786
   ResultSet rs;
787
   PreparedStatement pStmt = null;
788
   int permissionValue=permission;
789
   int permissionValueInTable;
790
   DBConnection conn = null;
791
   int serialNumber = -1;
792
   String sql = null;
793
   boolean topLevel = false;
794

    
795
   // decide top level or subtree level
796
   if (startId == TOPLEVELSTARTNODEID)
797
   {
798
     topLevel = true;
799
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
800
    "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid is NULL";
801
   }
802
   else
803
   {
804
     topLevel = false;
805
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
806
     "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid = ?";
807
   }
808

    
809
   try
810
   {
811
     //check out DBConnection
812
     conn=DBConnectionPool.getDBConnection("PermissionControl.hasExplicitDeny");
813
     serialNumber=conn.getCheckOutSerialNumber();
814

    
815
     pStmt = conn.prepareStatement(sql);
816
    //bind docid, perm_type
817
    pStmt.setString(1, docId);
818
    pStmt.setString(3, AccessControlInterface.DENY);
819

    
820
    // subtree level need to set up subtreeid
821
    if (!topLevel)
822
    {
823
      pStmt.setLong(4, startId);
824
    }
825

    
826
    //bind every elenment in user name array
827
    for (int i=0;i<lengthOfArray; i++)
828
    {
829
      pStmt.setString(2, principals[i]);
830
      pStmt.execute();
831
      rs=pStmt.getResultSet();
832
      while (rs.next())//check every entry for one user
833
      {
834
        permissionValueInTable=rs.getInt(1);
835

    
836
        //permission is ok the user doesn't have permission to access the file
837
        if (( permissionValueInTable & permissionValue )== permissionValue )
838

    
839
        {
840
           pStmt.close();
841
           return true;
842
         }//if
843
      }//while
844
    }//for
845
   }//try
846
   catch (SQLException e)
847
   {
848
     throw e;
849
   }//catch
850
   finally
851
   {
852
     try
853
     {
854
       pStmt.close();
855
     }
856
     finally
857
     {
858
       DBConnectionPool.returnDBConnection(conn, serialNumber);
859
     }
860
   }//finally
861
   return false;//no deny rule
862
  }//hasExplicitDenyRule
863

    
864

    
865
  /**
866
    * Creat a users pakages to check permssion rule, user itself, public and
867
    * the gourps the user belong will be include in this package
868
    * @param user, the name of user
869
    * @param groups, the string array of the groups that user belong to
870
    */
871
  private String[] createUsersPackage(String user, String [] groups)
872
  {
873
    String [] usersPackage=null;
874
    int lengthOfPackage;
875

    
876
    if (groups!=null)
877
    {
878
      //if gouprs is not null and user is not public, we should create a array
879
      //to store the groups and user and public.
880
      //So the length of userPackage is the length of group plus two
881
      if (!user.equalsIgnoreCase(AccessControlInterface.PUBLIC))
882
      {
883
        lengthOfPackage=(groups.length)+2;
884
        usersPackage=new String [lengthOfPackage];
885
        //the first two elements is user self and public
886
        //in order to ignore case sensitive, we transfer user to lower case
887
        if (user != null)
888
        {
889
          usersPackage[0]= user.toLowerCase();
890
          logMetacat.info("PermissionController.createUsersPackage - after transfer to lower case(not null): "+
891
                                     usersPackage[0]);
892
        }
893
        else
894
        {
895
          usersPackage[0] = user;
896
          usersPackage[0]= user.toLowerCase();
897
          logMetacat.info("PermissionController.createUsersPackage - after transfer to lower case(null): "+
898
                                     usersPackage[0]);
899
        }
900
        usersPackage[1]=AccessControlInterface.PUBLIC;
901
        //put groups element from index 0 to lengthOfPackage-3 into userPackage
902
        //from index 2 to lengthOfPackage-1
903
        for (int i=2; i<lengthOfPackage; i++)
904
        {
905
          //tansfer group to lower case too
906
          if (groups[i-2] != null)
907
          {
908
            usersPackage[i]=groups[i-2].toLowerCase();
909
          }
910
        } //for
911
      }//if user!=public
912
      else//use=public
913
      {
914
        lengthOfPackage=(groups.length)+1;
915
        usersPackage=new String [lengthOfPackage];
916
        //the first lements is public
917
        usersPackage[0]=AccessControlInterface.PUBLIC;
918
        //put groups element from index 0 to lengthOfPackage-2 into userPackage
919
        //from index 1 to lengthOfPackage-1
920
        for (int i=1; i<lengthOfPackage; i++)
921
        {
922
          if (groups[i-1] != null)
923
          {
924
            usersPackage[i]=groups[i-1].toLowerCase();
925
          }
926
        } //for
927
      }//else user=public
928

    
929
    }//if groups!=null
930
    else
931
    {
932
      //because no groups, the userPackage only need two elements
933
      //one is for user, the other is for public
934
      if (!user.equalsIgnoreCase(AccessControlInterface.PUBLIC))
935
      {
936
        lengthOfPackage=2;
937
        usersPackage=new String [lengthOfPackage];
938
        if (user != null)
939
        {
940
          usersPackage[0]=user.toLowerCase();
941
        }
942
        else
943
        {
944
          usersPackage[0]=user;
945
        }
946
        usersPackage[1]=AccessControlInterface.PUBLIC;
947
      }//if user!=public
948
      else //user==public
949
      {
950
        //only put public into array
951
        lengthOfPackage=1;
952
        usersPackage=new String [lengthOfPackage];
953
        usersPackage[0]=AccessControlInterface.PUBLIC;
954
      }
955
    }//else groups==null
956
    return usersPackage;
957
  }//createUsersPackage
958

    
959

    
960
  /**
961
   * A static method to get Hashtable which cointains a inlinedata object list that
962
   * user can't read it. The key is subtree id of inlinedata, the data is
963
   * 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<String, String> getUnReadableInlineDataIdList(String docidWithoutRev,
971
                                                   String user, String[] groups,
972
                                                   boolean withRevision)
973
                                                throws McdbException
974
   {
975
     Hashtable<String, String> inlineDataList = getUnAccessableInlineDataIdList(docidWithoutRev,
976
                              user, groups, AccessControlInterface.READSTRING,
977
                              withRevision);
978

    
979
     return inlineDataList;
980
   }
981

    
982
   /**
983
  * A static method to get Hashtable which cointains a inline  data object list that
984
  * user can't overwrite it. The key is subtree id of inline data distrubition,
985
  * the value is internal file name for the inline data which is stored as docid
986
  * in xml_access table or data object doc id.
987
  * @param docidWithoutRev, metadata docid which should be the accessfileid
988
  *                         in the table
989
  * @param user , the name of user
990
  * @param groups, the group which the user belong to
991
  */
992
  public static Hashtable<String, String> getUnWritableInlineDataIdList(String docidWithoutRev,
993
                                                  String user, String[] groups,
994
                                                  boolean withRevision)
995
                                               throws Exception
996
  {
997
    Hashtable<String, String> inlineDataList = getUnAccessableInlineDataIdList(docidWithoutRev,
998
                            user, groups, AccessControlInterface.WRITESTRING,
999
                            withRevision);
1000

    
1001
    return inlineDataList;
1002
  }
1003

    
1004

    
1005
   /*
1006
    * This method will get hashtable which contains a unaccessable distribution
1007
    * inlinedata object list
1008
    *
1009
    * withRevision is used to get inline id list with or without revision number
1010
    * e.g. when withRevision is true, temp.1.1.1, temp.1.1.2 would be returned
1011
    * otherwise temp.1.1 and temp.1.2 would be returned.
1012
    */
1013
   private static Hashtable<String, String> getUnAccessableInlineDataIdList(String docid,
1014
                               String user, String[] groups, String permission,
1015
                               boolean withRevision)
1016
                             throws McdbException
1017
   {
1018
       Hashtable<String, String> unAccessibleIdList = new Hashtable();
1019
       if (user == null) {
1020
           return unAccessibleIdList;
1021
       }
1022

    
1023
       Hashtable allIdList;
1024
       try {
1025
           allIdList = getAllInlineDataIdList(docid);
1026
       } catch (SQLException e) {
1027
           throw new McdbException(e.getMessage());
1028
       }
1029
       Enumeration<String> en = allIdList.keys();
1030
      while (en.hasMoreElements())
1031
      {
1032
        String subTreeId = (String) en.nextElement();
1033
        String fileId = (String) allIdList.get(subTreeId);
1034
        //Here fileid is internal file id for line data. It stored in docid
1035
        // field in xml_access table. so we don't need to delete rev
1036
        PermissionController controller = new PermissionController(docid, false);
1037
        if (!controller.hasPermissionForInlineData(user, groups, permission, fileId))
1038
        {
1039
            if(withRevision)
1040
            {
1041
                logMetacat.info("PermissionController.getUnAccessableInlineDataIdList - Put subtree id " + subTreeId +
1042
                                         " and " + "inline data file name " +
1043
                                         fileId + " into " + "un" + permission +
1044
                                         " hash");
1045
                unAccessibleIdList.put(subTreeId, fileId);
1046

    
1047
            }
1048
            else
1049
            {
1050
                logMetacat.info("PermissionController.getUnAccessableInlineDataIdList - Put subtree id " + subTreeId +
1051
                                         " and " + "inline data file name " +
1052
                                         DocumentUtil.getInlineDataIdWithoutRev(fileId) +
1053
                                         " into " + "un" + permission +
1054
                                         " hash");
1055
                unAccessibleIdList.put(subTreeId, 
1056
                		DocumentUtil.getInlineDataIdWithoutRev(fileId));
1057
            }
1058
        }
1059
      }
1060
      return unAccessibleIdList;
1061
   }
1062

    
1063

    
1064
   /*
1065
    * This method will get a hash table from xml_access table for all records
1066
    * about the inline data. The key is subtree id and data is a inline internal
1067
    * file name
1068
    */
1069
   private static Hashtable getAllInlineDataIdList(String docid) throws SQLException
1070
   {
1071
     Hashtable inlineDataList = new Hashtable();
1072
     String sql = "SELECT subtreeid, docid FROM xml_access WHERE " +
1073
                   "accessfileid = ? AND subtreeid  IS NOT NULL";
1074
     PreparedStatement pStmt=null;
1075
     ResultSet rs=null;
1076
     DBConnection conn=null;
1077
     int serialNumber=-1;
1078
     try
1079
     {
1080
       //check out DBConnection
1081
       conn=DBConnectionPool.getDBConnection("PermissionControl.getDataSetId");
1082
       serialNumber=conn.getCheckOutSerialNumber();
1083
       pStmt=conn.prepareStatement(sql);
1084
       //bind the value to query
1085
       pStmt.setString(1, docid);
1086
       //execute the query
1087
       pStmt.execute();
1088
       rs=pStmt.getResultSet();
1089
       //process the result
1090
       while(rs.next())
1091
       {
1092
         String subTreeId = rs.getString(1);
1093
         String inlineDataId = rs.getString(2);
1094
         if (subTreeId != null && !subTreeId.trim().equals("") &&
1095
            inlineDataId != null && !inlineDataId.trim().equals(""))
1096
         {
1097
           inlineDataList.put(subTreeId, inlineDataId);
1098
         }
1099
      }//while
1100
     }//try
1101
     finally
1102
     {
1103
       try
1104
       {
1105
         pStmt.close();
1106
       }
1107
       finally
1108
       {
1109
         DBConnectionPool.returnDBConnection(conn, serialNumber);
1110
       }
1111
     }//finally
1112
     return inlineDataList;
1113
   }//getAllInlineDataIdList
1114
}
(52-52/65)