Project

General

Profile

1 555 bojilova
/**
2
 *  '$RCSfile$'
3
 *    Purpose: A Class that loads eml-access.xml file containing ACL
4
 *             for a metadata document into relational DB
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Jivka Bojilova
8
 *    Release: @release@
9
 *
10
 *   '$Author$'
11
 *     '$Date$'
12
 * '$Revision$'
13 669 jones
 *
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 555 bojilova
 */
28
29
package edu.ucsb.nceas.metacat;
30
31
import java.io.*;
32
import java.sql.*;
33
import java.util.Stack;
34
import java.util.Vector;
35 652 bojilova
import java.util.Hashtable;
36
import java.net.URL;
37
import java.net.MalformedURLException;
38 555 bojilova
39
import org.xml.sax.Attributes;
40
import org.xml.sax.InputSource;
41 598 bojilova
import org.xml.sax.ContentHandler;
42
import org.xml.sax.EntityResolver;
43
import org.xml.sax.ErrorHandler;
44 555 bojilova
import org.xml.sax.SAXException;
45
import org.xml.sax.SAXParseException;
46
import org.xml.sax.XMLReader;
47
import org.xml.sax.helpers.XMLReaderFactory;
48
import org.xml.sax.helpers.DefaultHandler;
49
50
/**
51
 * A Class that loads eml-access.xml file containing ACL for a metadata
52
 * document into relational DB. It extends DefaultHandler class to handle
53
 * SAX parsing events when processing the XML stream.
54
 */
