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
 *
9
 *   '$Author$'
10
 *     '$Date$'
11
 * '$Revision$'
12 669 jones
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 555 bojilova
 */
27
28
package edu.ucsb.nceas.metacat;
29
30
import java.io.*;
31
import java.sql.*;
32
import java.util.Stack;
33
import java.util.Vector;
34 652 bojilova
import java.util.Hashtable;
35
import java.net.URL;
36
import java.net.MalformedURLException;
37 555 bojilova
38 4140 daigle
import org.apache.log4j.Logger;
39 555 bojilova
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 4335 daigle
import edu.ucsb.nceas.metacat.service.DatabaseService;
51 4080 daigle
import edu.ucsb.nceas.metacat.service.PropertyService;
52 4698 daigle
import edu.ucsb.nceas.metacat.util.MetacatUtil;
53 4080 daigle
import edu.ucsb.nceas.metacat.util.SystemUtil;
54
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
55
56 555 bojilova
/**
57
 * A Class that loads eml-access.xml file containing ACL for a metadata
58
 * document into relational DB. It extends DefaultHandler class to handle
59
 * SAX parsing events when processing the XML stream.
60
 */
61 1368 tao
public class AccessControlList extends DefaultHandler
62
                               implements AccessControlInterface
63
{
64 555 bojilova
65 1368 tao
66 4335 daigle
  private static String sysdate = DatabaseService.getDBAdapter().getDateTimeFunction();
67
  private static String isnull = DatabaseService.getDBAdapter().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 4140 daigle
101
  private static Logger logMetacat = Logger.getLogger(AccessControlList.class);
102 555 bojilova
  /**
103
   * Construct an instance of the AccessControlList class.
104 688 bojilova
   * It is used by the permission check up from DBQuery or DocumentImpl
105
   * and from "getaccesscontrol" action
106 570 bojilova
   *
107 684 bojilova
   * @param conn the JDBC connection where acl info is get
108 570 bojilova
   */
109 1214 tao
  public AccessControlList(DBConnection conn) throws SQLException
110 570 bojilova
  {
111 1214 tao
    this.connection = conn;
112 570 bojilova
  }
113 1214 tao
114 570 bojilova
115 1214 tao
116
117 570 bojilova
  /**
118
   * Construct an instance of the AccessControlList class.
119 555 bojilova
   * It parse acl file and loads acl data into db connection.
120
   *
121
   * @param conn the JDBC connection where acl data are loaded
122 684 bojilova
   * @param aclid the Accession# of the document with the acl data
123 570 bojilova
   * @param acl the acl file containing acl data
124 684 bojilova
   * @param user the user connected to MetaCat servlet and owns the document
125 802 bojilova
   * @param groups the groups to which user belongs
126 684 bojilova
   * @param serverCode the serverid from xml_replication on which this document
127
   *        resides.
128 555 bojilova
   */
129 4080 daigle
  public AccessControlList(DBConnection conn, String aclid, int rev,
130 802 bojilova
                           String user, String[] groups, int serverCode)
131 4080 daigle
                  throws SAXException, IOException, McdbException, PropertyNotFoundException
132 555 bojilova
  {
133 4213 daigle
		String parserName = PropertyService.getProperty("xml.saxparser");
134 4080 daigle
		this.server = SystemUtil.getSecureServerURL();
135 4212 daigle
		this.sep = PropertyService.getProperty("document.accNumSeparator");
136 555 bojilova
137 4080 daigle
		this.connection = conn;
138
		this.parserName = parserName;
139
		this.processingDTD = false;
140
		this.elementStack = new Stack();
141 819 bojilova
142 4080 daigle
		this.user = user;
143
		this.groups = groups;
144
		this.aclid = aclid;
145
		this.resourceURL = new Vector();
146
		this.resourceID = new Vector();
147
		this.principal = new Vector();
148
		this.permission = 0;
149
		this.ticketCount = 0;
150
		// this.publicAcc = null;
151
		this.serverCode = serverCode;
152 555 bojilova
153 4080 daigle
		// read the access file from db connection
154
		DocumentImpl acldoc = new DocumentImpl(aclid + sep + rev);
155
		String acl = acldoc.toString();
156
		this.rev = acldoc.getRev();
157
158
		// Initialize the parse
159
		XMLReader parser = initializeParser();
160
		// parse the access file and write the info to xml_access
161 4497 daigle
		if (acl != null) {
162
			parser.parse(new InputSource(new StringReader(acl)));
163
		} else {
164
			throw new McdbException("Could not retrieve access control list for:  " + aclid + sep + rev);
165
		}
166 4080 daigle
	}
167
168 819 bojilova
// NOT USED
169 4080 daigle
// /**
170
// * Construct an instance of the AccessControlList class.
171 819 bojilova
//   * It parses eml-access file and loads acl data into db connection.
172
//   * It is used from command line execution.
173
//   *
174
//   * @param conn the JDBC connection where acl data are loaded
175
//   * @param docid the Accession# of the document with the acl data
176
//   * @param aclfilename the name of acl file containing acl data
177
//   * @param user the user connected to MetaCat servlet and owns the document
178
//   * @param groups the groups to which user belongs
179
//   */
180
//  public AccessControlList( Connection conn, String aclid, String aclfilename,
181
//                           String user, String[] groups )
182
//                  throws SAXException, IOException, McdbException
183
//  {
184
//    this(conn, aclid, new FileReader(new File(aclfilename).toString()),
185
//         user, groups, 1);
186
//  }
187 638 bojilova
188 660 bojilova
  /* Set up the SAX parser for reading the XML serialized ACL */
189 555 bojilova
  private XMLReader initializeParser() throws SAXException
190
  {
191
    XMLReader parser = null;
192
193
    // Get an instance of the parser
194
    parser = XMLReaderFactory.createXMLReader(parserName);
195
196 598 bojilova
    // Turn off validation
197 638 bojilova
    parser.setFeature("http://xml.org/sax/features/validation", true);
198 598 bojilova
199
    // Set Handlers in the parser
200 555 bojilova
    // Set the ContentHandler to this instance
201 598 bojilova
    parser.setContentHandler((ContentHandler)this);
202 555 bojilova
203 598 bojilova
    // make a DBEntityResolver instance
204
    // Set the EntityReslover to DBEntityResolver instance
205 1214 tao
    EntityResolver eresolver = new DBEntityResolver(connection,this,null);
206 598 bojilova
    parser.setEntityResolver((EntityResolver)eresolver);
207
208 555 bojilova
    // Set the ErrorHandler to this instance
209 598 bojilova
    parser.setErrorHandler((ErrorHandler)this);
210 555 bojilova
211 862 berkley
    return parser;
212 555 bojilova
  }
213
214
  /**
215 688 bojilova
   * Callback method used by the SAX Parser when beginning of the document
216 645 bojilova
   */
217
  public void startDocument() throws SAXException
218
  {
219
    //delete all previously submitted permissions @ relations
220
    //this happens only on UPDATE of the access file
221
    try {
222 819 bojilova
      this.aclObjects = getACLObjects(aclid);
223 802 bojilova
224 819 bojilova
      //delete all permissions for resources related to @aclid if any
225 645 bojilova
      if ( aclid != null ) {
226
        deletePermissionsForRelatedResources(aclid);
227
      }
228
    } catch (SQLException sqle) {
229
      throw new SAXException(sqle);
230
    }
231
  }
232
233
  /**
234 688 bojilova
   * Callback method used by the SAX Parser when the start tag of an
235 555 bojilova
   * element is detected. Used in this context to parse and store
236
   * the acl information in class variables.
237
   */
238
  public void startElement (String uri, String localName,
239
                            String qName, Attributes atts)
240
         throws SAXException
241
  {
242 859 berkley
    instarttag = true;
243
    if(localName.equals("allow"))
244
    {
245
      tagName = "allow";
246
    }
247
    else if(localName.equals("deny"))
248
    {
249
      tagName = "deny";
250
    }
251 555 bojilova
    BasicNode currentNode = new BasicNode(localName);
252
    if (atts != null) {
253
      int len = atts.getLength();
254
      for (int i = 0; i < len; i++) {
255
        currentNode.setAttribute(atts.getLocalName(i), atts.getValue(i));
256
      }
257
    }
258 802 bojilova
    if ( currentNode.getTagName().equals("acl") ) {
259 570 bojilova
      permOrder = currentNode.getAttribute("order");
260 802 bojilova
    //  publicAcc = currentNode.getAttribute("public");
261 570 bojilova
    }
262 555 bojilova
    elementStack.push(currentNode);
263
  }
264
265
  /**
266 688 bojilova
   * Callback method used by the SAX Parser when the text sequences of an
267 555 bojilova
   * xml stream are detected. Used in this context to parse and store
268
   * the acl information in class variables.
269 859 berkley
   */
270 555 bojilova
  public void characters(char ch[], int start, int length)
271
         throws SAXException
272
  {
273 859 berkley
    if(!instarttag)
274
    {
275
      return;
276
    }
277 555 bojilova
    String inputString = new String(ch, start, length);
278 859 berkley
    inputString = inputString.trim();
279 862 berkley
    //System.out.println("==============inputString: " + inputString);
280 555 bojilova
    BasicNode currentNode = (BasicNode)elementStack.peek();
281
    String currentTag = currentNode.getTagName();
282
283 802 bojilova
      if (currentTag.equals("principal")) {
284 645 bojilova
285 802 bojilova
        principal.addElement(inputString);
286 645 bojilova
287 802 bojilova
      } else if (currentTag.equals("permission")) {
288 645 bojilova
289 802 bojilova
        if ( inputString.trim().toUpperCase().equals("READ") ) {
290
          permission = permission | READ;
291
        } else if ( inputString.trim().toUpperCase().equals("WRITE") ) {
292
          permission = permission | WRITE;
293 944 tao
        } else if ( inputString.trim().toUpperCase().equals("CHANGEPERMISSION"))
294
        {
295 862 berkley
          permission = permission | CHMOD;
296 802 bojilova
        } else if ( inputString.trim().toUpperCase().equals("ALL") ) {
297
          permission = permission | ALL;
298 862 berkley
        }/*else{
299 802 bojilova
          throw new SAXException("Unknown permission type: " + inputString);
300 859 berkley
        }*/
301 645 bojilova
302 802 bojilova
      } else if ( currentTag.equals("startDate") && beginTime == null ) {
303
        beginTime = inputString.trim();
304 645 bojilova
305 802 bojilova
      } else if ( currentTag.equals("stopDate") && endTime == null) {
306
        endTime = inputString.trim();
307 645 bojilova
308 802 bojilova
      } else if (currentTag.equals("ticketCount") && ticketCount == 0 ) {
309
        try {
310
          ticketCount = (new Integer(inputString.trim())).intValue();
311
        } catch (NumberFormatException nfe) {
312
          throw new SAXException("Wrong integer format for:" + inputString);
313
        }
314 555 bojilova
      }
315
  }
316
317
  /**
318 688 bojilova
   * Callback method used by the SAX Parser when the end tag of an
319 555 bojilova
   * element is detected. Used in this context to parse and store
320
   * the acl information in class variables.
321
   */
322
  public void endElement (String uri, String localName, String qName)
323
         throws SAXException
324
  {
325 859 berkley
    instarttag = false;
326 688 bojilova
    BasicNode leaving = (BasicNode)elementStack.pop();
327
    String leavingTagName = leaving.getTagName();
328
329 802 bojilova
    if ( leavingTagName.equals("allow") ||
330
         leavingTagName.equals("deny")    ) {
331 570 bojilova
332
      if ( permission > 0 ) {
333 555 bojilova
334 570 bojilova
        // insert into db calculated permission for the list of principals
335
        try {
336 802 bojilova
          // go through the objects in xml_relation about this acl doc
337
          for (int i=0; i < aclObjects.size(); i++) {
338
            // docid of the current object
339
            String docid = (String)aclObjects.elementAt(i);
340 2641 tao
            //DocumentIdentifier docID = new DocumentIdentifier(docid);
341
            //docid = docID.getIdentifier();
342
            // the docid get here has revision number, so we need to
343
            // remove it.
344 4698 daigle
            //docid = MetacatUtil.getDocIdFromAccessionNumber(docid);
345 2641 tao
            //System.out.println("The docid insert is!!!!!!!!!! "+ docid);
346 802 bojilova
            insertPermissions(docid,leavingTagName);
347
          }
348 968 tao
349 1330 tao
          // if acl is not in object list
350 968 tao
          //should insert permission for aclid itself into database
351 1336 tao
          /*if (!aclObjects.contains(aclid))
352 1330 tao
          {
353
            DocumentIdentifier aclIdItself = new DocumentIdentifier(aclid);
354
            String aclIdString = aclIdItself.getIdentifier();
355
            insertPermissions(aclIdString,leavingTagName);
356 1336 tao
          }*/
357 968 tao
358 802 bojilova
359 570 bojilova
        } catch (SQLException sqle) {
360
          throw new SAXException(sqle);
361 802 bojilova
        } catch (Exception e) {
362
          throw new SAXException(e);
363 570 bojilova
        }
364
      }
365
366 688 bojilova
      // reset the allow/deny permission
367 660 bojilova
      principal = new Vector();
368 555 bojilova
      permission = 0;
369 570 bojilova
      beginTime = null;
370
      endTime = null;
371
      ticketCount = 0;
372 555 bojilova
373 570 bojilova
    }
374 555 bojilova
375
  }
376 598 bojilova
377 688 bojilova
  /**
378
    * SAX Handler that receives notification of DOCTYPE. Sets the DTD.
379
    * @param name name of the DTD
380
    * @param publicId Public Identifier of the DTD
381
    * @param systemId System Identifier of the DTD
382
    */
383 598 bojilova
  public void startDTD(String name, String publicId, String systemId)
384
              throws SAXException {
385
    docname = name;
386
    doctype = publicId;
387
    systemid = systemId;
388
  }
389
390
  /**
391 688 bojilova
   * SAX Handler that receives notification of the start of entities.
392
   * @param name name of the entity
393 598 bojilova
   */
394
  public void startEntity(String name) throws SAXException {
395
    if (name.equals("[dtd]")) {
396
      processingDTD = true;
397
    }
398
  }
399
400
  /**
401 688 bojilova
   * SAX Handler that receives notification of the end of entities.
402
   * @param name name of the entity
403 598 bojilova
   */
404
  public void endEntity(String name) throws SAXException {
405
    if (name.equals("[dtd]")) {
406
      processingDTD = false;
407
    }
408
  }
409
410
  /**
411 688 bojilova
   * Get the document name.
412 598 bojilova
   */
413
  public String getDocname() {
414
    return docname;
415
  }
416
417
  /**
418 688 bojilova
   * Get the document processing state.
419 598 bojilova
   */
420
  public boolean processingDTD() {
421
    return processingDTD;
422
  }
423
424 802 bojilova
  /* Get all objects associated with @aclid from db.*/
425
  private Vector getACLObjects(String aclid)
426 638 bojilova
          throws SQLException
427
  {
428 802 bojilova
    Vector aclObjects = new Vector();
429 1214 tao
    DBConnection conn = null;
430
    int serialNumber = -1;
431
    PreparedStatement pstmt = null;
432
    try
433
    {
434
      //get connection from DBConnectionPool
435
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACLObject");
436
      serialNumber=conn.getCheckOutSerialNumber();
437
438
      // delete all acl records for resources related to @aclid if any
439
      pstmt = conn.prepareStatement(
440 802 bojilova
                             "SELECT object FROM xml_relation " +
441 830 jones
                             "WHERE subject = ? ");
442 1214 tao
      pstmt.setString(1,aclid);
443
      pstmt.execute();
444
      ResultSet rs = pstmt.getResultSet();
445
      boolean hasRows = rs.next();
446
      while (hasRows) {
447 2641 tao
        String object = rs.getString(1);
448
        //System.out.println("add acl object into vector !!!!!!!!!!!!!!!!!"+object);
449
        aclObjects.addElement(object);
450 1214 tao
        hasRows = rs.next();
451
      }//whil
452 802 bojilova
    }
453 1214 tao
    catch (SQLException e)
454
    {
455
      throw e;
456
    }
457
    finally
458
    {
459
      try
460
      {
461
        pstmt.close();
462
      }
463
      finally
464
      {
465
        //retrun DBConnection
466
        DBConnectionPool.returnDBConnection(conn,serialNumber);
467
      }
468
    }
469 802 bojilova
470
    return aclObjects;
471 638 bojilova
  }
472
473 802 bojilova
  /* Delete from db all permission for resources related to @aclid if any.*/
474
  private void deletePermissionsForRelatedResources(String aclid)
475 638 bojilova
          throws SQLException
476
  {
477 1214 tao
    //DBConnection conn = null;
478
    //int serialNumber = -1;
479
    Statement stmt = null;
480
    try
481
    {
482
      //check out DBConenction
483
      //conn=DBConnectionPool.getDBConnection("AccessControlList.deltePerm");
484
      //serialNumber=conn.getCheckOutSerialNumber();
485
      // delete all acl records for resources related to @aclid if any
486
      stmt = connection.createStatement();
487
      // Increase DBConnection usage count
488
      connection.increaseUsageCount(1);
489 4140 daigle
      logMetacat.debug("running sql: " + stmt.toString());
490 1214 tao
      stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + aclid
491
                                                                      + "'");
492
      //increase usageCount!!!!!!
493
      //conn.increaseUsageCount(1);
494
    }
495
    catch (SQLException e)
496
    {
497
      throw e;
498
    }
499
    finally
500
    {
501
      stmt.close();
502
      //retrun DBConnection
503
      //DBConnectionPool.returnDBConnection(conn,serialNumber);
504
    }
505 645 bojilova
  }
