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 5742 berkley
    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
      // Check for @permission on @docid for @user and/or @groups
144
      hasPermission = hasPermission(userPackage,docId, permission);
145
    }//else
146 2245 sgarg
147 1425 tao
    return hasPermission;
148
  }
149 2245 sgarg
150
151 1425 tao
  /**
152
    * Check from db connection if the users in String array @principals has
153 2245 sgarg
    * @permission on @docid*
154 1425 tao
    * @param principals, names in userPakcage need to check for @permission
155
    * @param docid, document identifier to check on
156 2245 sgarg
    * @param permission, permission (write or all...) to check for
157 1425 tao
    */
158
  private boolean hasPermission(String [] principals, String docId,
159
                                           int permission)
160
                         throws SQLException
161
  {
162 1527 tao
    long startId = TOPLEVELSTARTNODEID;// this is for top level, so startid is 0
163 2245 sgarg
    try
164 1425 tao
    {
165
      //first, if there is a docid owner in user package, return true
166 2245 sgarg
      //because doc owner has all permssion
167 1425 tao
      if (containDocumentOwner(principals, docId))
168
      {
169 2245 sgarg
170 1425 tao
          return true;
171
      }
172 2245 sgarg
173 1425 tao
      //If there is no owner in user package, checking the table
174
      //check perm_order
175 1527 tao
      if (isAllowFirst(principals, docId, startId))
176 1425 tao
      {
177 2245 sgarg
178 1527 tao
        if (hasExplicitDenyRule(principals, docId, permission, startId))
179 1425 tao
        {
180
          //if it is allowfirst and has deny rule(either explicit )
181
          //deny access
182 2245 sgarg
183 1425 tao
          return false;
184
        }//if
185 1527 tao
        else if ( hasAllowRule(principals, docId, permission, startId))
186 1425 tao
        {
187
          //if it is allowfirst and hasn't deny rule and has allow rule
188
          //allow access
189 2245 sgarg
190 1425 tao
          return true;
191
        }//else if
192
        else
193
        {
194
          //other situation deny access
195 2245 sgarg
196 1425 tao
          return false;
197
        }//else
198
     }//if isAllowFirst
199
     else //denyFirst
200
     {
201 1527 tao
       if (hasAllowRule(principals, docId, permission, startId))
202 1425 tao
       {
203
         //if it is denyFirst and has allow rule, allow access
204
         return true;
205
       }
206
       else
207
       {
208
         //if it is denyfirst but no allow rule, deny access
209
         return false;
210
       }
211
     }//else denyfirst
212
    }//try
213
    catch (Exception e)
214
    {
215 5311 daigle
      logMetacat.warn("PermissionController.hasPermission - There is a exception in hasPermission method: "
216 2663 sgarg
                         +e.getMessage());
217 1425 tao
    }
218 2245 sgarg
219 1425 tao
    return false;
220
  }//hasPermission
221 2245 sgarg
222 1425 tao
  /**
223 2245 sgarg
   *  Method to check if a person has permission to a inline data file
224
   * @param user String
225
   * @param groups String[]
226
   * @param myPermission String
227
   * @param inlineDataId String
228
   * @throws McdbException
229
   * @return boolean
230
   */
231
  private boolean hasPermissionForInlineData(String user, String[] groups,
232
                                      String myPermission, String inlineDataId)
233 5298 jones
      throws McdbException
234 2245 sgarg
  {
235
     // this method can call the public method - hasPermission(...)
236
     // the only difference is about the ownership, you couldn't find the owner
237
     // from inlinedataId directly. You should get it from eml document itself
238
     String []userPackage = createUsersPackage(user, groups);
239 5298 jones
     try {
240
        if (containDocumentOwner(userPackage, docId))
241
         {
242
           return true;
243
         }
244
         else
245
         {
246
             PermissionController controller =
247
                                   new PermissionController(inlineDataId, false);
248
             return controller.hasPermission(user, groups, myPermission);
249
         }
250
    } catch (SQLException e) {
251
        throw new McdbException(e.getMessage());
252
    }
253 2245 sgarg
  }
254
255
  /**
256 1485 tao
   * The method to determine of a node can be access by a user just by subtree
257
   * access control
258
   */
259
  public boolean hasPermissionForSubTreeNode(String user, String[] groups,
260
                                             String myPermission, long nodeId)
261
                                             throws McdbException
262
  {
263 1492 tao
    boolean flag = true;
264 1485 tao
    // Get unaccessble subtree for this user
265 4861 daigle
    Hashtable unaccessableSubTree = hasUnaccessableSubTree(user, groups,
266 1485 tao
                                                           myPermission);
267 4861 daigle
    Enumeration en = unaccessableSubTree.elements();
268 1485 tao
    while (en.hasMoreElements())
269
    {
270
      SubTree tree = (SubTree)en.nextElement();
271
      long start = tree.getStartNodeId();
272
      long stop  = tree.getEndNodeId();
273 1492 tao
      // nodeid in unaccessablesubtree, return false
274 1485 tao
      if ( nodeId >= start && nodeId <= stop)
275
      {
276 1492 tao
        flag = false;
277 1485 tao
        break;
278
      }
279
    }
280
    return flag;
281
  }