55
public class AccessControlList extends DefaultHandler {
56
57 862 berkley
  private static final int CHMOD = 1;
58 774 bojilova
  private static final int WRITE = 2;
59
  private static final int READ = 4;
60 862 berkley
  private static final int ALL = 7;
61 951 tao
  private static final String ALLOWFIRST="allowFirst";
62
  private static final String DENYFIRST="denyFirst";
63
  private static final String ALLOW="allow";
64
  private static final String DENY="deny";
65
  private static final String PUBLIC="public";
66 774 bojilova
  private static String sysdate = MetaCatUtil.dbAdapter.getDateTimeFunction();
67
  private static String isnull = MetaCatUtil.dbAdapter.getIsNULLFunction();
68 961 tao
69 1214 tao
  private DBConnection connection;
70 555 bojilova
  private String parserName;
71
  private Stack elementStack;
72 645 bojilova
  private String server;
73 802 bojilova
  private String sep;
74 961 tao
75 598 bojilova
  private boolean	processingDTD;
76 645 bojilova
  private String  user;
77 802 bojilova
  private String[] groups;
78 638 bojilova
  private String  aclid;
79 802 bojilova
  private int     rev;
80 598 bojilova
  private String 	docname;
81
  private String 	doctype;
82
  private String 	systemid;
83
84 665 bojilova
  private String docurl;
85
  private Vector resourceURL;
86
  private Vector resourceID;
87 660 bojilova
  private Vector principal;
88 570 bojilova
  private int    permission;
89
  private String permType;
90
  private String permOrder;
91 802 bojilova
//  private String publicAcc;
92 570 bojilova
  private String beginTime;
93
  private String endTime;
94
  private int    ticketCount;
95 684 bojilova
  private int    serverCode = 1;
96 802 bojilova
97
  private Vector aclObjects = new Vector();
98 859 berkley
  private boolean instarttag = true;
99
  private String tagName = "";
100 555 bojilova
  /**
101
   * Construct an instance of the AccessControlList class.
102 688 bojilova
   * It is used by the permission check up from DBQuery or DocumentImpl
103
   * and from "getaccesscontrol" action
104 570 bojilova
   *
105 684 bojilova
   * @param conn the JDBC connection where acl info is get
106 570 bojilova
   */
107 1214 tao
  public AccessControlList(DBConnection conn) throws SQLException
108 570 bojilova
  {
109 1214 tao
    this.connection = conn;
110 570 bojilova
  }
111 1214 tao
112 570 bojilova
113 1214 tao
114
115 570 bojilova
  /**
116
   * Construct an instance of the AccessControlList class.
117 555 bojilova
   * It parse acl file and loads acl data into db connection.
118
   *
119
   * @param conn the JDBC connection where acl data are loaded
120 684 bojilova
   * @param aclid the Accession# of the document with the acl data
121 570 bojilova
   * @param acl the acl file containing acl data
122 684 bojilova
   * @param user the user connected to MetaCat servlet and owns the document
123 802 bojilova
   * @param groups the groups to which user belongs
124 684 bojilova
   * @param serverCode the serverid from xml_replication on which this document
125
   *        resides.
126 555 bojilova
   */
127 1214 tao
  public AccessControlList(DBConnection conn, String aclid, //Reader acl,
128 802 bojilova
                           String user, String[] groups, int serverCode)
129 819 bojilova
                  throws SAXException, IOException, McdbException
130 555 bojilova
  {
131 802 bojilova
    String parserName = MetaCatUtil.getOption("saxparser");
132
    this.server = MetaCatUtil.getOption("server");
133
    this.sep = MetaCatUtil.getOption("accNumSeparator");
134 555 bojilova
135 1214 tao
    this.connection = conn;
136 555 bojilova
    this.parserName = parserName;
137 598 bojilova
    this.processingDTD = false;
138 570 bojilova
    this.elementStack = new Stack();
139
140 645 bojilova
    this.user = user;
141 802 bojilova
    this.groups = groups;
142 638 bojilova
    this.aclid = aclid;
143 665 bojilova
    this.resourceURL = new Vector();
144
    this.resourceID = new Vector();
145 660 bojilova
    this.principal = new Vector();
146 570 bojilova
    this.permission = 0;
147
    this.ticketCount = 0;
148 802 bojilova
  //  this.publicAcc = null;
149 684 bojilova
    this.serverCode = serverCode;
150 638 bojilova
151 819 bojilova
    // read the access file from db connection
152 1214 tao
    DocumentImpl acldoc = new DocumentImpl(aclid);
153 819 bojilova
    String acl = acldoc.toString();
154
    this.rev = acldoc.getRev();
155
156
    // Initialize the parse
157 555 bojilova
    XMLReader parser = initializeParser();
158 819 bojilova
    // parse the access file and write the info to xml_access
159
    parser.parse(new InputSource(new StringReader(acl)));
160
161 555 bojilova
  }
162
163 819 bojilova
// NOT USED
164
//  /**
165
//   * Construct an instance of the AccessControlList class.
166
//   * It parses eml-access file and loads acl data into db connection.
167
//   * It is used from command line execution.
168
//   *
169
//   * @param conn the JDBC connection where acl data are loaded
170
//   * @param docid the Accession# of the document with the acl data
171
//   * @param aclfilename the name of acl file containing acl data
172
//   * @param user the user connected to MetaCat servlet and owns the document
173
//   * @param groups the groups to which user belongs
174
//   */
175
//  public AccessControlList( Connection conn, String aclid, String aclfilename,
176
//                           String user, String[] groups )
177
//                  throws SAXException, IOException, McdbException
178
//  {
179
//    this(conn, aclid, new FileReader(new File(aclfilename).toString()),
180
//         user, groups, 1);
181
//  }
182 638 bojilova
183 660 bojilova
  /* Set up the SAX parser for reading the XML serialized ACL */
184 555 bojilova
  private XMLReader initializeParser() throws SAXException
185
  {
186
    XMLReader parser = null;
187
188
    // Get an instance of the parser
189
    parser = XMLReaderFactory.createXMLReader(parserName);
190
191 598 bojilova
    // Turn off validation
192 638 bojilova
    parser.setFeature("http://xml.org/sax/features/validation", true);
193 598 bojilova
194
    // Set Handlers in the parser
195 555 bojilova
    // Set the ContentHandler to this instance
196 598 bojilova
    parser.setContentHandler((ContentHandler)this);
197 555 bojilova
198 598 bojilova
    // make a DBEntityResolver instance
199
    // Set the EntityReslover to DBEntityResolver instance
200 1214 tao
    EntityResolver eresolver = new DBEntityResolver(connection,this,null);
201 598 bojilova
    parser.setEntityResolver((EntityResolver)eresolver);
202
203 555 bojilova
    // Set the ErrorHandler to this instance
204 598 bojilova
    parser.setErrorHandler((ErrorHandler)this);
205 555 bojilova
206 862 berkley
    return parser;
207 555 bojilova
  }
208
209
  /**
210 688 bojilova
   * Callback method used by the SAX Parser when beginning of the document
211 645 bojilova
   */
212
  public void startDocument() throws SAXException
213
  {
214
    //delete all previously submitted permissions @ relations
215
    //this happens only on UPDATE of the access file
216
    try {
217 819 bojilova
      this.aclObjects = getACLObjects(aclid);
218 802 bojilova
219 819 bojilova
      //delete all permissions for resources related to @aclid if any
220 645 bojilova
      if ( aclid != null ) {
221
        deletePermissionsForRelatedResources(aclid);
222
      }
223
    } catch (SQLException sqle) {
224
      throw new SAXException(sqle);
225
    }
226
  }
227
228
  /**
229 688 bojilova
   * Callback method used by the SAX Parser when the start tag of an
230 555 bojilova
   * element is detected. Used in this context to parse and store
231
   * the acl information in class variables.
232
   */
233
  public void startElement (String uri, String localName,
234
                            String qName, Attributes atts)
235
         throws SAXException
236
  {
237 859 berkley
    instarttag = true;
238
    if(localName.equals("allow"))
239
    {
240
      tagName = "allow";
241
    }
242
    else if(localName.equals("deny"))
243
    {
244
      tagName = "deny";
245
    }
246 555 bojilova
    BasicNode currentNode = new BasicNode(localName);
247
    if (atts != null) {
248
      int len = atts.getLength();
249
      for (int i = 0; i < len; i++) {
250
        currentNode.setAttribute(atts.getLocalName(i), atts.getValue(i));
251
      }
252
    }
253 802 bojilova
    if ( currentNode.getTagName().equals("acl") ) {
254 570 bojilova
      permOrder = currentNode.getAttribute("order");
255 802 bojilova
    //  publicAcc = currentNode.getAttribute("public");
256 570 bojilova
    }
257 555 bojilova
    elementStack.push(currentNode);
258
  }
259
260
  /**
261 688 bojilova
   * Callback method used by the SAX Parser when the text sequences of an
262 555 bojilova
   * xml stream are detected. Used in this context to parse and store
263
   * the acl information in class variables.
264 859 berkley
   */
265 555 bojilova
  public void characters(char ch[], int start, int length)
266
         throws SAXException
267
  {
268 859 berkley
    if(!instarttag)
269
    {
270
      return;
271
    }
272 555 bojilova
    String inputString = new String(ch, start, length);
273 859 berkley
    inputString = inputString.trim();
274 862 berkley
    //System.out.println("==============inputString: " + inputString);
275 555 bojilova
    BasicNode currentNode = (BasicNode)elementStack.peek();
276
    String currentTag = currentNode.getTagName();
277
278 802 bojilova
      if (currentTag.equals("principal")) {
279 645 bojilova
280 802 bojilova
        principal.addElement(inputString);
281 645 bojilova
282 802 bojilova
      } else if (currentTag.equals("permission")) {
283 645 bojilova
284 802 bojilova
        if ( inputString.trim().toUpperCase().equals("READ") ) {
285
          permission = permission | READ;
286
        } else if ( inputString.trim().toUpperCase().equals("WRITE") ) {
287
          permission = permission | WRITE;
288 944 tao
        } else if ( inputString.trim().toUpperCase().equals("CHANGEPERMISSION"))
289
        {
290 862 berkley
          permission = permission | CHMOD;
291 802 bojilova
        } else if ( inputString.trim().toUpperCase().equals("ALL") ) {
292
          permission = permission | ALL;
293 862 berkley
        }/*else{
294 802 bojilova
          throw new SAXException("Unknown permission type: " + inputString);
295 859 berkley
        }*/
296 645 bojilova
297 802 bojilova
      } else if ( currentTag.equals("startDate") && beginTime == null ) {
298
        beginTime = inputString.trim();
299 645 bojilova
300 802 bojilova
      } else if ( currentTag.equals("stopDate") && endTime == null) {
301
        endTime = inputString.trim();
302 645 bojilova
303 802 bojilova
      } else if (currentTag.equals("ticketCount") && ticketCount == 0 ) {
304
        try {
305
          ticketCount = (new Integer(inputString.trim())).intValue();
306
        } catch (NumberFormatException nfe) {
307
          throw new SAXException("Wrong integer format for:" + inputString);
308
        }
309 555 bojilova
      }
310
  }
311
312
  /**
313 688 bojilova
   * Callback method used by the SAX Parser when the end tag of an
314 555 bojilova
   * element is detected. Used in this context to parse and store
315
   * the acl information in class variables.
316
   */
317
  public void endElement (String uri, String localName, String qName)
318
         throws SAXException
319
  {
320 859 berkley
    instarttag = false;
321 688 bojilova
    BasicNode leaving = (BasicNode)elementStack.pop();
322
    String leavingTagName = leaving.getTagName();
323
324 802 bojilova
    if ( leavingTagName.equals("allow") ||
325
         leavingTagName.equals("deny")    ) {
326 570 bojilova
327
      if ( permission > 0 ) {
328 555 bojilova
329 570 bojilova
        // insert into db calculated permission for the list of principals
330
        try {
331 802 bojilova
          // go through the objects in xml_relation about this acl doc
332
          for (int i=0; i < aclObjects.size(); i++) {
333
            // docid of the current object
334
            String docid = (String)aclObjects.elementAt(i);
335
            DocumentIdentifier docID = new DocumentIdentifier(docid);
336
            docid = docID.getIdentifier();
337
            insertPermissions(docid,leavingTagName);
338
          }
339 968 tao
340
          //should insert permission for aclid itself into database
341
          DocumentIdentifier aclIdItself = new DocumentIdentifier(aclid);
342
          String aclIdString = aclIdItself.getIdentifier();
343
          insertPermissions(aclIdString,leavingTagName);
344
345 802 bojilova
346 570 bojilova
        } catch (SQLException sqle) {
347
          throw new SAXException(sqle);
348 802 bojilova
        } catch (Exception e) {
349
          throw new SAXException(e);
350 570 bojilova
        }
351
      }
352
353 688 bojilova
      // reset the allow/deny permission
354 660 bojilova
      principal = new Vector();
355 555 bojilova
      permission = 0;
356 570 bojilova
      beginTime = null;
357
      endTime = null;
358
      ticketCount = 0;
359 555 bojilova
360 570 bojilova
    }
361 555 bojilova
362
  }
363 598 bojilova
364 688 bojilova
  /**
365
    * SAX Handler that receives notification of DOCTYPE. Sets the DTD.
366
    * @param name name of the DTD
367
    * @param publicId Public Identifier of the DTD
368
    * @param systemId System Identifier of the DTD
369
    */
370 598 bojilova
  public void startDTD(String name, String publicId, String systemId)
371
              throws SAXException {
372
    docname = name;
373
    doctype = publicId;
374
    systemid = systemId;
375
  }
376
377
  /**
378 688 bojilova
   * SAX Handler that receives notification of the start of entities.
379
   * @param name name of the entity
380 598 bojilova
   */
381
  public void startEntity(String name) throws SAXException {
382
    if (name.equals("[dtd]")) {
383
      processingDTD = true;
384
    }
385
  }
386
387
  /**
388 688 bojilova
   * SAX Handler that receives notification of the end of entities.
389
   * @param name name of the entity
390 598 bojilova
   */
391
  public void endEntity(String name) throws SAXException {
392
    if (name.equals("[dtd]")) {
393
      processingDTD = false;
394
    }
395
  }
396
397
  /**
398 688 bojilova
   * Get the document name.
399 598 bojilova
   */
400
  public String getDocname() {
401
    return docname;
402
  }
403
404
  /**
405 688 bojilova
   * Get the document processing state.
406 598 bojilova
   */
407
  public boolean processingDTD() {
408
    return processingDTD;
409
  }
410
411 802 bojilova
  /* Get all objects associated with @aclid from db.*/
412
  private Vector getACLObjects(String aclid)
413 638 bojilova
          throws SQLException
414
  {
415 802 bojilova
    Vector aclObjects = new Vector();
416 1214 tao
    DBConnection conn = null;
417
    int serialNumber = -1;
418
    PreparedStatement pstmt = null;
419
    try
420
    {
421
      //get connection from DBConnectionPool
422
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACLObject");
423
      serialNumber=conn.getCheckOutSerialNumber();
424
425
      // delete all acl records for resources related to @aclid if any
426
      pstmt = conn.prepareStatement(
427 802 bojilova
                             "SELECT object FROM xml_relation " +
428 830 jones
                             "WHERE subject = ? ");
429 1214 tao
      pstmt.setString(1,aclid);
430
      pstmt.execute();
431
      ResultSet rs = pstmt.getResultSet();
432
      boolean hasRows = rs.next();
433
      while (hasRows) {
434
        aclObjects.addElement(rs.getString(1));
435
        hasRows = rs.next();
436
      }//whil
437 802 bojilova
    }
438 1214 tao
    catch (SQLException e)
439
    {
440
      throw e;
441
    }
442
    finally
443
    {
444
      try
445
      {
446
        pstmt.close();
447
      }
448
      finally
449
      {
450
        //retrun DBConnection
451
        DBConnectionPool.returnDBConnection(conn,serialNumber);
452
      }
453
    }
454 802 bojilova
455
    return aclObjects;
456 638 bojilova
  }
457
458 802 bojilova
  /* Delete from db all permission for resources related to @aclid if any.*/
459
  private void deletePermissionsForRelatedResources(String aclid)
460 638 bojilova
          throws SQLException
461
  {
462 1214 tao
    //DBConnection conn = null;
463
    //int serialNumber = -1;
464
    Statement stmt = null;
465
    try
466
    {
467
      //check out DBConenction
468
      //conn=DBConnectionPool.getDBConnection("AccessControlList.deltePerm");
469
      //serialNumber=conn.getCheckOutSerialNumber();
470
      // delete all acl records for resources related to @aclid if any
471
      stmt = connection.createStatement();
472
      // Increase DBConnection usage count
473
      connection.increaseUsageCount(1);
474
      stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + aclid
475
                                                                      + "'");
476
      //increase usageCount!!!!!!
477
      //conn.increaseUsageCount(1);
478
    }
479
    catch (SQLException e)
480
    {
481
      throw e;
482
    }
483
    finally
484
    {
485
      stmt.close();
486
      //retrun DBConnection
487
      //DBConnectionPool.returnDBConnection(conn,serialNumber);
488
    }
489 645 bojilova
  }
