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 4861 daigle
import java.util.Stack;
34 1425 tao
import java.util.Vector;
35 4861 daigle
import java.util.Iterator;
36 1425 tao
37 2663 sgarg
import org.apache.log4j.Logger;
38
39 5090 daigle
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlForSingleFile;
40
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlInterface;
41
import edu.ucsb.nceas.metacat.accesscontrol.AccessControlList;
42 5015 daigle
import edu.ucsb.nceas.metacat.database.DBConnection;
43
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
44 5030 daigle
import edu.ucsb.nceas.metacat.properties.PropertyService;
45 5072 daigle
import edu.ucsb.nceas.metacat.service.SessionService;
46 5025 daigle
import edu.ucsb.nceas.metacat.util.DocumentUtil;
47 4698 daigle
import edu.ucsb.nceas.metacat.util.MetacatUtil;
48 5072 daigle
import edu.ucsb.nceas.metacat.util.SessionData;
49 4080 daigle
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
50 5374 berkley
import edu.ucsb.nceas.metacat.shared.ServiceException;
51 4080 daigle
52 1425 tao
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 4861 daigle
   private Vector subTreeList = new Vector();
58 2245 sgarg
59 5098 daigle
   private static final long TOPLEVELSTARTNODEID = 0; //if start node is 0, means it is top
60 1527 tao
                                         //level document
61 2245 sgarg
62 2663 sgarg
   private static Logger logMetacat = Logger.getLogger(PermissionController.class);
63 2245 sgarg
64 1425 tao
   /**
65
    * Constructor for PermissionController
66
    * @param myDocid      the docid need to access
67
    */
68 1434 tao
   public PermissionController(String myDocid) throws McdbException
69 1425 tao
   {
70
     // Get rid of rev number
71 5025 daigle
     docId = DocumentUtil.getSmartDocId(myDocid);
72 2245 sgarg
     //hasSubTreeAccessControl = checkSubTreeAccessControl();
73 1425 tao
   }
74 2245 sgarg
75 1485 tao
   /**
76 2245 sgarg
    * 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 5025 daigle
         docId = DocumentUtil.getDocIdFromAccessionNumber(myDocid);
89 2245 sgarg
     }
90
   }
91
92
   /**
93 1485 tao
    * Return if a document has subtree access control
94
    */
95
   public boolean hasSubTreeAccessControl()
96
   {
97
     return hasSubTreeAccessControl;
98
   }
99 2245 sgarg
100 5072 daigle
   public boolean hasPermission(String sessionId, String myPermission) throws SQLException {
101 5374 berkley
       SessionData sessionData = null;
102
       sessionData = SessionService.getInstance().getRegisteredSession(sessionId);
103
       if (sessionData == null) {
104
           return false;
105
       }
106 5072 daigle
107
	   return hasPermission(sessionData.getUserName(), sessionData.getGroupNames(), myPermission);
108
   }
109
110 2245 sgarg
111 1425 tao
  /**
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 2245 sgarg
  public boolean hasPermission(String user, String[]groups, String myPermission)
118 4950 daigle
                              throws SQLException //, Exception
119 1425 tao
  {
120
    boolean hasPermission=false;
121
    String [] userPackage=null;
122
    int permission =AccessControlList.intValue(myPermission);
123 2245 sgarg
124 1425 tao
    //for the commnad line invocation
125
    if ((user==null) && (groups==null || groups.length==0))
126
    {
127
      return true;
128
    }
129 2245 sgarg
130 1425 tao
    //create a userpackage including user, public and group member
131
    userPackage=createUsersPackage(user, groups);
132 2245 sgarg
133 1425 tao
    //if the requested document is access documents and requested permission
134
    //is "write", the user should have "all" right
135 2245 sgarg
136 1425 tao
    if (isAccessDocument(docId) && (permission == AccessControlInterface.WRITE))
137
    {
138 2245 sgarg
139 1425 tao
      hasPermission = hasPermission(userPackage,docId, 7);// 7 is all permission
140
    }//if
141
    else //in other situation, just check the request permission
142
    {
143 2245 sgarg
144
145 1425 tao
      // Check for @permission on @docid for @user and/or @groups
146
      hasPermission = hasPermission(userPackage,docId, permission);
147 2245 sgarg
148 1425 tao
    }//else
149 2245 sgarg
150 1425 tao
    return hasPermission;
151
  }
152 2245 sgarg
153
154 1425 tao
  /**
155
    * Check from db connection if the users in String array @principals has
156 2245 sgarg
    * @permission on @docid*
157 1425 tao
    * @param principals, names in userPakcage need to check for @permission
158
    * @param docid, document identifier to check on
159 2245 sgarg
    * @param permission, permission (write or all...) to check for
160 1425 tao
    */