282
  /**
283 2245 sgarg
   * This method will return a hasTable of subtree which user doesn't has the
284 1434 tao
   * permssion to access
285
   * @param user  the user name
286
   * @param groups  the groups which the use is in
287
   * @param myPermission  permission type to check for
288
   */
289 4861 daigle
  public Hashtable hasUnaccessableSubTree(String user, String[] groups,
290 1434 tao
                                       String myPermission) throws McdbException
291
  {
292 4861 daigle
    Hashtable resultUnaccessableSubTree = new Hashtable();
293 1434 tao
    String [] principals=null;
294
    int permission =AccessControlList.intValue(myPermission);
295 2245 sgarg
296 1434 tao
    //for the commnad line invocation return null(no unaccessable subtree)
297
    if ((user==null) && (groups==null || groups.length==0))
298
    {
299
      return resultUnaccessableSubTree;
300
    }
301 2245 sgarg
302 1434 tao
    //create a userpackage including user, public and group member
303
    principals=createUsersPackage(user, groups);
304
    //for the document owner return null(no unaccessable subtree)
305
    try
306
    {
307
      if (containDocumentOwner(principals, docId))
308
      {
309
       return resultUnaccessableSubTree;
310
      }
311
    }
312
    catch (SQLException ee)
313
    {
314
      throw new McdbException(ee);
315
    }
316 2245 sgarg
317 1434 tao
    // go through every subtree which has access control
318
    for (int i = 0; i< subTreeList.size(); i++)
319
    {
320
      SubTree tree = (SubTree)subTreeList.elementAt(i);
321 1527 tao
      long startId = tree.getStartNodeId();
322 2245 sgarg
323
324 1434 tao
        try
325
        {
326 1527 tao
          if (isAllowFirst(principals, docId, startId))
327 1434 tao
          {
328 2245 sgarg
329 1527 tao
            if (hasExplicitDenyRule(principals, docId, permission, startId ))
330 1434 tao
            {
331 2245 sgarg
332 1434 tao
             //if it is allowfirst and has deny rule
333
              // put the subtree into unaccessable vector
334 1527 tao
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
335 1434 tao
              {
336 1527 tao
                resultUnaccessableSubTree.put(new Long(startId), tree);
337 1434 tao
              }
338
            }//if
339 1527 tao
            else if ( hasAllowRule(principals, docId, permission, startId))
340 1434 tao
            {
341
              //if it is allowfirst and hasn't deny rule and has allow rule
342
              //allow access do nothing
343 2245 sgarg
344 1434 tao
            }//else if
345
            else
346
            {
347
              //other situation deny access
348 1527 tao
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
349 1434 tao
              {
350 1527 tao
                resultUnaccessableSubTree.put(new Long(startId), tree);
351 1434 tao
              }
352 2245 sgarg
353 1434 tao
            }//else
354
          }//if isAllowFirst
355
          else //denyFirst
356
          {
357 1527 tao
            if (hasAllowRule(principals, docId, permission,startId))
358 1434 tao
            {
359
              //if it is denyFirst and has allow rule, allow access, do nothing
360 2245 sgarg
361 1434 tao
            }
362
            else
363
            {
364
              //if it is denyfirst but no allow rule, deny access
365
              // add into vector
366 1527 tao
              if (!resultUnaccessableSubTree.containsKey(new Long(startId)))
367 1434 tao
              {
368 1527 tao
                resultUnaccessableSubTree.put(new Long(startId), tree);
369 1434 tao
              }
370
            }
371
          }//else denyfirst
372
        }//try
373
        catch( Exception e)
374
        {
375 5311 daigle
          logMetacat.error("PermissionController.hasUnaccessableSubTree - error in PermissionControl.has" +
376 2663 sgarg
                                   "UnaccessableSubTree "+e.getMessage());
377 1434 tao
          throw new McdbException(e);
378
        }
379 2245 sgarg
380 1434 tao
    }//for
381 2245 sgarg
    // merge the subtree if a subtree is another subtree'subtree
382 1521 tao
    resultUnaccessableSubTree = mergeEquivalentSubtree(resultUnaccessableSubTree);
383 1434 tao
    return resultUnaccessableSubTree;
384
  }//hasUnaccessableSubtree
385 2245 sgarg
386
387
  /*
388 1513 tao
   * A method to merge nested subtree into bigger one. For example subtree b
389
   * is a subtree of subtree a. And user doesn't have read permission for both
390
   * so we only use subtree a is enough.
391
   */