490
491 1214 tao
  /* Insert into db calculated permission for the list of principals
492
   * The DBConnection it is use is class field. Because we want to keep rollback
493
   * features and it need use same connection
494
  */
495
496 802 bojilova
  private void insertPermissions(String docid, String permType )
497 1214 tao
                                            throws SQLException
498 555 bojilova
  {
499 1214 tao
    PreparedStatement pstmt = null;
500
    //DBConnection conn = null;
501
    //int serialNumber = -1;
502 555 bojilova
    try {
503 1214 tao
      //Check out DBConnection
504
      //conn=DBConnectionPool.getDBConnection("AccessControlList.insertPerm");
505
      //serialNumber=conn.getCheckOutSerialNumber();
506
507
      pstmt = connection.prepareStatement(
508 555 bojilova
              "INSERT INTO xml_access " +
509 645 bojilova
              "(docid, principal_name, permission, perm_type, perm_order," +
510
              "begin_time,end_time,ticket_count, accessfileid) VALUES " +
511
              "(?,?,?,?,?,to_date(?,'mm/dd/yy'),to_date(?,'mm/dd/yy'),?,?)");
512 1214 tao
      // Increase DBConnection usage count
513
      connection.increaseUsageCount(1);
514 555 bojilova
      // Bind the values to the query
515 802 bojilova
      pstmt.setString(1, docid);
516 570 bojilova
      pstmt.setInt(3, permission);
517
      pstmt.setString(4, permType);
518
      pstmt.setString(5, permOrder);
519
      pstmt.setString(6, beginTime);
520
      pstmt.setString(7, endTime);
521 645 bojilova
      pstmt.setString(9, aclid);
522 570 bojilova
      if ( ticketCount > 0 ) {
523
        pstmt.setString(8, "" + ticketCount);
524
      } else {
525 899 berkley
        pstmt.setString(8, null);
526 570 bojilova
      }
527 1214 tao
528
      //incrase usagecount for DBConnection
529
      //conn.increaseUsageCount(1);
530 688 bojilova
      String prName;
531 802 bojilova
      for ( int j = 0; j < principal.size(); j++ ) {
532
        prName = (String)principal.elementAt(j);
533
        pstmt.setString(2, prName);
534
        pstmt.execute();
535
      /*
536
        // check if there are conflict with permission's order
537
        String permOrderOpos = permOrder;
538
        int perm = getPermissions(permission, prName, docid, permOrder);
539
        if (  perm != 0 ) {
540
          if ( permOrder.equals("allowFirst") ) {
541
            permOrderOpos = "denyFirst";
542
          } else if ( permOrder.equals("denyFirst") ) {
543
            permOrderOpos = "allowFirst";
544 688 bojilova
          }
545 802 bojilova
          throw new SQLException("Permission(s) " + txtValue(perm) +
546
                    " for \"" + prName + "\" on document #" + docid +
547
                    " has/have been used with \"" + permOrderOpos + "\"");
548 665 bojilova
        }
549 802 bojilova
      */
550 570 bojilova
      }
551 672 bojilova
      pstmt.close();
552 555 bojilova
553 570 bojilova
    } catch (SQLException e) {
554
      throw new
555
      SQLException("AccessControlList.insertPermissions(): " + e.getMessage());
556 672 bojilova
    }
557 1214 tao
    finally
558
    {
559
      pstmt.close();
560
      //return the DBConnection
561
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
562
    }
563 672 bojilova
  }
564
565 688 bojilova
  /* Get permissions with permission order different than @permOrder. */
566
  private int getPermissions(int permission, String principal,
567
                             String docid, String permOrder)
568
          throws SQLException
569
  {
570 1214 tao
    PreparedStatement pstmt = null;
571
    DBConnection conn = null;
572
    int serialNumber = -1;
573
    try
574
    {
575
      //check out DBConnection
576
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPermissions");
577
      serialNumber=conn.getCheckOutSerialNumber();
578
      pstmt = conn.prepareStatement(
579 688 bojilova
            "SELECT permission FROM xml_access " +
580 765 bojilova
            "WHERE docid = ? " +
581
            "AND principal_name = ? " +
582
            "AND perm_order NOT = ?");
583 1214 tao
      pstmt.setString(1, docid);
584
      pstmt.setString(2, principal);
585
      pstmt.setString(3, permOrder);
586
      pstmt.execute();
587
      ResultSet rs = pstmt.getResultSet();
588
      boolean hasRow = rs.next();
589
      int perm = 0;
590
      while ( hasRow ) {
591
        perm = rs.getInt(1);
592
        perm = permission & perm;
593
        if ( perm != 0 ) {
594
          pstmt.close();
595
          return perm;
596
        }
597
        hasRow = rs.next();
598
      }
599
    }//try
600
    catch (SQLException e)
601
    {
602
      throw e;
603
    }
604
    finally
605
    {
606
      try
607
      {
608 1139 tao
        pstmt.close();
609 688 bojilova
      }
610 1214 tao
      finally
611
      {
612
        DBConnectionPool.returnDBConnection(conn, serialNumber);
613
      }
614 688 bojilova
    }
615
    return 0;
616
  }
617
618
  /* Get the int value of READ, WRITE or ALL. */
619 1214 tao
  private static int intValue ( String permission )
620 688 bojilova
  {
621
    if ( permission.equals("READ") ) {
622
      return READ;
623
    } else if ( permission.equals("WRITE") ) {
624
      return WRITE;
625
    } else if ( permission.equals("ALL") ) {
626
      return ALL;
627
    }
628
629
    return -1;
630
  }
631
632
  /* Get the text value of READ, WRITE or ALL. */
633
  private String txtValue ( int permission )
634
  {
635
    StringBuffer txtPerm = new StringBuffer("\"");
636
    if ( (permission & READ) != 0 ) {
637
      txtPerm.append("read");
638
    }
639
    if ( (permission & WRITE) != 0 ) {
640
      if ( txtPerm.length() > 0 ) txtPerm.append(",");
641
      txtPerm.append("write");
642
    }
643
    if ( (permission & ALL) != 0 ) {
644
      if ( txtPerm.length() > 0 ) txtPerm.append(",");
645
      txtPerm.append("all");
646
    }
647
648
    return txtPerm.append("\"").toString();
649
  }