506
507 1214 tao
  /* Insert into db calculated permission for the list of principals
508
   * The DBConnection it is use is class field. Because we want to keep rollback
509
   * features and it need use same connection
510
  */
511
512 802 bojilova
  private void insertPermissions(String docid, String permType )
513 1214 tao
                                            throws SQLException
514 555 bojilova
  {
515 1214 tao
    PreparedStatement pstmt = null;
516
    //DBConnection conn = null;
517
    //int serialNumber = -1;
518 555 bojilova
    try {
519 1214 tao
      //Check out DBConnection
520
      //conn=DBConnectionPool.getDBConnection("AccessControlList.insertPerm");
521
      //serialNumber=conn.getCheckOutSerialNumber();
522
523
      pstmt = connection.prepareStatement(
524 555 bojilova
              "INSERT INTO xml_access " +
525 645 bojilova
              "(docid, principal_name, permission, perm_type, perm_order," +
526 1750 tao
              "ticket_count, accessfileid) VALUES " +
527
              "(?,?,?,?,?,?,?)");
528 1214 tao
      // Increase DBConnection usage count
529
      connection.increaseUsageCount(1);
530 555 bojilova
      // Bind the values to the query
531 802 bojilova
      pstmt.setString(1, docid);
532 570 bojilova
      pstmt.setInt(3, permission);
533
      pstmt.setString(4, permType);
534
      pstmt.setString(5, permOrder);
535 1750 tao
      pstmt.setString(7, aclid);
536 570 bojilova
      if ( ticketCount > 0 ) {
537 2604 tao
        pstmt.setInt(6, ticketCount);
538 570 bojilova
      } else {
539 2604 tao
        pstmt.setInt(6, 0);
540 570 bojilova
      }
541 1214 tao
542
      //incrase usagecount for DBConnection
543
      //conn.increaseUsageCount(1);
544 688 bojilova
      String prName;
545 802 bojilova
      for ( int j = 0; j < principal.size(); j++ ) {
546
        prName = (String)principal.elementAt(j);
547
        pstmt.setString(2, prName);
548 4140 daigle
        logMetacat.debug("running sql: " + pstmt.toString());
549 802 bojilova
        pstmt.execute();
550
      /*
551
        // check if there are conflict with permission's order
552
        String permOrderOpos = permOrder;
553
        int perm = getPermissions(permission, prName, docid, permOrder);
554
        if (  perm != 0 ) {
555
          if ( permOrder.equals("allowFirst") ) {
556
            permOrderOpos = "denyFirst";
557
          } else if ( permOrder.equals("denyFirst") ) {
558
            permOrderOpos = "allowFirst";
559 688 bojilova
          }
560 802 bojilova
          throw new SQLException("Permission(s) " + txtValue(perm) +
561
                    " for \"" + prName + "\" on document #" + docid +
562
                    " has/have been used with \"" + permOrderOpos + "\"");
563 665 bojilova
        }
564 802 bojilova
      */
565 570 bojilova
      }
566 672 bojilova
      pstmt.close();
567 555 bojilova
568 570 bojilova
    } catch (SQLException e) {
569
      throw new
570
      SQLException("AccessControlList.insertPermissions(): " + e.getMessage());
571 672 bojilova
    }
572 1214 tao
    finally
573
    {
574
      pstmt.close();
575
      //return the DBConnection
576
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
577
    }
578 672 bojilova
  }