392 4861 daigle
  private Hashtable mergeEquivalentSubtree(Hashtable unAccessSubTree)
393 1513 tao
  {
394 4861 daigle
    Hashtable newSubTreeHash = new Hashtable();
395 1513 tao
    boolean   needDelete = false;
396
    // check the parameters
397
    if (unAccessSubTree == null || unAccessSubTree.isEmpty())
398
    {
399
      return newSubTreeHash;
400
    }
401
    else
402
    {
403
      // look every subtree start point and stop point, to see if it is embedded
404
      // in another one. If embedded, they are equavelent and we can use bigger
405
      // one to replace smaller one
406 4861 daigle
      Enumeration en = unAccessSubTree.elements();
407 1513 tao
      while (en.hasMoreElements())
408
      {
409
        SubTree tree    = (SubTree)en.nextElement();
410
        String  treeId  = tree.getSubTreeId();
411
        long    startId = tree.getStartNodeId();
412
        long    endId   = tree.getEndNodeId();
413 2245 sgarg
414 4861 daigle
        Enumeration enu = unAccessSubTree.elements();
415 1513 tao
        while (enu.hasMoreElements())
416
        {
417
          SubTree subTree = (SubTree)enu.nextElement();
418 4861 daigle
          String subTreeId= subTree.getSubTreeId();
419 1513 tao
          long   subTreeStartId = subTree.getStartNodeId();
420
          long   subTreeEndId   = subTree.getEndNodeId();
421
          //compare and if the first subtree is a subtree of the second
422
          // one, set neeDelete true
423
          if (startId > subTreeStartId && endId < subTreeEndId)
424
          {
425
            needDelete = true;
426 5311 daigle
            logMetacat.info("PermissionController.mergeEquivalentSubtree - the subtree: "+ treeId +
427 1513 tao
                                     " need to be get rid of from unaccessable"+
428
                                     " subtree list becuase it is a subtree of"+
429 2663 sgarg
                                     " another subtree in the list");
430 1513 tao
            break;
431
          }//if
432
        }//while
433
        // if not need to delete, put the subtree into hash
434
        if (!needDelete)
435
        {
436 1527 tao
          newSubTreeHash.put(new Long(startId), tree);
437 1513 tao
        }
438
        //reset needDelete
439
        needDelete = false;
440
      }//while
441
      return newSubTreeHash;
442
    }//else
443
  }
444 2245 sgarg
445 1434 tao
  /**
446 4080 daigle
	 * Check if a document id is a access document. Access document need user
447
	 * has "all" permission to access it.
448
	 *
449
	 * @param docId,
450
	 *            the document id need to be checked
451
	 */
452
	private boolean isAccessDocument(String docId) throws SQLException {
453
		// detele the rev number if docid contains it
454 5025 daigle
		docId = DocumentUtil.getDocIdFromString(docId);
455 4080 daigle
		PreparedStatement pStmt = null;
456
		DBConnection conn = null;
457
		int serialNumber = -1;
458
		try {
459
			// check out DBConnection
460
			conn = DBConnectionPool.getDBConnection("PermissionControl.isAccessDoc");
461
			serialNumber = conn.getCheckOutSerialNumber();
462
			pStmt = conn.prepareStatement("select doctype from xml_documents where "
463
					+ "docid like '" + docId + "'");
464
			pStmt.execute();
465
			ResultSet rs = pStmt.getResultSet();
466
			boolean hasRow = rs.next();
467
			String doctype = null;
468
			if (hasRow) {
469
				doctype = rs.getString(1);
470 2245 sgarg
471 4080 daigle
			}
472
			pStmt.close();
473 2245 sgarg
474 4080 daigle
			// if it is an access document
475
			if (doctype != null
476 4698 daigle
					&& ((MetacatUtil.getOptionList(PropertyService
477 4213 daigle
							.getProperty("xml.accessdoctype")).contains(doctype)))) {
478 2245 sgarg
479 4080 daigle
				return true;
480
			}
481 2245 sgarg
482 4080 daigle
		} catch (SQLException e) {
483
			throw new SQLException("PermissionControl.isAccessDocument "
484
					+ "Error checking" + " on document " + docId + ". " + e.getMessage());
485
		} catch (PropertyNotFoundException pnfe) {
486
			throw new SQLException("PermissionControl.isAccessDocument "
487
					+ "Error checking" + " on document " + docId + ". " + pnfe.getMessage());
488
		} finally {
489
			try {
490
				pStmt.close();
491
			} finally {
492
				DBConnectionPool.returnDBConnection(conn, serialNumber);
493
			}
494
		}
495 2245 sgarg
496 4080 daigle
		return false;
497
	}// isAccessDocument
498 2245 sgarg
499
500
501 1425 tao
  /**
502 4080 daigle
	 * Check if a stirng array contains a given documents' owner
503
	 *
504
	 * @param principals,
505
	 *            a string array storing the username, groups name and public.
506
	 * @param docid,
507
	 *            the id of given documents
508
	 */