650
651 951 tao
652 802 bojilova
  /**
653 951 tao
    * Check if a document id is a access document. Access document need user
654
    * has "all" permission to access it.
655
    * @param docId, the document id need to be checked
656
    */
657 1214 tao
    private static boolean isAccessDocument(String docId) throws SQLException
658 951 tao
    {
659
      //detele the rev number if docid contains it
660
      docId=MetaCatUtil.getDocIdFromString(docId);
661
      PreparedStatement pStmt=null;
662 1214 tao
      DBConnection conn = null;
663
      int serialNumber = -1;
664 951 tao
      try
665
      {
666 1214 tao
        //check out DBConnection
667
        conn=DBConnectionPool.getDBConnection("AccessControlList.isAccessDoc");
668
        serialNumber=conn.getCheckOutSerialNumber();
669 951 tao
        pStmt = conn.prepareStatement("select 'x' from xml_access where " +
670
                                      "accessfileid like '" + docId +  "'");
671
        pStmt.execute();
672
        ResultSet rs = pStmt.getResultSet();
673
        boolean hasRow = rs.next();
674
        pStmt.close();
675
        if(hasRow)
676
        {
677
          return true;
678
        }
679
      }
680
      catch(SQLException e)
681
      {
682 1214 tao
683
        throw new SQLException("AccessControlList.isAccessDocument " +
684
                     "Error checking" +
685
                     " on document " + docId + ". " + e.getMessage());
686 951 tao
      }
687 1214 tao
      finally
688
      {
689
        try
690
        {
691
           pStmt.close();
692
        }
693
        finally
694
        {
695
          DBConnectionPool.returnDBConnection(conn, serialNumber);
696
        }
697
      }
698 951 tao
      return false;
699
    }//isAccessDocument
700
701
  /**
702
    * To create a part of query: "docid like '" +str1+ "', " +"docid like '"
703
    * +str2+"'" ... We need to check user, group and public together for the
704
    * permission. So we need the principal in an array and according the array
705
    * to create a part of query which will be used in other methods
706
    * @param principals, a string array storing the username, groups name and
707
    * public.
708
    */
709
   private String partQueryAboutDocId( String [] principals)
710
   {
711
     String partQuery="";
712
     int lengthOfArray=principals.length;
713
714
     for (int i=0;i<(lengthOfArray-1);i++)
715
     {
716
        partQuery=partQuery+"docid like '"+principals[i]+"',";
717
     }
718
719
     //the last one dosen't has "'"
720
     partQuery=partQuery+"docid like '"+principals[(lengthOfArray-1)]+"'";
721
     return partQuery;
722
723
   }
724
725
  /**
726
    * Check if a stirng array contains a given documents' owner
727
    * @param principals, a string array storing the username, groups name and
728
    * public.
729
    * @param docid, the id of given documents
730
    */
731 1214 tao
  private static boolean containDocumentOwner( String [] principals,
732
                                                              String docId)
733 951 tao
                    throws SQLException
734
  {
735
    int lengthOfArray=principals.length;
736
    boolean hasRow;
737
    PreparedStatement pStmt=null;
738 1214 tao
    DBConnection conn = null;
739
    int serialNumber = -1;
740
741 951 tao
    try
742
    {
743 1214 tao
      //check out DBConnection
744
     conn=DBConnectionPool.getDBConnection("AccessControlList.containDocOnwer");
745
      serialNumber=conn.getCheckOutSerialNumber();
746 951 tao
      pStmt = conn.prepareStatement(
747
                "SELECT 'x' FROM xml_documents " +
748
                "WHERE docid = ? AND user_owner = ?");
749
      //check every element in the string array too see if it conatains
750
      //the owner of document
751
      for (int i=0; i<lengthOfArray; i++)
752
      {
753
754
        // Bind the values to the query
755
        pStmt.setString(1, docId);
756
        pStmt.setString(2, principals[i]);
757
758
        pStmt.execute();
759
        ResultSet rs = pStmt.getResultSet();
760
        hasRow = rs.next();
761
        if (hasRow)
762
        {
763
          pStmt.close();
764
          return true;
765
        }//if
766
767
      }//for
768
    }//try
769
    catch (SQLException e)
770
    {
771
        pStmt.close();
772
773
        throw new
774
        SQLException("AccessControlList.hasPermission(). " +
775
                     "Error checking ownership for " + principals[0] +
776
                     " on document #" + docId + ". " + e.getMessage());
777
    }//catch
778 1214 tao
    finally
779
    {
780
      try
781
      {
782
        pStmt.close();
783
      }
784
      finally
785
      {
786
        DBConnectionPool.returnDBConnection(conn, serialNumber);
787
      }
788
    }
789 951 tao
    return false;
790
  }//containDocumentOwner
791
792
  /**
793
    * Check if the permission order for user at that documents is allowFirst
794
    * @param principals, list of names of principals to check for
795
    * @param docid, document identifier to check for
796
    */
797 1214 tao
  private static boolean isAllowFirst(String [] principals, String docId)
798 951 tao
                  throws SQLException, Exception
799
  {
800
    int lengthOfArray=principals.length;
801
    boolean hasRow;
802 1214 tao
    PreparedStatement pStmt = null;
803
    DBConnection conn = null;
804
    int serialNumber = -1;
805
    try
806
    {
807
      //check out DBConnection
808
      conn=DBConnectionPool.getDBConnection("AccessControlList.isAllowFirst");
809
      serialNumber=conn.getCheckOutSerialNumber();
810 951 tao
811 1214 tao
      //select permission order from database
812
      pStmt = conn.prepareStatement(
813 951 tao
                "SELECT perm_order FROM xml_access " +
814
                "WHERE principal_name= ? AND docid = ?");
815
816 1214 tao
      //check every name in the array
817
      for (int i=0; i<lengthOfArray;i++)
818
      {
819
        //bind value
820
        pStmt.setString(1, principals[i]);//user name
821
        pStmt.setString(2, docId);//docid
822
823
        pStmt.execute();
824
        ResultSet rs = pStmt.getResultSet();
825
        hasRow=rs.next();
826
        if (hasRow)
827
        {
828
          //get the permission order from data base
829
          String permissionOrder=rs.getString(1);
830
          //if the permission order is "allowFirst
831
          if (permissionOrder.equalsIgnoreCase(ALLOWFIRST))
832
          {
833
            pStmt.close();
834
            return true;
835
          }
836
          else
837
          {
838
            pStmt.close();
839
            return false;
840
          }
841
        }//if
842
      }//for
843
    }//try
844
    catch (SQLException e)
845 1139 tao
    {
846 1214 tao
      throw e;
847
    }
848
    finally
849
    {
850
      try
851 1123 tao
      {
852 1214 tao
        pStmt.close();
853
      }
854
      finally
855
      {
856
        DBConnectionPool.returnDBConnection(conn, serialNumber);
857
      }
858
    }
859 951 tao
860
    //if reach here, means there is no permssion record for given names and
861
    //docid. So throw a exception.
862 1214 tao
863 951 tao
    throw new Exception("There is no permission record for user"+principals[0]+
864
                        "at document "+docId);
865
866
  }//isAllowFirst
867
868
  /**
869
    * Check if the users array has allow rules for given users, docid and
870
    * permission.
871
    * If it has permission rule and ticket count is greater than 0, the ticket
872 952 tao
    * number will decrease one for every allow rule
873 951 tao
    * @param principals, list of names of principals to check for
874
    * @param docid, document identifier to check for
875
    * @param permission, the permssion need to check
876
    */
877 1214 tao
  private static boolean hasAllowRule(String [] principals, String docId,
878 951 tao
                                  String permission)
879
                  throws SQLException, Exception