579
580 688 bojilova
  /* Get permissions with permission order different than @permOrder. */
581
  private int getPermissions(int permission, String principal,
582
                             String docid, String permOrder)
583
          throws SQLException
584
  {
585 1214 tao
    PreparedStatement pstmt = null;
586
    DBConnection conn = null;
587
    int serialNumber = -1;
588
    try
589
    {
590
      //check out DBConnection
591
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPermissions");
592
      serialNumber=conn.getCheckOutSerialNumber();
593
      pstmt = conn.prepareStatement(
594 688 bojilova
            "SELECT permission FROM xml_access " +
595 765 bojilova
            "WHERE docid = ? " +
596
            "AND principal_name = ? " +
597
            "AND perm_order NOT = ?");
598 1214 tao
      pstmt.setString(1, docid);
599
      pstmt.setString(2, principal);
600
      pstmt.setString(3, permOrder);
601 4140 daigle
      logMetacat.debug("running sql: " + pstmt.toString());
602 1214 tao
      pstmt.execute();
603
      ResultSet rs = pstmt.getResultSet();
604
      boolean hasRow = rs.next();
605
      int perm = 0;
606
      while ( hasRow ) {
607
        perm = rs.getInt(1);
608
        perm = permission & perm;
609
        if ( perm != 0 ) {
610
          pstmt.close();
611
          return perm;
612
        }
613
        hasRow = rs.next();
614
      }
615
    }//try
616
    catch (SQLException e)
617
    {
618
      throw e;
619
    }
620
    finally
621
    {
622
      try
623
      {
624 1139 tao
        pstmt.close();
625 688 bojilova
      }
626 1214 tao
      finally
627
      {
628
        DBConnectionPool.returnDBConnection(conn, serialNumber);
629
      }
630 688 bojilova
    }
631
    return 0;
632
  }