509 1434 tao
  private boolean containDocumentOwner( String[] principals, String docId)
510 1425 tao
                    throws SQLException
511
  {
512
    int lengthOfArray=principals.length;
513 2245 sgarg
    boolean hasRow;
514 1425 tao
    PreparedStatement pStmt=null;
515
    DBConnection conn = null;
516
    int serialNumber = -1;
517 2245 sgarg
518 1425 tao
    try
519
    {
520
      //check out DBConnection
521 1434 tao
     conn=DBConnectionPool.getDBConnection("PermissionControl.containDocOnwer");
522 1425 tao
      serialNumber=conn.getCheckOutSerialNumber();
523
      pStmt = conn.prepareStatement(
524
                "SELECT 'x' FROM xml_documents " +
525 6196 leinfelder
                "WHERE docid = ? AND lower(user_owner) = ? " +
526
                "UNION ALL " +
527
                "SELECT 'x' FROM xml_revisions " +
528
                "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 6196 leinfelder
        pStmt.setString(3, docId);
538
        pStmt.setString(4, principals[i]);
539 5311 daigle
        logMetacat.info("PermissionController.containDocumentOwner - the principle stack is : " +
540 2663 sgarg
                                  principals[i]);
541 1425 tao
542
        pStmt.execute();
543
        ResultSet rs = pStmt.getResultSet();
544
        hasRow = rs.next();
545 2245 sgarg
        if (hasRow)
546 1425 tao
        {
547
          pStmt.close();
548 5311 daigle
           logMetacat.info("PermissionController.containDocumentOwner - find the owner");
549 1425 tao
          return true;
550 2245 sgarg
        }//if
551
552 1425 tao
      }//for
553
    }//try
554 2245 sgarg
    catch (SQLException e)
555 1425 tao
    {
556
        pStmt.close();
557 2245 sgarg
558
        throw new
559 5099 daigle
        SQLException("PermissionControl.hasPermission - " +
560 1425 tao
                     "Error checking ownership for " + principals[0] +
561
                     " on document #" + docId + ". " + e.getMessage());
562
    }//catch
563
    finally
564
    {
565
      try
566
      {
567
        pStmt.close();
568
      }
569
      finally
570
      {
571
        DBConnectionPool.returnDBConnection(conn, serialNumber);
572
      }
573
    }
574 2245 sgarg
    return false;
575 1425 tao
  }//containDocumentOwner
576 2245 sgarg
577 1425 tao
  /**
578
    * Check if the permission order for user at that documents is allowFirst
579 2245 sgarg
    * @param principals, list of names of principals to check for
580 1425 tao
    * @param docid, document identifier to check for
581
    */
582 2245 sgarg
  private boolean isAllowFirst(String [] principals, String docId,
583 1527 tao
                               long startId)
584 1425 tao
                  throws SQLException, Exception
585
  {
586
    int lengthOfArray=principals.length;
587
    boolean hasRow;
588
    PreparedStatement pStmt = null;
589
    DBConnection conn = null;
590
    int serialNumber = -1;
591 1434 tao
    String sql = null;
592
    boolean topLever =false;
593 1527 tao
    if (startId == TOPLEVELSTARTNODEID)
594 1434 tao
    {
595
      //top level
596
      topLever = true;
597
      sql = "SELECT perm_order FROM xml_access " +
598 2045 tao
    "WHERE lower(principal_name) = ? AND docid = ? AND startnodeid is NULL";
599 1434 tao
    }
600
    else
601
    {
602
      //sub tree level
603
      sql = "SELECT perm_order FROM xml_access " +
604 2045 tao
        "WHERE lower(principal_name)= ? AND docid = ? AND startnodeid = ?";
605 1434 tao
    }
606 2245 sgarg
607 1425 tao
    try
608
    {
609
      //check out DBConnection
610
      conn=DBConnectionPool.getDBConnection("AccessControlList.isAllowFirst");
611
      serialNumber=conn.getCheckOutSerialNumber();
612 2245 sgarg
613 1425 tao
      //select permission order from database
614 1434 tao
      pStmt = conn.prepareStatement(sql);
615 2245 sgarg
616 1425 tao
      //check every name in the array
617
      for (int i=0; i<lengthOfArray;i++)
618
      {
619
        //bind value
620
        pStmt.setString(1, principals[i]);//user name
621
        pStmt.setString(2, docId);//docid
622 2245 sgarg
623
        // if subtree, we need set subtree id
624 1434 tao
        if (!topLever)
625
        {
626 1527 tao
          pStmt.setLong(3, startId);
627 1434 tao
        }
628 2245 sgarg
629 1425 tao
        pStmt.execute();
630
        ResultSet rs = pStmt.getResultSet();
631
        hasRow=rs.next();
632
        if (hasRow)
633
        {
634
          //get the permission order from data base
635
          String permissionOrder=rs.getString(1);
636
          //if the permission order is "allowFirst
637
          if (permissionOrder.equalsIgnoreCase(AccessControlInterface.ALLOWFIRST))
638
          {
639
            pStmt.close();
640
            return true;
641
          }
642
          else
643
          {
644
            pStmt.close();
645
            return false;
646
          }
647
        }//if
648
      }//for
649
    }//try
650
    catch (SQLException e)
651
    {
652
      throw e;
653
    }
654
    finally
655
    {
656
      try
657
      {
658
        pStmt.close();
659
      }
660
      finally
661
      {
662
        DBConnectionPool.returnDBConnection(conn, serialNumber);
663
      }
664
    }
665 2245 sgarg
666
    //if reach here, means there is no permssion record for given names and
667 1425 tao
    //docid. So throw a exception.
668 2245 sgarg
669 5099 daigle
    throw new Exception("PermissionController.isAllowFirst - There is no permission record for user "+ principals[0] +
670
                        " at document " + docId);
671 2245 sgarg
672 1425 tao
  }//isAllowFirst