880
 {
881
   int lengthOfArray=principals.length;
882 952 tao
   boolean allow=false;//initial value is no allow rule
883 951 tao
   ResultSet rs;
884 1214 tao
   PreparedStatement pStmt = null;
885 951 tao
   int permissionValue=intValue(permission);
886
   int permissionValueInTable;
887
   int ticketCount;
888 1214 tao
   DBConnection conn = null;
889
   int serialNumber = -1;
890
   try
891
   {
892
     //check out DBConnection
893
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasAllowRule");
894
     serialNumber=conn.getCheckOutSerialNumber();
895
    //This sql statement will select entry with
896
    //begin_time<=currentTime<=end_time in xml_access table
897
    //If begin_time or end_time is null in table, isnull(begin_time, sysdate)
898
    //function will assign begin_time=sysdate
899
    pStmt = conn.prepareStatement(
900 951 tao
                "SELECT permission, ticket_count " +
901
                "FROM xml_access " +
902
                "WHERE docid = ? " +
903
                "AND principal_name = ? " +
904
                "AND perm_type = ? " +
905
                "AND " + sysdate +
906
                " BETWEEN " + isnull + "(begin_time," + sysdate + ") " +
907
                     "AND " + isnull + "(end_time," + sysdate + ")");
908 1214 tao
    //bind docid, perm_type
909
    pStmt.setString(1, docId);
910
    pStmt.setString(3, ALLOW);
911 951 tao
912 1214 tao
    //bind every elenment in user name array
913 951 tao
    for (int i=0;i<lengthOfArray; i++)
914
    {
915
      pStmt.setString(2, principals[i]);
916
      pStmt.execute();
917
      rs=pStmt.getResultSet();
918
      while (rs.next())//check every entry for one user
919
      {
920
        permissionValueInTable=rs.getInt(1);
921
        ticketCount=rs.getInt(2);
922
923
        //permission is ok and ticketcount geat than 0 or ticket is null,
924
        //the user have a permission to access the file
925
        if ((( permissionValueInTable & permissionValue )== permissionValue )
926
              && (rs.wasNull()||ticketCount > 0))
927
        {
928
           //ticket count should minus one
929
           //ticketCount isnot null and greater than 0, order is allowfirst
930
           if (!rs.wasNull() && ticketCount>0 && isAllowFirst(principals,docId))
931
           {
932
              decreaseNumberOfAccess(permissionValueInTable, principals[i],
933
                                              docId, ALLOW, ALLOWFIRST);
934
            }
935 952 tao
           //ticketCount isnot null and greater than 0, order is not allowfirst
936
           if (!rs.wasNull() &&ticketCount>0 && !isAllowFirst(principals,docId))
937
           {
938
              decreaseNumberOfAccess(permissionValueInTable, principals[i],
939
                                              docId, ALLOW, DENYFIRST);
940
           }
941
942
           allow=true;//has allow rule entry
943
         }//if
944
      }//while
945
    }//for
946 1214 tao
   }//try
947
   catch (SQLException sqlE)
948
   {
949
     throw sqlE;
950
   }
951
   catch (Exception e)
952
   {
953
     throw e;
954
   }
955
   finally
956
   {
957
     try
958
     {
959
       pStmt.close();
960
     }
961
     finally
962
     {
963
       DBConnectionPool.returnDBConnection(conn, serialNumber);
964
     }
965
   }
966 952 tao
    return allow;
967
 }//hasAllowRule
968
969 1214 tao
970 952 tao
971 951 tao
   /**
972
    * Check if the users array has explicit deny rules for given users, docid
973
    * and permission. That means the perm_type is deny and current time is
974
    * less than end_time and greater than begin time, or no time limit.
975
    * @param principals, list of names of principals to check for
976
    * @param docid, document identifier to check for
977
    * @param permission, the permssion need to check
978
    */
979 1214 tao
  private static boolean hasExplicitDenyRule(String [] principals, String docId,
980 951 tao
                                  String permission)
981
                  throws SQLException
982
 {
983
   int lengthOfArray=principals.length;
984
   ResultSet rs;
985 1214 tao
   PreparedStatement pStmt = null;
986 951 tao
   int permissionValue=intValue(permission);
987
   int permissionValueInTable;
988 1214 tao
   DBConnection conn = null;
989
   int serialNumber = -1;
990 951 tao
991 1214 tao
   try
992
   {
993
     //check out DBConnection
994
     conn=DBConnectionPool.getDBConnection("AccessControlList.hasExplicitDeny");
995
     serialNumber=conn.getCheckOutSerialNumber();
996
997
    //This sql statement will select entry with
998
    //begin_time<=currentTime<=end_time in xml_access table
999
    //If begin_time or end_time is null in table, isnull(begin_time, sysdate)
1000
    //function will assign begin_time=sysdate
1001
    pStmt = conn.prepareStatement(
1002 951 tao
                "SELECT permission " +
1003
                "FROM xml_access " +
1004
                "WHERE docid = ? " +
1005
                "AND principal_name = ? " +
1006
                "AND perm_type = ? " +
1007
                "AND " + sysdate +
1008
                " BETWEEN " + isnull + "(begin_time," + sysdate + ") " +
1009
                     "AND " + isnull + "(end_time," + sysdate + ")");
1010 1214 tao
    //bind docid, perm_type
1011
    pStmt.setString(1, docId);
1012
    pStmt.setString(3, DENY);
1013 951 tao
1014 1214 tao
    //bind every elenment in user name array
1015 951 tao
    for (int i=0;i<lengthOfArray; i++)
1016
    {
1017
      pStmt.setString(2, principals[i]);
1018
      pStmt.execute();
1019
      rs=pStmt.getResultSet();
1020
      while (rs.next())//check every entry for one user
1021
      {
1022
        permissionValueInTable=rs.getInt(1);
1023
1024
        //permission is ok the user doesn't have permission to access the file
1025
        if (( permissionValueInTable & permissionValue )== permissionValue )
1026
1027
        {
1028
           pStmt.close();
1029
           return true;
1030
         }//if
1031
      }//while
1032
    }//for
1033 1214 tao
   }//try
1034
   catch (SQLException e)
1035
   {
1036
     throw e;
1037
   }//catch
1038
   finally
1039
   {
1040
     try
1041
     {
1042
       pStmt.close();
1043
     }
1044
     finally
1045
     {
1046
       DBConnectionPool.returnDBConnection(conn, serialNumber);
1047
     }
1048
   }//finally
1049
   return false;//no deny rule
1050 951 tao
  }//hasExplicitDenyRule
1051
1052
   /**
1053
    * Check if the users array has implicit deny rules for given users, docid
1054
    * and permission. That means the though perm_type is "allow" but current
1055
    * time is less than begin_time or greater than end time, or ticket count
1056
    * is 0.
1057
    * @param principals, list of names of principals to check for
1058
    * @param docid, document identifier to check for
1059
    * @param permission, the permssion need to check
1060
    */
1061 1214 tao
  private static boolean hasImplicitDenyRule(String [] principals, String docId,
1062 951 tao
                                  String permission)
1063
                  throws SQLException