633
634
  /* Get the int value of READ, WRITE or ALL. */
635 1368 tao
  public static int intValue ( String permission )
636 688 bojilova
  {
637 1368 tao
    if ( permission.equalsIgnoreCase("READ") ) {
638 688 bojilova
      return READ;
639 1368 tao
    } else if ( permission.equalsIgnoreCase("WRITE") ) {
640 688 bojilova
      return WRITE;
641 1368 tao
    } else if ( permission.equalsIgnoreCase("ALL") ) {
642 688 bojilova
      return ALL;
643
    }
644
645
    return -1;
646
  }
647
648
  /* Get the text value of READ, WRITE or ALL. */
649 4447 leinfelder
  public static String txtValue ( int permission )
650 688 bojilova
  {
651 4447 leinfelder
    StringBuffer txtPerm = new StringBuffer();
652
    if (permission == READ) {
653
      txtPerm.append("READ");
654 688 bojilova
    }
655 4447 leinfelder
    if (permission == WRITE) {
656
      txtPerm.append("WRITE");
657 688 bojilova
    }
658 4447 leinfelder
    if (permission == ALL) {
659
      txtPerm.append("ALL");
660 688 bojilova
    }
661
662 4447 leinfelder
    return txtPerm.toString();
663 688 bojilova
  }