673 2245 sgarg
674 1425 tao
  /**
675 2245 sgarg
    * Check if the users array has allow rules for given users, docid and
676 1425 tao
    * permission.
677
    * If it has permission rule and ticket count is greater than 0, the ticket
678
    * number will decrease one for every allow rule
679 2245 sgarg
    * @param principals, list of names of principals to check for
680 1425 tao
    * @param docid, document identifier to check for
681
    * @param permission, the permssion need to check
682
    */
683 2245 sgarg
  private boolean hasAllowRule(String [] principals, String docId,
684 1527 tao
                                  int permission, long startId)
685 1425 tao
                  throws SQLException, Exception
686
 {
687
   int lengthOfArray=principals.length;
688
   boolean allow=false;//initial value is no allow rule
689
   ResultSet rs;
690
   PreparedStatement pStmt = null;
691
   int permissionValue=permission;
692
   int permissionValueInTable;
693 4861 daigle
   int ticketCount;
694 1425 tao
   DBConnection conn = null;
695
   int serialNumber = -1;
696 1434 tao
   boolean topLever = false;
697
   String sql = null;
698 1527 tao
   if (startId == TOPLEVELSTARTNODEID)
699 1434 tao
   {
700
     // for toplevel
701
     topLever = true;
702 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
703 2045 tao
   "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid is NULL";
704 1434 tao
   }
705
   else
706
   {
707
     topLever =false;
708 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
709 2045 tao
      "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid = ?";
710 1434 tao
   }
711 1425 tao
   try
712
   {
713
     //check out DBConnection
714
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasAllowRule");
715
     serialNumber=conn.getCheckOutSerialNumber();
716 2245 sgarg
    //This sql statement will select entry with
717 1425 tao
    //begin_time<=currentTime<=end_time in xml_access table
718
    //If begin_time or end_time is null in table, isnull(begin_time, sysdate)
719
    //function will assign begin_time=sysdate
720 1434 tao
    pStmt = conn.prepareStatement(sql);
721 1425 tao
    //bind docid, perm_type
722
    pStmt.setString(1, docId);
723
    pStmt.setString(3, AccessControlInterface.ALLOW);
724 2245 sgarg
725 1434 tao
    // if subtree lever, need to set subTreeId
726
    if (!topLever)
727
    {
728 1527 tao
      pStmt.setLong(4, startId);
729 1434 tao
    }
730 2245 sgarg
731 1425 tao
    //bind every elenment in user name array
732
    for (int i=0;i<lengthOfArray; i++)
733
    {
734
      pStmt.setString(2, principals[i]);
735
      pStmt.execute();
736
      rs=pStmt.getResultSet();
737
      while (rs.next())//check every entry for one user
738
      {
739
        permissionValueInTable=rs.getInt(1);
740 2245 sgarg
741
        //permission is ok
742 1425 tao
        //the user have a permission to access the file
743
        if (( permissionValueInTable & permissionValue )== permissionValue )
744
        {
745 2245 sgarg
746 1425 tao
           allow=true;//has allow rule entry
747
        }//if
748
      }//while
749
    }//for
750
   }//try
751
   catch (SQLException sqlE)
752
   {
753
     throw sqlE;
754
   }
755
   catch (Exception e)
756
   {
757
     throw e;
758
   }
759
   finally
760
   {
761
     try
762
     {
763
       pStmt.close();
764
     }
765
     finally
766
     {
767
       DBConnectionPool.returnDBConnection(conn, serialNumber);
768
     }
769
   }
770
    return allow;
771
 }//hasAllowRule