1064
 {
1065
   int lengthOfArray=principals.length;
1066
   ResultSet rs;
1067 1214 tao
   PreparedStatement pStmt = null;
1068 951 tao
   int permissionValue=intValue(permission);
1069
   int permissionValueInTable;
1070 1214 tao
   DBConnection conn = null;
1071
   int serialNumber = -1;
1072
1073 1139 tao
1074 1214 tao
   try
1075
   {
1076
    //check out DBConnection
1077
    conn=DBConnectionPool.getDBConnection("AccessControlList.hasImplicitDeny");
1078
    serialNumber=conn.getCheckOutSerialNumber();
1079
    //This sql statement will select entry with  perm_type =allow and
1080
    //currentTime is less than begin_time or greater than end time
1081
    //in xml_access table. This is an implicit deny rule (allow is out of date)
1082
    pStmt = conn.prepareStatement(
1083 951 tao
                "SELECT permission " +
1084
                "FROM xml_access " +
1085
                "WHERE docid = ? " +
1086
                "AND principal_name = ? " +
1087
                "AND perm_type = ? " +
1088
                "AND " + sysdate +
1089
                " < " + isnull + "(begin_time," + sysdate + ") " +
1090
                "OR " + sysdate + " > "+ isnull + "(end_time," + sysdate + ")");
1091 1214 tao
    //bind docid, perm_type
1092
    pStmt.setString(1, docId);
1093
    pStmt.setString(3, ALLOW);//It is allow
1094 951 tao
1095 1214 tao
    //bind every elenment in user name array
1096 951 tao
    for (int i=0;i<lengthOfArray; i++)
1097
    {
1098
      pStmt.setString(2, principals[i]);
1099
      pStmt.execute();
1100
      rs=pStmt.getResultSet();
1101
      while (rs.next())//check every entry for one user
1102
      {
1103
        permissionValueInTable=rs.getInt(1);
1104
1105
        //permission is ok the user doesn't have permission to access the file
1106
        if (( permissionValueInTable & permissionValue )== permissionValue )
1107
1108
        {
1109
           pStmt.close();
1110
           //has a implicit deny rule: allow is out of date
1111
           return true;
1112
         }//if
1113
      }//while
1114
    }//for
1115
    pStmt.close();
1116
1117
    //Now, there is no implicit deny rule which is allow is out of date
1118
    //another implicit deny rule need to be check: allow is out of ticketCount
1119
    //ticketCount=0
1120
    pStmt = conn.prepareStatement(
1121
                "SELECT permission " +
1122
                "FROM xml_access " +
1123
                "WHERE docid = ? " +
1124
                "AND principal_name = ? " +
1125
                "AND perm_type = ? " +
1126
                "AND ticket_count = ?");
1127 1214 tao
    //bind docid, perm_type, ticket_count
1128
    pStmt.setString(1, docId);
1129
    pStmt.setString(3, ALLOW);//It is allow!
1130
    pStmt.setInt(4,0);
1131
1132
    //Because this DBConnection used twice in this method. But we only count one
1133
    //when it checked out. So we should increase another one
1134
    conn.increaseUsageCount(1);
1135
1136
    //bind every elenment in user name array
1137 951 tao
    for (int i=0;i<lengthOfArray; i++)
1138
    {
1139
      pStmt.setString(2, principals[i]);
1140
      pStmt.execute();
1141
      rs=pStmt.getResultSet();
1142
      while (rs.next())//check every entry for one user
1143
      {
1144
        permissionValueInTable=rs.getInt(1);
1145
1146
        //permission is ok the user doesn't have permission to access the file
1147
        if (( permissionValueInTable & permissionValue )== permissionValue )
1148
1149
        {
1150
1151
           pStmt.close();
1152
           //has a implicit deny rule: allow is out of ticketCount
1153
           return true;
1154
         }//if
1155
      }//while
1156
    }//for
1157 1214 tao
   }//try
1158
   finally
1159
   {
1160
1161
     try
1162
     {
1163
       pStmt.close();
1164
     }
1165
     finally
1166
     {
1167
       DBConnectionPool.returnDBConnection(conn, serialNumber);
1168
     }
1169
   }//finally
1170 951 tao
    return false;//no implicit deny rule
1171
  }//hasImplicitDenyRule
1172
1173
  /**
1174
    * Creat a users pakages to check permssion rule, user itself, public and
1175
    * the gourps the user belong will be include in this package
1176
    * @param user, the name of user
1177
    * @param groups, the string array of the groups that user belong to
1178
    */
1179 1214 tao
  private static String [] createUsersPackage(String user, String [] groups)
1180 951 tao
  {
1181
    String [] usersPackage=null;
1182
    int lengthOfPackage;
1183
1184
    if (groups!=null)
1185
    {
1186
      //if gouprs is not null and user is not public, we should create a array
1187
      //to store the groups and user and public.
1188
      //So the length of userPackage is the length of group plus two
1189 966 tao
      if (!user.equalsIgnoreCase(PUBLIC))
1190 951 tao
      {
1191
        lengthOfPackage=(groups.length)+2;
1192
        usersPackage=new String [lengthOfPackage];
1193
        //the first two elements is user self and public
1194
        usersPackage[0]=user;
1195
        usersPackage[1]=PUBLIC;
1196
        //put groups element from index 0 to lengthOfPackage-3 into userPackage
1197
        //from index 2 to lengthOfPackage-1
1198
        for (int i=2; i<lengthOfPackage; i++)
1199
        {
1200
          usersPackage[i]=groups[i-2];
1201
        } //for
1202
      }//if user!=public
1203
      else//use=public
1204
      {
1205
        lengthOfPackage=(groups.length)+1;
1206
        usersPackage=new String [lengthOfPackage];
1207
        //the first lements is public
1208
        usersPackage[0]=PUBLIC;
1209
        //put groups element from index 0 to lengthOfPackage-2 into userPackage
1210
        //from index 1 to lengthOfPackage-1
1211
        for (int i=1; i<lengthOfPackage; i++)
1212
        {
1213
          usersPackage[i]=groups[i-1];
1214
        } //for
1215
      }//else user=public
1216
1217
    }//if groups!=null
1218
    else
1219
    {
1220
      //because no groups, the userPackage only need two elements
1221
      //one is for user, the other is for public
1222 966 tao
      if (!user.equalsIgnoreCase(PUBLIC))
1223 951 tao
      {
1224
        lengthOfPackage=2;
1225
        usersPackage=new String [lengthOfPackage];
1226
        usersPackage[0]=user;
1227
        usersPackage[1]=PUBLIC;
1228
      }//if user!=public
1229
      else //user==public
1230
      {
1231
        //only put public into array
1232
        lengthOfPackage=1;
1233
        usersPackage=new String [lengthOfPackage];
1234
        usersPackage[0]=PUBLIC;
1235
      }
1236
    }//else groups==null
1237
    return usersPackage;
1238
  }//createUsersPackage
1239 959 tao
1240 951 tao
  /**
1241 959 tao
    * This method will return a data set id for given access id.
1242
    * @param accessDocId, the accessDocId which need to be found data set id
1243
   */
1244 1214 tao
  private static String getDataSetId(String accessDocId)
1245 961 tao
                              throws SQLException
1246 959 tao
  {
1247
    String dataSetId=null;
1248 1214 tao
    PreparedStatement pStmt=null;
1249 959 tao
    ResultSet rs=null;
1250 1214 tao
    DBConnection conn=null;
1251
    int serialNumber=-1;
1252 959 tao
    String query="SELECT docId from xml_relation where subject = ? or "
1253
                                                +"object = ?";
1254
1255 1214 tao
    try
1256 959 tao
    {
1257 1214 tao
      //check out DBConnection
1258
      conn=DBConnectionPool.getDBConnection("AccessControlList.getDataSetId");
1259
      serialNumber=conn.getCheckOutSerialNumber();
1260
1261
      pStmt=conn.prepareStatement(query);
1262
      //bind the value to query
1263
      pStmt.setString(1, accessDocId);
1264
      pStmt.setString(2, accessDocId);
1265
      //execute the query
1266
      pStmt.execute();
1267
      rs=pStmt.getResultSet();
1268
      //process the result
1269
      if (rs.next()) //There are some records for the data set id for access id
1270
      {
1271
        dataSetId=rs.getString(1);
1272
      }
1273
      else //No data set id for the given access id in xml_relation table
1274
      {
1275
        dataSetId=null;
1276
      }
1277
    }//try
1278
    finally
1279 959 tao
    {
1280 1214 tao
      try
1281
      {
1282
        pStmt.close();
1283
      }
1284
      finally
1285
      {
1286
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1287
      }
1288 959 tao
    }
1289
    return dataSetId;
1290
  }//getDataPackageId()
1291
1292
  /**
1293 802 bojilova
    * Check from db connection if at least one of the list of @principals
1294
    * has @permission on @docid.
1295
    * @param permission permission type to check for
1296
    * @param principals list of names of principals to check for @permission
1297
    * @param docid document identifier to check on
1298
    */
1299 1214 tao
  public static boolean hasPermission(String permission, String user,
1300 951 tao
                               String[] groups, String docId )
1301 959 tao
                 throws SQLException, Exception
1302 688 bojilova
  {
1303 951 tao
    //detele the rev number if docid contains it
1304
    docId=MetaCatUtil.getDocIdFromString(docId);
1305
    boolean hasPermission=false;
1306
    String [] userPackage=null;
1307 975 tao
    //for the commnad line invocation
1308
    if ((user==null) && (groups==null || groups.length==0))
1309
    {
1310
      return true;
1311
    }
1312 959 tao
1313 951 tao
    //create a userpackage including user, public and group member
1314
    userPackage=createUsersPackage(user, groups);
1315
1316 966 tao
    //if the requested document is access documents and requested permission
1317
    //is "write", the user should have "all" right
1318
    if (isAccessDocument(docId) && (intValue(permission)==WRITE))
1319 951 tao
    {
1320 966 tao
      hasPermission = hasPermission(userPackage,docId, "ALL");
1321 951 tao
    }//if
1322 966 tao
    else //in other situation, just check the request permission
1323 951 tao
    {
1324
1325
      // Check for @permission on @docid for @user and/or @groups
1326
      hasPermission = hasPermission(userPackage,docId, permission);
1327
1328
    }//else
1329
1330 802 bojilova
    return hasPermission;
1331
  }