664
665 802 bojilova
  /**
666 688 bojilova
    * Get Access Control List information for document from db connetion.
667
    * User or Group should have permissions for reading
668
    * access control information for a document specified by @docid.
669
    * @param docid document identifier which acl info to get
670
    * @param user name of user connected to Metacat system
671 802 bojilova
    * @param groups names of user's groups to which user belongs
672 688 bojilova
    */
673 802 bojilova
  public String getACL(String docid, String user, String[] groups)
674 959 tao
          throws SQLException, Exception
675 570 bojilova
  {
676 688 bojilova
    StringBuffer output = new StringBuffer();
677
    StringBuffer outTemp = new StringBuffer();
678 4213 daigle
    String accDoctype = PropertyService.getProperty("xml.accessdoctype");
679
    String server = PropertyService.getProperty("server.name");
680 688 bojilova
    String docurl = "metacat://" + server + "/?docid=" + docid;
681
    String systemID;
682
    boolean isOwned = false;
683
    boolean hasPermission = false;
684
    String publicAcc;
685 570 bojilova
686 688 bojilova
    String acfid = "";
687
    String acfid_prev = "";
688
    String principal;
689
    Vector principalArr = new Vector();
690
    int permission;
691
    int perm_prev = -1;
692
    String permType;
693
    String permOrder = "";
694
    String permOrder_prev = "";
695
    String beginTime = "";
696
    String begin_prev = "";
697
    String endTime = "";
698
    String end_prev = "";
699
    int ticketCount = -1;
700
    int ticket_prev = -1;
701 1214 tao
    DBConnection conn = null;
702
    int serialNumber = -1;
703
    PreparedStatement pstmt = null;
704 638 bojilova
    try {
705 688 bojilova
706 1214 tao
      //check out DBConnection
707
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACL");
708
      serialNumber=conn.getCheckOutSerialNumber();
709
710 688 bojilova
      isOwned = isOwned(docid, user);
711 4698 daigle
      systemID = getSystemID((String)MetacatUtil.
712 944 tao
                                      getOptionList(accDoctype).elementAt(0));
713 688 bojilova
      publicAcc = getPublicAccess(docid);
714
715
      output.append("<?xml version=\"1.0\"?>\n");
716
      output.append("<!DOCTYPE acl PUBLIC \"" + accDoctype + "\" \"" +
717
                    systemID + "\">\n");
718
      output.append("<acl authSystem=\"\">\n");
719
720 1214 tao
721 688 bojilova
      pstmt = conn.prepareStatement(
722
              "SELECT distinct accessfileid, principal_name, permission, " +
723
              "perm_type, perm_order, to_char(begin_time,'mm/dd/yyyy'), " +
724
              "to_char(end_time,'mm/dd/yyyy'), ticket_count " +
725 765 bojilova
              "FROM xml_access WHERE docid = ? " +
726 688 bojilova
              "ORDER BY accessfileid, perm_order, perm_type, permission");
727
      // Bind the values to the query
728
      pstmt.setString(1, docid);
729 4140 daigle
      logMetacat.debug("running sql: " + pstmt.toString());
730 688 bojilova
      pstmt.execute();
731
      ResultSet rs = pstmt.getResultSet();
732
      boolean hasRows = rs.next();
733
      while (hasRows) {
734
735
        acfid = rs.getString(1);
736
        principal = rs.getString(2);
737
        permission = rs.getInt(3);
738
        permType = rs.getString(4);
739
        permOrder = rs.getString(5);
740
        beginTime = rs.getString(6);
741
        endTime = rs.getString(7);
742
        ticketCount = rs.getInt(8);
743
744
        // if @docid is not owned by @user, only ACL info from that
745 802 bojilova
        // access files to which @user/@groups has "read" permission
746 688 bojilova
        // is extracted
747
        if ( !isOwned ) {
748
          if ( !acfid.equals(acfid_prev) ) {
749
            acfid_prev = acfid;
750 1426 tao
            //hasPermission = this.hasPermission("READ",user,groups,acfid);
751
             PermissionController controller = new PermissionController(acfid);
752
             hasPermission = controller.hasPermission(user,groups,
753
                                            AccessControlInterface.READSTRING);
754 688 bojilova
          }
755
          if ( !hasPermission ) {
756
            rs.next();
757
            continue;
758
          }
759
        }
760
761
        // open <resource> tag
762
        if ( !permOrder.equals(permOrder_prev) ) {
763
          // close </resource> tag if any was opened
764
          output.append(outTemp.toString());
765
          outTemp = new StringBuffer();
766
          if ( !permOrder_prev.equals("") ) {
767
            output.append("  </resource>\n");
768
          }
769
          output.append("  <resource order=\"" + permOrder + "\" public=\"" +
770
                        publicAcc + "\">\n");
771
          output.append("    <resourceIdentifier>" + docurl +
772
                        "</resourceIdentifier>\n");
773
          permOrder_prev = permOrder;
774
        }
775
776
        // close </allow> or </deny> tag then open new one
777
        if ( permission != perm_prev ||
778
             (endTime == null) && (end_prev != null) ||
779
             (beginTime == null) && (begin_prev != null) ||
780
             endTime != null && !endTime.equals(end_prev)  ||
781
             beginTime != null && !beginTime.equals(begin_prev) ||
782
             ticketCount != ticket_prev )  {
783
          output.append(outTemp.toString());
784
          outTemp = new StringBuffer();
785
          principalArr.removeAllElements();
786
          output.append("    <" + permType + ">\n");
787
        }
788
789
        // put all principals here for the same
790
        // permission, duration and ticket_count
791
        if ( !principalArr.contains(principal) ) {
792
          principalArr.addElement(principal);
793
          output.append("      <principal>" + principal + "</principal>\n");
794
        }
795
796
        // prepare <permission> tags, <duration> and <ticketCount>
797
        // if any to put within <allow> (<deny>) by next cicle
798
        if ( permission != perm_prev ||
799
             (endTime == null) && (end_prev != null) ||
800
             (beginTime == null) && (begin_prev != null) ||
801
             endTime != null && !endTime.equals(end_prev)  ||
802
             beginTime != null && !beginTime.equals(begin_prev) ||
803
             ticketCount != ticket_prev )  {
804
          if ( (permission & READ) != 0 ) {
805
            outTemp.append("      <permission>read</permission>\n");
806
          }
807
          if ( (permission & WRITE) != 0 ) {
808
            outTemp.append("      <permission>write</permission>\n");
809
          }
810
          if ( (permission & ALL) != 0 ) {
811
            outTemp.append("      <permission>all</permission>\n");
812
          }
813
          if ( (beginTime != null) || (endTime != null) ) {
814
            outTemp.append("      <duration>" + beginTime + " " + endTime +
815
                          "</duration>\n");
816
          }
817
          if ( ticketCount > 0 ) {
818
            outTemp.append("      <ticketCount>" + ticketCount +
819
                          "</ticketCount>\n");
820
          }
821
          outTemp.append("    </" + permType + ">\n");
822
          perm_prev = permission;
823
          ticket_prev = ticketCount;
824
          begin_prev = beginTime;
825
          end_prev = endTime;
826
        }
827
828
        hasRows = rs.next();
829 652 bojilova
      }
830 688 bojilova
831
      // close <allow> or <deny> if anything left in outTemp var
832
      output.append(outTemp.toString());
833
834
      // If there are no any acl info for @docid accessible by @user/@group,
835
      // extract only the following information
836
      if ( permOrder.equals("") ) {
837
        output.append("  <resource public=\"" + publicAcc + "\">\n");
838
        output.append("    <resourceIdentifier>" + docurl +
839
                      "</resourceIdentifier>\n");
840
      }
841
842
      // always close them
843
      output.append("  </resource>\n");
844
      output.append("</acl>\n");
845
846
      pstmt.close();
847
848
      return output.toString();
849
850
    } catch (SQLException e) {
851
      throw new
852
      SQLException("AccessControlList.getACL(). " + e.getMessage());
853 638 bojilova
    }
854 1214 tao
    finally
855
    {
856
      try
857
      {
858
        pstmt.close();
859
      }
860
      finally
861
      {
862
        DBConnectionPool.returnDBConnection(conn, serialNumber);
863
      }
864
    }
865 688 bojilova
  }