772 2245 sgarg
773
774
775 1425 tao
   /**
776 2245 sgarg
    * Check if the users array has explicit deny rules for given users, docid
777 1425 tao
    * and permission. That means the perm_type is deny and current time is
778
    * less than end_time and greater than begin time, or no time limit.
779 2245 sgarg
    * @param principals, list of names of principals to check for
780 1425 tao
    * @param docid, document identifier to check for
781
    * @param permission, the permssion need to check
782
    */
783 2245 sgarg
  private boolean hasExplicitDenyRule(String [] principals, String docId,
784 1527 tao
                                      int permission, long startId)
785 1425 tao
                  throws SQLException
786
 {
787
   int lengthOfArray=principals.length;
788
   ResultSet rs;
789
   PreparedStatement pStmt = null;
790
   int permissionValue=permission;
791
   int permissionValueInTable;
792
   DBConnection conn = null;
793
   int serialNumber = -1;
794 1434 tao
   String sql = null;
795
   boolean topLevel = false;
796 2245 sgarg
797 1434 tao
   // decide top level or subtree level
798 1527 tao
   if (startId == TOPLEVELSTARTNODEID)
799 1434 tao
   {
800
     topLevel = true;
801 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
802 2045 tao
    "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid is NULL";
803 1434 tao
   }
804
   else
805
   {
806
     topLevel = false;
807 2245 sgarg
     sql = "SELECT permission FROM xml_access WHERE docid = ? " +
808 2045 tao
     "AND lower(principal_name) = ? AND perm_type = ? AND startnodeid = ?";
809 1434 tao
   }
810 2245 sgarg
811 1425 tao
   try
812
   {
813
     //check out DBConnection
814 1434 tao
     conn=DBConnectionPool.getDBConnection("PermissionControl.hasExplicitDeny");
815 1425 tao
     serialNumber=conn.getCheckOutSerialNumber();
816 2245 sgarg
817 1434 tao
     pStmt = conn.prepareStatement(sql);
818 1425 tao
    //bind docid, perm_type
819
    pStmt.setString(1, docId);
820
    pStmt.setString(3, AccessControlInterface.DENY);
821 2245 sgarg
822 1434 tao
    // subtree level need to set up subtreeid
823
    if (!topLevel)
824
    {
825 1527 tao
      pStmt.setLong(4, startId);
826 1434 tao
    }
827 2245 sgarg
828 1425 tao
    //bind every elenment in user name array
829
    for (int i=0;i<lengthOfArray; i++)
830
    {
831
      pStmt.setString(2, principals[i]);
832
      pStmt.execute();
833
      rs=pStmt.getResultSet();
834
      while (rs.next())//check every entry for one user
835
      {
836
        permissionValueInTable=rs.getInt(1);
837 2245 sgarg
838 1425 tao
        //permission is ok the user doesn't have permission to access the file
839
        if (( permissionValueInTable & permissionValue )== permissionValue )
840 2245 sgarg
841 1425 tao
        {
842
           pStmt.close();
843
           return true;
844
         }//if
845
      }//while
846
    }//for
847
   }//try
848
   catch (SQLException e)
849
   {
850
     throw e;
851
   }//catch
852
   finally
853
   {
854
     try
855
     {
856
       pStmt.close();
857
     }
858
     finally
859
     {
860
       DBConnectionPool.returnDBConnection(conn, serialNumber);
861
     }
862
   }//finally
863
   return false;//no deny rule
864 2245 sgarg
  }//hasExplicitDenyRule
865 1425 tao
866 2245 sgarg
867 1425 tao
  /**
868
    * Creat a users pakages to check permssion rule, user itself, public and
869
    * the gourps the user belong will be include in this package
870
    * @param user, the name of user
871
    * @param groups, the string array of the groups that user belong to
872
    */
873
  private String[] createUsersPackage(String user, String [] groups)