1332 951 tao
1333 688 bojilova
  /**
1334 951 tao
    * Check from db connection if the users in String array @principals has
1335
    * @permission on @docid*
1336
    * @param principals, names in userPakcage need to check for @permission
1337
    * @param docid, document identifier to check on
1338
    * @param permission, permission (write or all...) to check for
1339 688 bojilova
    */
1340 1214 tao
  private static boolean hasPermission(String [] principals, String docId,
1341 951 tao
                                            String permission)
1342
                         throws SQLException
1343 570 bojilova
  {
1344 951 tao
    try
1345
    {
1346
      //first, if there is a docid owner in user package, return true
1347
      //because doc owner has all permssion
1348
      if (containDocumentOwner(principals, docId))
1349
      {
1350
1351 570 bojilova
          return true;
1352
      }
1353 869 berkley
1354 951 tao
      //If there is no owner in user package, checking the table
1355
      //check perm_order
1356
      if (isAllowFirst(principals, docId))
1357
      {
1358
1359
        if (hasExplicitDenyRule(principals, docId, permission)||
1360
                            hasImplicitDenyRule(principals, docId, permission))
1361
        {
1362
          //if it is allowfirst and has deny rule(either explicit or implicit)
1363
          //deny access
1364
          return false;
1365
        }//if
1366
        else if ( hasAllowRule(principals, docId, permission))
1367
        {
1368
          //if it is allowfirst and hasn't deny rule and has allow rule
1369
          //allow access
1370
          return true;
1371
        }//else if
1372
        else
1373
        {
1374
          //other situation deny access
1375
          return false;
1376
        }//else
1377
     }//if isAllowFirst
1378
     else //denyFirst
1379
     {
1380
       if (hasAllowRule(principals, docId, permission))
1381
       {
1382
         //if it is denyFirst and has allow rule, allow access
1383
         return true;
1384
       }
1385
       else
1386
       {
1387
         //if it is denyfirst but no allow rule, deny access
1388
         return false;
1389
       }
1390
     }//else denyfirst
1391
    }//try
1392
    catch (Exception e)
1393
    {
1394
      MetaCatUtil.debugMessage("There is a exception in hasPermission method: "
1395 1096 tao
                         +e.getMessage(), 50);
1396 951 tao
    }
1397 966 tao
1398 951 tao
    return false;
1399
  }//hasPermission
1400
1401 1214 tao
1402 802 bojilova
  /* Decrease the number of access to @docid for @principal in db. */
1403 1214 tao
  private static void decreaseNumberOfAccess(int permission, String principal,
1404 802 bojilova
                                      String docid, String permType,
1405 688 bojilova
                                      String permOrder)
1406 570 bojilova
               throws SQLException
1407
  {
1408 1214 tao
    PreparedStatement pstmt = null;
1409
    DBConnection conn = null;
1410
    int serialNumber = -1;
1411
    try
1412
    {
1413
      //check out DBConnection
1414
      conn=DBConnectionPool.getDBConnection("AccessControlList.decreaseNumOfA");
1415
      serialNumber=conn.getCheckOutSerialNumber();
1416
1417
      pstmt = conn.prepareStatement(
1418 570 bojilova
            "UPDATE xml_access SET ticket_count = ticket_count - 1 " +
1419 765 bojilova
            "WHERE docid = ? " +
1420
            "AND principal_name = ? " +
1421
            "AND permission = ? " +
1422
            "AND perm_type = ? " +
1423
            "AND perm_order = ? " +
1424 774 bojilova
            "AND " + sysdate +
1425
            " BETWEEN " + isnull + "(begin_time," + sysdate + ") " +
1426
                 "AND " + isnull + "(end_time," + sysdate + ")");
1427 1214 tao
      // Bind the values to the query
1428
      pstmt.setString(1, docid);
1429
      pstmt.setString(2, principal);
1430
      pstmt.setInt(3, permission);
1431
      pstmt.setString(4, permType);
1432
      pstmt.setString(5, permOrder);
1433 570 bojilova
1434 1214 tao
      pstmt.execute();
1435
    }//try
1436
    finally
1437
    {
1438
      try
1439
      {
1440
        pstmt.close();
1441
      }
1442
      finally
1443
      {
1444
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1445
      }
1446
    }//finally
1447 570 bojilova
  }
1448
1449 688 bojilova
1450
  /**
1451
    * Get Access Control List information for document from db connetion.
1452
    * User or Group should have permissions for reading
1453
    * access control information for a document specified by @docid.
1454
    * @param docid document identifier which acl info to get
1455
    * @param user name of user connected to Metacat system
1456 802 bojilova
    * @param groups names of user's groups to which user belongs
1457 688 bojilova
    */
1458 802 bojilova
  public String getACL(String docid, String user, String[] groups)
1459 959 tao
          throws SQLException, Exception