866
867
  /* Check if @user is owner of @docid from db conn. */
868
  private boolean isOwned(String docid, String user) throws SQLException {
869
870 1214 tao
    PreparedStatement pstmt = null;
871
    DBConnection conn = null;
872
    int serialNumber = -1;
873
    try
874
    {
875
      //check out DBConnection
876
      conn=DBConnectionPool.getDBConnection("AccessControlList.isOwned");
877
      serialNumber=conn.getCheckOutSerialNumber();
878
      pstmt = conn.prepareStatement("SELECT 'x' FROM xml_documents " +
879 765 bojilova
                                  "WHERE docid = ? " +
880
                                  "AND user_owner = ?");
881 1214 tao
      pstmt.setString(1, docid);
882
      pstmt.setString(2, user);
883
      pstmt.execute();
884
      ResultSet rs = pstmt.getResultSet();
885
      boolean hasRow = rs.next();
886
      return hasRow;
887
    }
888
    finally
889
    {
890
      try
891
      {
892
        pstmt.close();
893
      }
894
      finally
895
      {
896
        DBConnectionPool.returnDBConnection(conn, serialNumber);
897
      }
898
    }
899 688 bojilova
  }
900 652 bojilova
901 688 bojilova
  /* Get the flag for public "read" access for @docid from db conn. */