161
  private boolean hasPermission(String [] principals, String docId,
162
                                           int permission)
163
                         throws SQLException
164
  {
165 1527 tao
    long startId = TOPLEVELSTARTNODEID;// this is for top level, so startid is 0
166 2245 sgarg
    try
167 1425 tao
    {
168
      //first, if there is a docid owner in user package, return true
169 2245 sgarg
      //because doc owner has all permssion
170 1425 tao
      if (containDocumentOwner(principals, docId))
171
      {
172 2245 sgarg
173 1425 tao
          return true;
174
      }
175 2245 sgarg
176 1425 tao
      //If there is no owner in user package, checking the table
177
      //check perm_order
178 1527 tao
      if (isAllowFirst(principals, docId, startId))
179 1425 tao
      {
180 2245 sgarg
181 1527 tao
        if (hasExplicitDenyRule(principals, docId, permission, startId))
182 1425 tao
        {
183
          //if it is allowfirst and has deny rule(either explicit )
184
          //deny access
185 2245 sgarg
186 1425 tao
          return false;
187
        }//if
188 1527 tao
        else if ( hasAllowRule(principals, docId, permission, startId))
189 1425 tao
        {
190
          //if it is allowfirst and hasn't deny rule and has allow rule
191
          //allow access
192 2245 sgarg
193 1425 tao
          return true;
194
        }//else if
195
        else
196
        {
197
          //other situation deny access
198 2245 sgarg
199 1425 tao
          return false;
200
        }//else
201
     }//if isAllowFirst
202
     else //denyFirst
203
     {
204 1527 tao
       if (hasAllowRule(principals, docId, permission, startId))
205 1425 tao
       {
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 5311 daigle
      logMetacat.warn("PermissionController.hasPermission - There is a exception in hasPermission method: "
219 2663 sgarg
                         +e.getMessage());
220 1425 tao
    }
221 2245 sgarg
222 1425 tao
    return false;
223
  }//hasPermission
224 2245 sgarg
225 1425 tao
  /**
226 2245 sgarg
   *  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 5298 jones
      throws McdbException
237 2245 sgarg
  {
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 5298 jones
     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 2245 sgarg
  }
257
258
  /**
259 1485 tao
   * 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 1492 tao
    boolean flag = true;
267 1485 tao
    // Get unaccessble subtree for this user
268 4861 daigle
    Hashtable unaccessableSubTree = hasUnaccessableSubTree(user, groups,
269 1485 tao
                                                           myPermission);
270 4861 daigle
    Enumeration en = unaccessableSubTree.elements();
271 1485 tao
    while (en.hasMoreElements())
272
    {
273
      SubTree tree = (SubTree)en.nextElement();
274
      long start = tree.getStartNodeId();
275
      long stop  = tree.getEndNodeId();
276 1492 tao
      // nodeid in unaccessablesubtree, return false
277 1485 tao
      if ( nodeId >= start && nodeId <= stop)
278
      {
279 1492 tao
        flag = false;
280 1485 tao
        break;
281
      }
282
    }
283
    return flag;
284
  }
285
  /**
286 2245 sgarg
   * This method will return a hasTable of subtree which user doesn't has the
287 1434 tao
   * 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 4861 daigle
  public Hashtable hasUnaccessableSubTree(String user, String[] groups,
293 1434 tao
                                       String myPermission) throws McdbException
294
  {
295 4861 daigle
    Hashtable resultUnaccessableSubTree = new Hashtable();
296 1434 tao
    String [] principals=null;
297
    int permission =AccessControlList.intValue(myPermission);
298 2245 sgarg
299 1434 tao
    //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 2245 sgarg
305 1434 tao
    //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 2245 sgarg
320 1434 tao
    // 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 1527 tao
      long startId = tree.getStartNodeId();
325 2245 sgarg
326
327 1434 tao
        try
328
        {
329 1527 tao
          if (isAllowFirst(principals, docId, startId))
330 1434 tao
          {
331 2245 sgarg
332 1527 tao
            if (hasExplicitDenyRule(principals, docId, permission, startId ))
333 1434 tao
            {
334 2245 sgarg
335 1434 tao
             //if it is allowfirst and has deny rule
336
              // put the subtree into unaccessable vector
337 1527 tao
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
338 1434 tao
              {
339 1527 tao
                resultUnaccessableSubTree.put(new Long(startId), tree);
340 1434 tao
              }
341
            }//if
342 1527 tao
            else if ( hasAllowRule(principals, docId, permission, startId))
343 1434 tao
            {
344
              //if it is allowfirst and hasn't deny rule and has allow rule
345
              //allow access do nothing
346 2245 sgarg
347 1434 tao
            }//else if
348
            else
349
            {
350
              //other situation deny access
351 1527 tao
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
352 1434 tao
              {
353 1527 tao
                resultUnaccessableSubTree.put(new Long(startId), tree);
354 1434 tao
              }
355 2245 sgarg
356 1434 tao
            }//else
357
          }//if isAllowFirst
358
          else //denyFirst
359
          {
360 1527 tao
            if (hasAllowRule(principals, docId, permission,startId))
361 1434 tao
            {
362
              //if it is denyFirst and has allow rule, allow access, do nothing
363 2245 sgarg
364 1434 tao
            }
365
            else
366
            {
367
              //if it is denyfirst but no allow rule, deny access
368
              // add into vector
369 1527 tao
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
370 1434 tao
              {
371 1527 tao
                resultUnaccessableSubTree.put(new Long(startId), tree);
372 1434 tao
              }
373
            }
374
          }//else denyfirst
375
        }//try
376
        catch( Exception e)
377
        {
378 5311 daigle
          logMetacat.error("PermissionController.hasUnaccessableSubTree - error in PermissionControl.has" +
379 2663 sgarg
                                   "UnaccessableSubTree "+e.getMessage());
380 1434 tao
          throw new McdbException(e);
381
        }
382 2245 sgarg
383 1434 tao
    }//for
384 2245 sgarg
    // merge the subtree if a subtree is another subtree'subtree
385 1521 tao
    resultUnaccessableSubTree = mergeEquivalentSubtree(resultUnaccessableSubTree);
386 1434 tao
    return resultUnaccessableSubTree;
387
  }//hasUnaccessableSubtree
388 2245 sgarg
389
390
  /*
391 1513 tao
   * 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 4861 daigle
  private Hashtable mergeEquivalentSubtree(Hashtable unAccessSubTree)
396 1513 tao
  {
397 4861 daigle
    Hashtable newSubTreeHash = new Hashtable();
398 1513 tao
    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 4861 daigle
      Enumeration en = unAccessSubTree.elements();
410 1513 tao
      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 2245 sgarg
417 4861 daigle
        Enumeration enu = unAccessSubTree.elements();
418 1513 tao
        while (enu.hasMoreElements())
419
        {
420
          SubTree subTree = (SubTree)enu.nextElement();
421 4861 daigle
          String subTreeId= subTree.getSubTreeId();
422 1513 tao
          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 5311 daigle
            logMetacat.info("PermissionController.mergeEquivalentSubtree - the subtree: "+ treeId +
430 1513 tao
                                     " need to be get rid of from unaccessable"+
431
                                     " subtree list becuase it is a subtree of"+
432 2663 sgarg
                                     " another subtree in the list");
433 1513 tao
            break;
434
          }//if
435
        }//while
436
        // if not need to delete, put the subtree into hash
437
        if (!needDelete)
438
        {
439 1527 tao
          newSubTreeHash.put(new Long(startId), tree);
440 1513 tao
        }
441
        //reset needDelete
442
        needDelete = false;
443
      }//while
444
      return newSubTreeHash;
445
    }//else
446
  }
447 2245 sgarg
448 1434 tao
  /**
449 4080 daigle
	 * 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 5025 daigle
		docId = DocumentUtil.getDocIdFromString(docId);
458 4080 daigle
		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 2245 sgarg
474 4080 daigle
			}
475
			pStmt.close();
476 2245 sgarg
477 4080 daigle
			// if it is an access document
478
			if (doctype != null
479 4698 daigle
					&& ((MetacatUtil.getOptionList(PropertyService
480 4213 daigle
							.getProperty("xml.accessdoctype")).contains(doctype)))) {
481 2245 sgarg
482 4080 daigle
				return true;
483
			}
484 2245 sgarg
485 4080 daigle
		} 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 2245 sgarg
499 4080 daigle
		return false;
500
	}// isAccessDocument
501 2245 sgarg
502
503
504 1425 tao
  /**
505 4080 daigle
	 * 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 1434 tao
  private boolean containDocumentOwner( String[] principals, String docId)
513 1425 tao
                    throws SQLException
514
  {
515
    int lengthOfArray=principals.length;
516 2245 sgarg
    boolean hasRow;
517 1425 tao
    PreparedStatement pStmt=null;
518
    DBConnection conn = null;
519
    int serialNumber = -1;
520 2245 sgarg
521 1425 tao
    try
522
    {
523
      //check out DBConnection
524 1434 tao
     conn=DBConnectionPool.getDBConnection("PermissionControl.containDocOnwer");
525 1425 tao
      serialNumber=conn.getCheckOutSerialNumber();
526
      pStmt = conn.prepareStatement(
527
                "SELECT 'x' FROM xml_documents " +
528 2245 sgarg
                "WHERE docid = ? AND lower(user_owner) = ?");
529 1425 tao
      //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 2245 sgarg
534 1425 tao
        // Bind the values to the query
535
        pStmt.setString(1, docId);
536
        pStmt.setString(2, principals[i]);
537 5311 daigle
        logMetacat.info("PermissionController.containDocumentOwner - the principle stack is : " +
538 2663 sgarg
                                  principals[i]);
539 1425 tao
540
        pStmt.execute();
541
        ResultSet rs = pStmt.getResultSet();
542
        hasRow = rs.next();
543 2245 sgarg
        if (hasRow)
544 1425 tao
        {
545
          pStmt.close();
546 5311 daigle
           logMetacat.info("PermissionController.containDocumentOwner - find the owner");
547 1425 tao
          return true;
548 2245 sgarg
        }//if
549
550 1425 tao
      }//for
551
    }//try
552 2245 sgarg
    catch (SQLException e)
553 1425 tao
    {
554
        pStmt.close();
555 2245 sgarg
556
        throw new
557 5099 daigle
        SQLException("PermissionControl.hasPermission - " +
558 1425 tao
                     "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 2245 sgarg
    return false;
573 1425 tao
  }//containDocumentOwner
574 2245 sgarg
575 1425 tao
  /**
576
    * Check if the permission order for user at that documents is allowFirst
577 2245 sgarg
    * @param principals, list of names of principals to check for
578 1425 tao
    * @param docid, document identifier to check for
579
    */
580 2245 sgarg
  private boolean isAllowFirst(String [] principals, String docId,
581 1527 tao
                               long startId)
582 1425 tao
                  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 1434 tao
    String sql = null;
590
    boolean topLever =false;
591 1527 tao
    if (startId == TOPLEVELSTARTNODEID)
592 1434 tao
    {
593
      //top level
594
      topLever = true;
595
      sql = "SELECT perm_order FROM xml_access " +
596 2045 tao
    "WHERE lower(principal_name) = ? AND docid = ? AND startnodeid is NULL";
597 1434 tao
    }
598
    else
599
    {
600
      //sub tree level
601
      sql = "SELECT perm_order FROM xml_access " +
602 2045 tao
        "WHERE lower(principal_name)= ? AND docid = ? AND startnodeid = ?";
603 1434 tao
    }
604 2245 sgarg
605 1425 tao
    try
606
    {
607
      //check out DBConnection
608
      conn=DBConnectionPool.getDBConnection("AccessControlList.isAllowFirst");
609
      serialNumber=conn.getCheckOutSerialNumber();
610 2245 sgarg
611 1425 tao
      //select permission order from database
612 1434 tao
      pStmt = conn.prepareStatement(sql);
613 2245 sgarg
614 1425 tao
      //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 2245 sgarg
621
        // if subtree, we need set subtree id
622 1434 tao
        if (!topLever)
623
        {
624 1527 tao
          pStmt.setLong(3, startId);
625 1434 tao
        }
626 2245 sgarg
627 1425 tao
        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 2245 sgarg
664
    //if reach here, means there is no permssion record for given names and
665 1425 tao
    //docid. So throw a exception.
666 2245 sgarg
667 5099 daigle
    throw new Exception("PermissionController.isAllowFirst - There is no permission record for user "+ principals[0] +
668
                        " at document " + docId);
669 2245 sgarg
670 1425 tao
  }//isAllowFirst
671 2245 sgarg
672 1425 tao
  /**
673 2245 sgarg
    * Check if the users array has allow rules for given users, docid and
674 1425 tao
    * 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 2245 sgarg
    * @param principals, list of names of principals to check for
678 1425 tao
    * @param docid, document identifier to check for
679
    * @param permission, the permssion need to check
680
    */
681 2245 sgarg
  private boolean hasAllowRule(String [] principals, String docId,
682 1527 tao
                                  int permission, long startId)
683 1425 tao
                  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 4861 daigle
   int ticketCount;
692 1425 tao
   DBConnection conn = null;
693
   int serialNumber = -1;
694 1434 tao
   boolean topLever = false;
695
   String sql = null;
696 1527 tao
   if (startId == TOPLEVELSTARTNODEID)
697 1434 tao
   {
698
     // for toplevel
699
     topLever = true;
700 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
701 2045 tao
   "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid is NULL";
702 1434 tao
   }
703
   else
704
   {
705
     topLever =false;
706 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
707 2045 tao
      "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid = ?";
708 1434 tao
   }
709 1425 tao
   try
710
   {
711
     //check out DBConnection
712
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasAllowRule");
713
     serialNumber=conn.getCheckOutSerialNumber();
714 2245 sgarg
    //This sql statement will select entry with
715 1425 tao
    //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 1434 tao
    pStmt = conn.prepareStatement(sql);
719 1425 tao
    //bind docid, perm_type
720
    pStmt.setString(1, docId);
721
    pStmt.setString(3, AccessControlInterface.ALLOW);
722 2245 sgarg
723 1434 tao
    // if subtree lever, need to set subTreeId
724
    if (!topLever)
725
    {
726 1527 tao
      pStmt.setLong(4, startId);
727 1434 tao
    }
728 2245 sgarg
729 1425 tao
    //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 2245 sgarg
739
        //permission is ok
740 1425 tao
        //the user have a permission to access the file
741
        if (( permissionValueInTable & permissionValue )== permissionValue )
742
        {
743 2245 sgarg
744 1425 tao
           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 2245 sgarg
771
772
773 1425 tao
   /**
774 2245 sgarg
    * Check if the users array has explicit deny rules for given users, docid
775 1425 tao
    * 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 2245 sgarg
    * @param principals, list of names of principals to check for
778 1425 tao
    * @param docid, document identifier to check for
779
    * @param permission, the permssion need to check
780
    */
781 2245 sgarg
  private boolean hasExplicitDenyRule(String [] principals, String docId,
782 1527 tao
                                      int permission, long startId)
783 1425 tao
                  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 1434 tao
   String sql = null;
793
   boolean topLevel = false;
794 2245 sgarg
795 1434 tao
   // decide top level or subtree level
796 1527 tao
   if (startId == TOPLEVELSTARTNODEID)
797 1434 tao
   {
798
     topLevel = true;
799 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
800 2045 tao
    "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid is NULL";
801 1434 tao
   }
802
   else
803
   {
804
     topLevel = false;
805 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
806 2045 tao
     "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid = ?";
807 1434 tao
   }
808 2245 sgarg
809 1425 tao
   try
810
   {
811
     //check out DBConnection
812 1434 tao
     conn=DBConnectionPool.getDBConnection("PermissionControl.hasExplicitDeny");
813 1425 tao
     serialNumber=conn.getCheckOutSerialNumber();
814 2245 sgarg
815 1434 tao
     pStmt = conn.prepareStatement(sql);
816 1425 tao
    //bind docid, perm_type
817
    pStmt.setString(1, docId);
818
    pStmt.setString(3, AccessControlInterface.DENY);
819 2245 sgarg
820 1434 tao
    // subtree level need to set up subtreeid
821
    if (!topLevel)
822
    {
823 1527 tao
      pStmt.setLong(4, startId);
824 1434 tao
    }
825 2245 sgarg
826 1425 tao
    //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 2245 sgarg
836 1425 tao
        //permission is ok the user doesn't have permission to access the file
837
        if (( permissionValueInTable & permissionValue )== permissionValue )
838 2245 sgarg
839 1425 tao
        {
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 2245 sgarg
  }//hasExplicitDenyRule
863 1425 tao
864 2245 sgarg
865 1425 tao
  /**
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 2245 sgarg
876 1425 tao
    if (groups!=null)
877
    {
878 2245 sgarg
      //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 1425 tao
      //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 2045 tao
        //in order to ignore case sensitive, we transfer user to lower case
887
        if (user != null)
888
        {
889
          usersPackage[0]= user.toLowerCase();
890 5311 daigle
          logMetacat.info("PermissionController.createUsersPackage - after transfer to lower case(not null): "+
891 2663 sgarg
                                     usersPackage[0]);
892 2045 tao
        }
893
        else
894
        {
895
          usersPackage[0] = user;
896
          usersPackage[0]= user.toLowerCase();
897 5311 daigle
          logMetacat.info("PermissionController.createUsersPackage - after transfer to lower case(null): "+
898 2663 sgarg
                                     usersPackage[0]);
899 2045 tao
        }
900 1425 tao
        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 2045 tao
          //tansfer group to lower case too
906
          if (groups[i-2] != null)
907
          {
908
            usersPackage[i]=groups[i-2].toLowerCase();
909
          }
910 1425 tao
        } //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 2045 tao
          if (groups[i-1] != null)
923
          {
924
            usersPackage[i]=groups[i-1].toLowerCase();
925
          }
926 1425 tao
        } //for
927
      }//else user=public
928 2245 sgarg
929 1425 tao
    }//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 2045 tao
        if (user != null)
939
        {
940
          usersPackage[0]=user.toLowerCase();
941
        }
942
        else
943
        {
944
          usersPackage[0]=user;
945
        }
946 1425 tao
        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 2245 sgarg
959
960 1425 tao
  /**
961 2245 sgarg
   * 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 1425 tao
   */
970 4466 daigle
   public static Hashtable<String, String> getUnReadableInlineDataIdList(String docidWithoutRev,
971 2291 sgarg
                                                   String user, String[] groups,
972
                                                   boolean withRevision)
973 5298 jones
                                                throws McdbException
974 2245 sgarg
   {
975 4466 daigle
     Hashtable<String, String> inlineDataList = getUnAccessableInlineDataIdList(docidWithoutRev,
976 2291 sgarg
                              user, groups, AccessControlInterface.READSTRING,
977
                              withRevision);
978 2245 sgarg
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 4466 daigle
  public static Hashtable<String, String> getUnWritableInlineDataIdList(String docidWithoutRev,
993 2291 sgarg
                                                  String user, String[] groups,
994
                                                  boolean withRevision)
995 2245 sgarg
                                               throws Exception
996 1425 tao
  {
997 4466 daigle
    Hashtable<String, String> inlineDataList = getUnAccessableInlineDataIdList(docidWithoutRev,
998 2291 sgarg
                            user, groups, AccessControlInterface.WRITESTRING,
999
                            withRevision);
1000 2245 sgarg
1001
    return inlineDataList;
1002
  }
1003
1004
1005
   /*
1006
    * This method will get hashtable which contains a unaccessable distribution
1007
    * inlinedata object list
1008 2291 sgarg
    *
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 2245 sgarg
    */
1013 4466 daigle
   private static Hashtable<String, String> getUnAccessableInlineDataIdList(String docid,
1014 2291 sgarg
                               String user, String[] groups, String permission,
1015
                               boolean withRevision)
1016 5298 jones
                             throws McdbException
1017 2245 sgarg
   {
1018 5298 jones
       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 2245 sgarg
      while (en.hasMoreElements())
1031 1425 tao
      {
1032 2245 sgarg
        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 2291 sgarg
            if(withRevision)
1040
            {
1041 5311 daigle
                logMetacat.info("PermissionController.getUnAccessableInlineDataIdList - Put subtree id " + subTreeId +
1042 2291 sgarg
                                         " and " + "inline data file name " +
1043
                                         fileId + " into " + "un" + permission +
1044 2663 sgarg
                                         " hash");
1045 4466 daigle
                unAccessibleIdList.put(subTreeId, fileId);
1046 2291 sgarg
1047
            }
1048
            else
1049
            {
1050 5311 daigle
                logMetacat.info("PermissionController.getUnAccessableInlineDataIdList - Put subtree id " + subTreeId +
1051 2291 sgarg
                                         " and " + "inline data file name " +
1052 5025 daigle
                                         DocumentUtil.getInlineDataIdWithoutRev(fileId) +
1053 2291 sgarg
                                         " into " + "un" + permission +
1054 2663 sgarg
                                         " hash");
1055 5025 daigle
                unAccessibleIdList.put(subTreeId,
1056
                		DocumentUtil.getInlineDataIdWithoutRev(fileId));
1057 2291 sgarg
            }
1058 2245 sgarg
        }
1059 1425 tao
      }
1060 4466 daigle
      return unAccessibleIdList;
1061 2245 sgarg
   }
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 4861 daigle
   private static Hashtable getAllInlineDataIdList(String docid) throws SQLException
1070 2245 sgarg
   {
1071 4861 daigle
     Hashtable inlineDataList = new Hashtable();
1072 2245 sgarg
     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 1425 tao
}