1460 570 bojilova
  {
1461 688 bojilova
    StringBuffer output = new StringBuffer();
1462
    StringBuffer outTemp = new StringBuffer();
1463
    MetaCatUtil util = new MetaCatUtil();
1464
    String accDoctype = util.getOption("accessdoctype");
1465
    String server = util.getOption("server");
1466
    String docurl = "metacat://" + server + "/?docid=" + docid;
1467
    String systemID;
1468
    boolean isOwned = false;
1469
    boolean hasPermission = false;
1470
    String publicAcc;
1471 570 bojilova
1472 688 bojilova
    String acfid = "";
1473
    String acfid_prev = "";
1474
    String principal;
1475
    Vector principalArr = new Vector();
1476
    int permission;
1477
    int perm_prev = -1;
1478
    String permType;
1479
    String permOrder = "";
1480
    String permOrder_prev = "";
1481
    String beginTime = "";
1482
    String begin_prev = "";
1483
    String endTime = "";
1484
    String end_prev = "";
1485
    int ticketCount = -1;
1486
    int ticket_prev = -1;
1487 1214 tao
    DBConnection conn = null;
1488
    int serialNumber = -1;
1489
    PreparedStatement pstmt = null;
1490 638 bojilova
    try {
1491 688 bojilova
1492 1214 tao
      //check out DBConnection
1493
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACL");
1494
      serialNumber=conn.getCheckOutSerialNumber();
1495
1496 688 bojilova
      isOwned = isOwned(docid, user);
1497 944 tao
      systemID = getSystemID((String)MetaCatUtil.
1498
                                      getOptionList(accDoctype).elementAt(0));
1499 688 bojilova
      publicAcc = getPublicAccess(docid);
1500
1501
      output.append("<?xml version=\"1.0\"?>\n");
1502
      output.append("<!DOCTYPE acl PUBLIC \"" + accDoctype + "\" \"" +
1503
                    systemID + "\">\n");
1504
      output.append("<acl authSystem=\"\">\n");
1505
1506 1214 tao
1507 688 bojilova
      pstmt = conn.prepareStatement(
1508
              "SELECT distinct accessfileid, principal_name, permission, " +
1509
              "perm_type, perm_order, to_char(begin_time,'mm/dd/yyyy'), " +
1510
              "to_char(end_time,'mm/dd/yyyy'), ticket_count " +
1511 765 bojilova
              "FROM xml_access WHERE docid = ? " +
1512 688 bojilova
              "ORDER BY accessfileid, perm_order, perm_type, permission");
1513
      // Bind the values to the query
1514
      pstmt.setString(1, docid);
1515
      pstmt.execute();
1516
      ResultSet rs = pstmt.getResultSet();
1517
      boolean hasRows = rs.next();
1518
      while (hasRows) {
1519
1520
        acfid = rs.getString(1);
1521
        principal = rs.getString(2);
1522
        permission = rs.getInt(3);
1523
        permType = rs.getString(4);
1524
        permOrder = rs.getString(5);
1525
        beginTime = rs.getString(6);
1526
        endTime = rs.getString(7);
1527
        ticketCount = rs.getInt(8);
1528
1529
        // if @docid is not owned by @user, only ACL info from that
1530 802 bojilova
        // access files to which @user/@groups has "read" permission
1531 688 bojilova
        // is extracted
1532
        if ( !isOwned ) {
1533
          if ( !acfid.equals(acfid_prev) ) {
1534
            acfid_prev = acfid;
1535 802 bojilova
            hasPermission = this.hasPermission("READ",user,groups,acfid);
1536 688 bojilova
          }
1537
          if ( !hasPermission ) {
1538
            rs.next();
1539
            continue;
1540
          }
1541
        }
1542
1543
        // open <resource> tag
1544
        if ( !permOrder.equals(permOrder_prev) ) {
1545
          // close </resource> tag if any was opened
1546
          output.append(outTemp.toString());
1547
          outTemp = new StringBuffer();
1548
          if ( !permOrder_prev.equals("") ) {
1549
            output.append("  </resource>\n");
1550
          }
1551
          output.append("  <resource order=\"" + permOrder + "\" public=\"" +
1552
                        publicAcc + "\">\n");
1553
          output.append("    <resourceIdentifier>" + docurl +
1554
                        "</resourceIdentifier>\n");
1555
          permOrder_prev = permOrder;
1556
        }
1557
1558
        // close </allow> or </deny> tag then open new one
1559
        if ( permission != perm_prev ||
1560
             (endTime == null) && (end_prev != null) ||
1561
             (beginTime == null) && (begin_prev != null) ||
1562
             endTime != null && !endTime.equals(end_prev)  ||
1563
             beginTime != null && !beginTime.equals(begin_prev) ||
1564
             ticketCount != ticket_prev )  {
1565
          output.append(outTemp.toString());
1566
          outTemp = new StringBuffer();
1567
          principalArr.removeAllElements();
1568
          output.append("    <" + permType + ">\n");
1569
        }
1570
1571
        // put all principals here for the same
1572
        // permission, duration and ticket_count
1573
        if ( !principalArr.contains(principal) ) {
1574
          principalArr.addElement(principal);
1575
          output.append("      <principal>" + principal + "</principal>\n");
1576
        }
1577
1578
        // prepare <permission> tags, <duration> and <ticketCount>
1579
        // if any to put within <allow> (<deny>) by next cicle
1580
        if ( permission != perm_prev ||
1581
             (endTime == null) && (end_prev != null) ||
1582
             (beginTime == null) && (begin_prev != null) ||
1583
             endTime != null && !endTime.equals(end_prev)  ||
1584
             beginTime != null && !beginTime.equals(begin_prev) ||
1585
             ticketCount != ticket_prev )  {
1586
          if ( (permission & READ) != 0 ) {
1587
            outTemp.append("      <permission>read</permission>\n");
1588
          }
1589
          if ( (permission & WRITE) != 0 ) {
1590
            outTemp.append("      <permission>write</permission>\n");
1591
          }
1592
          if ( (permission & ALL) != 0 ) {
1593
            outTemp.append("      <permission>all</permission>\n");
1594
          }
1595
          if ( (beginTime != null) || (endTime != null) ) {
1596
            outTemp.append("      <duration>" + beginTime + " " + endTime +
1597
                          "</duration>\n");
1598
          }
1599
          if ( ticketCount > 0 ) {
1600
            outTemp.append("      <ticketCount>" + ticketCount +
1601
                          "</ticketCount>\n");
1602
          }
1603
          outTemp.append("    </" + permType + ">\n");
1604
          perm_prev = permission;
1605
          ticket_prev = ticketCount;
1606
          begin_prev = beginTime;
1607
          end_prev = endTime;
1608
        }
1609
1610
        hasRows = rs.next();
1611 652 bojilova
      }
1612 688 bojilova
1613
      // close <allow> or <deny> if anything left in outTemp var
1614
      output.append(outTemp.toString());
1615
1616
      // If there are no any acl info for @docid accessible by @user/@group,
1617
      // extract only the following information
1618
      if ( permOrder.equals("") ) {
1619
        output.append("  <resource public=\"" + publicAcc + "\">\n");
1620
        output.append("    <resourceIdentifier>" + docurl +
1621
                      "</resourceIdentifier>\n");
1622
      }
1623
1624
      // always close them
1625
      output.append("  </resource>\n");
1626
      output.append("</acl>\n");
1627
1628
      pstmt.close();
1629
1630
      return output.toString();
1631
1632
    } catch (SQLException e) {
1633
      throw new
1634
      SQLException("AccessControlList.getACL(). " + e.getMessage());
1635 638 bojilova
    }
1636 1214 tao
    finally
1637
    {
1638
      try
1639
      {
1640
        pstmt.close();
1641
      }
1642
      finally
1643
      {
1644
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1645
      }
1646
    }
1647 688 bojilova
  }
1648
1649
  /* Check if @user is owner of @docid from db conn. */
1650
  private boolean isOwned(String docid, String user) throws SQLException {
1651
1652 1214 tao
    PreparedStatement pstmt = null;
1653
    DBConnection conn = null;
1654
    int serialNumber = -1;
1655
    try
1656
    {
1657
      //check out DBConnection
1658
      conn=DBConnectionPool.getDBConnection("AccessControlList.isOwned");
1659
      serialNumber=conn.getCheckOutSerialNumber();
1660
      pstmt = conn.prepareStatement("SELECT 'x' FROM xml_documents " +
1661 765 bojilova
                                  "WHERE docid = ? " +
1662
                                  "AND user_owner = ?");
1663 1214 tao
      pstmt.setString(1, docid);
1664
      pstmt.setString(2, user);
1665
      pstmt.execute();
1666
      ResultSet rs = pstmt.getResultSet();
1667
      boolean hasRow = rs.next();
1668
      return hasRow;
1669
    }
1670
    finally
1671
    {
1672
      try
1673
      {
1674
        pstmt.close();
1675
      }
1676
      finally
1677
      {
1678
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1679
      }
1680
    }
1681 688 bojilova
  }
1682 652 bojilova
1683 688 bojilova
  /* Get the flag for public "read" access for @docid from db conn. */
1684
  private String getPublicAccess(String docid) throws SQLException {
1685
1686
    int publicAcc = 0;
1687 1214 tao
    PreparedStatement pstmt = null;
1688
    DBConnection conn = null;
1689
    int serialNumber = -1;
1690
    try
1691
    {
1692
      //check out DBConnection
1693
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPublicAcces");
1694
      serialNumber=conn.getCheckOutSerialNumber();
1695
      pstmt = conn.prepareStatement("SELECT public_access FROM xml_documents " +
1696 765 bojilova
                                  "WHERE docid = ?");
1697 1214 tao
      pstmt.setString(1, docid);
1698
      pstmt.execute();
1699
      ResultSet rs = pstmt.getResultSet();
1700
      boolean hasRow = rs.next();
1701
      if ( hasRow ) {
1702
        publicAcc = rs.getInt(1);
1703
      }
1704
1705
      return (publicAcc == 1) ? "yes" : "no";
1706 1139 tao
    }
1707 1214 tao
    finally
1708
    {
1709
      try
1710
      {
1711
        pstmt.close();
1712
      }
1713
      finally
1714
      {
1715
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1716
      }
1717
    }
1718 688 bojilova
  }
1719
1720
  /* Get SystemID for @publicID from Metacat DB Catalog. */
1721
  private String getSystemID(String publicID) throws SQLException {
1722
1723
    String systemID = "";
1724 1214 tao
    PreparedStatement pstmt = null;
1725
    DBConnection conn = null;
1726
    int serialNumber = -1;
1727
1728
    try
1729
    {
1730
      //check out DBConnection
1731
      conn=DBConnectionPool.getDBConnection("AccessControlList.getSystemID");
1732
      serialNumber=conn.getCheckOutSerialNumber();
1733
1734
      pstmt = conn.prepareStatement("SELECT system_id FROM xml_catalog " +
1735 688 bojilova
                                  "WHERE entry_type = 'DTD' " +
1736 765 bojilova
                                  "AND public_id = ?");
1737 1214 tao
      pstmt.setString(1, publicID);
1738
      pstmt.execute();
1739
      ResultSet rs = pstmt.getResultSet();
1740
      boolean hasRow = rs.next();
1741
      if ( hasRow ) {
1742
        systemID = rs.getString(1);
1743
      }
1744 688 bojilova
1745 1214 tao
      return systemID;
1746
    }//try
1747
    finally
1748
    {
1749
1750
      try
1751
      {
1752
        pstmt.close();
1753
      }
1754
      finally
1755
      {
1756
        DBConnectionPool.returnDBConnection(conn, serialNumber);
1757
      }
1758
    }//finally
1759 688 bojilova
  }
1760
1761 555 bojilova
}