874
  {
875
    String [] usersPackage=null;
876
    int lengthOfPackage;
877 2245 sgarg
878 1425 tao
    if (groups!=null)
879
    {
880 2245 sgarg
      //if gouprs is not null and user is not public, we should create a array
881
      //to store the groups and user and public.
882 1425 tao
      //So the length of userPackage is the length of group plus two
883
      if (!user.equalsIgnoreCase(AccessControlInterface.PUBLIC))
884
      {
885
        lengthOfPackage=(groups.length)+2;
886
        usersPackage=new String [lengthOfPackage];
887
        //the first two elements is user self and public
888 2045 tao
        //in order to ignore case sensitive, we transfer user to lower case
889
        if (user != null)
890
        {
891
          usersPackage[0]= user.toLowerCase();
892 5311 daigle
          logMetacat.info("PermissionController.createUsersPackage - after transfer to lower case(not null): "+
893 2663 sgarg
                                     usersPackage[0]);
894 2045 tao
        }
895
        else
896
        {
897
          usersPackage[0] = user;
898
          usersPackage[0]= user.toLowerCase();
899 5311 daigle
          logMetacat.info("PermissionController.createUsersPackage - after transfer to lower case(null): "+
900 2663 sgarg
                                     usersPackage[0]);
901 2045 tao
        }
902 1425 tao
        usersPackage[1]=AccessControlInterface.PUBLIC;
903
        //put groups element from index 0 to lengthOfPackage-3 into userPackage
904
        //from index 2 to lengthOfPackage-1
905
        for (int i=2; i<lengthOfPackage; i++)
906
        {
907 2045 tao
          //tansfer group to lower case too
908
          if (groups[i-2] != null)
909
          {
910
            usersPackage[i]=groups[i-2].toLowerCase();
911
          }
912 1425 tao
        } //for
913
      }//if user!=public
914
      else//use=public
915
      {
916
        lengthOfPackage=(groups.length)+1;
917
        usersPackage=new String [lengthOfPackage];
918
        //the first lements is public
919
        usersPackage[0]=AccessControlInterface.PUBLIC;
920
        //put groups element from index 0 to lengthOfPackage-2 into userPackage
921
        //from index 1 to lengthOfPackage-1
922
        for (int i=1; i<lengthOfPackage; i++)
923
        {
924 2045 tao
          if (groups[i-1] != null)
925
          {
926
            usersPackage[i]=groups[i-1].toLowerCase();
927
          }
928 1425 tao
        } //for
929
      }//else user=public
930 2245 sgarg
931 1425 tao
    }//if groups!=null
932
    else
933
    {
934
      //because no groups, the userPackage only need two elements
935
      //one is for user, the other is for public
936
      if (!user.equalsIgnoreCase(AccessControlInterface.PUBLIC))
937
      {
938
        lengthOfPackage=2;
939
        usersPackage=new String [lengthOfPackage];
940 2045 tao
        if (user != null)
941
        {
942
          usersPackage[0]=user.toLowerCase();
943
        }
944
        else
945
        {
946
          usersPackage[0]=user;
947
        }
948 1425 tao
        usersPackage[1]=AccessControlInterface.PUBLIC;
949
      }//if user!=public
950
      else //user==public
951
      {
952
        //only put public into array
953
        lengthOfPackage=1;
954
        usersPackage=new String [lengthOfPackage];
955
        usersPackage[0]=AccessControlInterface.PUBLIC;
956
      }
957
    }//else groups==null
958
    return usersPackage;
959
  }//createUsersPackage
960 2245 sgarg
961
962 1425 tao
  /**
963 2245 sgarg
   * A static method to get Hashtable which cointains a inlinedata object list that
964
   * user can't read it. The key is subtree id of inlinedata, the data is
965
   * internal file name for the inline data which is stored as docid
966
   * in xml_access table or data object doc id.
967
   * @param docidWithoutRev, metadata docid which should be the accessfileid
968
   *                         in the table
969
   * @param user , the name of user
970
   * @param groups, the group which the user belong to
971 1425 tao
   */
972 4466 daigle
   public static Hashtable<String, String> getUnReadableInlineDataIdList(String docidWithoutRev,
973 2291 sgarg
                                                   String user, String[] groups,
974
                                                   boolean withRevision)
975 5298 jones
                                                throws McdbException
976 2245 sgarg
   {
977 4466 daigle
     Hashtable<String, String> inlineDataList = getUnAccessableInlineDataIdList(docidWithoutRev,
978 2291 sgarg
                              user, groups, AccessControlInterface.READSTRING,
979
                              withRevision);
980 2245 sgarg
981
     return inlineDataList;
982
   }
983
984
   /**
985
  * A static method to get Hashtable which cointains a inline  data object list that
986
  * user can't overwrite it. The key is subtree id of inline data distrubition,
987
  * the value is internal file name for the inline data which is stored as docid
988
  * in xml_access table or data object doc id.
989
  * @param docidWithoutRev, metadata docid which should be the accessfileid
990
  *                         in the table
991
  * @param user , the name of user
992
  * @param groups, the group which the user belong to
993
  */
994 4466 daigle
  public static Hashtable<String, String> getUnWritableInlineDataIdList(String docidWithoutRev,
995 2291 sgarg
                                                  String user, String[] groups,
996
                                                  boolean withRevision)
997 2245 sgarg
                                               throws Exception
998 1425 tao
  {
999 4466 daigle
    Hashtable<String, String> inlineDataList = getUnAccessableInlineDataIdList(docidWithoutRev,
1000 2291 sgarg
                            user, groups, AccessControlInterface.WRITESTRING,
1001
                            withRevision);
1002 2245 sgarg
1003
    return inlineDataList;
1004
  }
1005
1006
1007
   /*
1008
    * This method will get hashtable which contains a unaccessable distribution
1009
    * inlinedata object list
1010 2291 sgarg
    *
1011
    * withRevision is used to get inline id list with or without revision number
1012
    * e.g. when withRevision is true, temp.1.1.1, temp.1.1.2 would be returned
1013
    * otherwise temp.1.1 and temp.1.2 would be returned.
1014 2245 sgarg
    */