902
  private String getPublicAccess(String docid) throws SQLException {
903
904
    int publicAcc = 0;
905 1214 tao
    PreparedStatement pstmt = null;
906
    DBConnection conn = null;
907
    int serialNumber = -1;
908
    try
909
    {
910
      //check out DBConnection
911
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPublicAcces");
912
      serialNumber=conn.getCheckOutSerialNumber();
913
      pstmt = conn.prepareStatement("SELECT public_access FROM xml_documents " +
914 765 bojilova
                                  "WHERE docid = ?");
915 1214 tao
      pstmt.setString(1, docid);
916
      pstmt.execute();
917
      ResultSet rs = pstmt.getResultSet();
918
      boolean hasRow = rs.next();
919
      if ( hasRow ) {
920
        publicAcc = rs.getInt(1);
921
      }
922
923
      return (publicAcc == 1) ? "yes" : "no";
924 1139 tao
    }
925 1214 tao
    finally
926
    {
927
      try
928
      {
929
        pstmt.close();
930
      }
931
      finally
932
      {
933
        DBConnectionPool.returnDBConnection(conn, serialNumber);
934
      }
935
    }
936 688 bojilova
  }
937
938
  /* Get SystemID for @publicID from Metacat DB Catalog. */
939 4080 daigle
  private String getSystemID(String publicID) throws SQLException, PropertyNotFoundException {
940 688 bojilova
941 4080 daigle
		String systemID = "";
942
		PreparedStatement pstmt = null;
943
		DBConnection conn = null;
944
		int serialNumber = -1;
945
946
		try {
947
			//check out DBConnection
948
			conn = DBConnectionPool.getDBConnection("AccessControlList.getSystemID");
949
			serialNumber = conn.getCheckOutSerialNumber();
950
951
			pstmt = conn.prepareStatement("SELECT system_id FROM xml_catalog "
952
					+ "WHERE entry_type = 'DTD' " + "AND public_id = ?");
953
			pstmt.setString(1, publicID);
954
			pstmt.execute();
955
			ResultSet rs = pstmt.getResultSet();
956
			boolean hasRow = rs.next();
957
			if (hasRow) {
958
				systemID = rs.getString(1);
959
				// system id may not have server url on front.  Add it if not.
960
				if (!systemID.startsWith("http://")) {
961 4123 daigle
					systemID = SystemUtil.getContextURL() + systemID;
962 4080 daigle
				}
963
			}
964
965
			return systemID;
966
		}//try
967
		finally {
968
			try {
969
				pstmt.close();
970
			} finally {
971
				DBConnectionPool.returnDBConnection(conn, serialNumber);
972
			}
973
		}//finally
974
	}
975
976 555 bojilova
}