1015 4466 daigle
   private static Hashtable<String, String> getUnAccessableInlineDataIdList(String docid,
1016 2291 sgarg
                               String user, String[] groups, String permission,
1017
                               boolean withRevision)
1018 5298 jones
                             throws McdbException
1019 2245 sgarg
   {
1020 5298 jones
       Hashtable<String, String> unAccessibleIdList = new Hashtable();
1021
       if (user == null) {
1022
           return unAccessibleIdList;
1023
       }
1024
1025
       Hashtable allIdList;
1026
       try {
1027
           allIdList = getAllInlineDataIdList(docid);
1028
       } catch (SQLException e) {
1029
           throw new McdbException(e.getMessage());
1030
       }
1031
       Enumeration<String> en = allIdList.keys();
1032 2245 sgarg
      while (en.hasMoreElements())
1033 1425 tao
      {
1034 2245 sgarg
        String subTreeId = (String) en.nextElement();
1035
        String fileId = (String) allIdList.get(subTreeId);
1036
        //Here fileid is internal file id for line data. It stored in docid
1037
        // field in xml_access table. so we don't need to delete rev
1038
        PermissionController controller = new PermissionController(docid, false);
1039
        if (!controller.hasPermissionForInlineData(user, groups, permission, fileId))
1040
        {
1041 2291 sgarg
            if(withRevision)
1042
            {
1043 5311 daigle
                logMetacat.info("PermissionController.getUnAccessableInlineDataIdList - Put subtree id " + subTreeId +
1044 2291 sgarg
                                         " and " + "inline data file name " +
1045
                                         fileId + " into " + "un" + permission +
1046 2663 sgarg
                                         " hash");
1047 4466 daigle
                unAccessibleIdList.put(subTreeId, fileId);
1048 2291 sgarg
1049
            }
1050
            else
1051
            {
1052 5311 daigle
                logMetacat.info("PermissionController.getUnAccessableInlineDataIdList - Put subtree id " + subTreeId +
1053 2291 sgarg
                                         " and " + "inline data file name " +
1054 5025 daigle
                                         DocumentUtil.getInlineDataIdWithoutRev(fileId) +
1055 2291 sgarg
                                         " into " + "un" + permission +
1056 2663 sgarg
                                         " hash");
1057 5025 daigle
                unAccessibleIdList.put(subTreeId,
1058
                		DocumentUtil.getInlineDataIdWithoutRev(fileId));
1059 2291 sgarg
            }
1060 2245 sgarg
        }
1061 1425 tao
      }
1062 4466 daigle
      return unAccessibleIdList;
1063 2245 sgarg
   }
1064
1065
1066
   /*
1067
    * This method will get a hash table from xml_access table for all records
1068
    * about the inline data. The key is subtree id and data is a inline internal
1069
    * file name
1070
    */
1071 4861 daigle
   private static Hashtable getAllInlineDataIdList(String docid) throws SQLException
1072 2245 sgarg
   {
1073 4861 daigle
     Hashtable inlineDataList = new Hashtable();
1074 2245 sgarg
     String sql = "SELECT subtreeid, docid FROM xml_access WHERE " +
1075
                   "accessfileid = ? AND subtreeid  IS NOT NULL";
1076
     PreparedStatement pStmt=null;
1077
     ResultSet rs=null;
1078
     DBConnection conn=null;
1079
     int serialNumber=-1;
1080
     try
1081
     {
1082
       //check out DBConnection
1083
       conn=DBConnectionPool.getDBConnection("PermissionControl.getDataSetId");
1084
       serialNumber=conn.getCheckOutSerialNumber();
1085
       pStmt=conn.prepareStatement(sql);
1086
       //bind the value to query
1087
       pStmt.setString(1, docid);
1088
       //execute the query
1089
       pStmt.execute();
1090
       rs=pStmt.getResultSet();
1091
       //process the result
1092
       while(rs.next())
1093
       {
1094
         String subTreeId = rs.getString(1);
1095
         String inlineDataId = rs.getString(2);
1096
         if (subTreeId != null && !subTreeId.trim().equals("") &&
1097
            inlineDataId != null && !inlineDataId.trim().equals(""))
1098
         {
1099
           inlineDataList.put(subTreeId, inlineDataId);
1100
         }
1101
      }//while
1102
     }//try
1103
     finally
1104
     {
1105
       try
1106
       {
1107
         pStmt.close();
1108
       }
1109
       finally
1110
       {
1111
         DBConnectionPool.returnDBConnection(conn, serialNumber);
1112
       }
1113
     }//finally
1114
     return inlineDataList;
1115
   }//getAllInlineDataIdList
1116 1425 tao
}