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 4080 daigle
import edu.ucsb.nceas.metacat.service.PropertyService;
51
import edu.ucsb.nceas.metacat.util.MetaCatUtil;
52
import edu.ucsb.nceas.metacat.util.SystemUtil;
53
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
54
55 555 bojilova
/**
56
 * A Class that loads eml-access.xml file containing ACL for a metadata
57
 * document into relational DB. It extends DefaultHandler class to handle
58
 * SAX parsing events when processing the XML stream.
59
 */
60 1368 tao
public class AccessControlList extends DefaultHandler
61
                               implements AccessControlInterface
62
{
63 555 bojilova
64 1368 tao
65 774 bojilova
  private static String sysdate = MetaCatUtil.dbAdapter.getDateTimeFunction();
66
  private static String isnull = MetaCatUtil.dbAdapter.getIsNULLFunction();
67 961 tao
68 1214 tao
  private DBConnection connection;
69 555 bojilova
  private String parserName;
70
  private Stack elementStack;
71 645 bojilova
  private String server;
72 802 bojilova
  private String sep;
73 961 tao
74 598 bojilova
  private boolean	processingDTD;
75 645 bojilova
  private String  user;
76 802 bojilova
  private String[] groups;
77 638 bojilova
  private String  aclid;
78 802 bojilova
  private int     rev;
79 598 bojilova
  private String 	docname;
80
  private String 	doctype;
81
  private String 	systemid;
82
83 665 bojilova
  private String docurl;
84
  private Vector resourceURL;
85
  private Vector resourceID;
86 660 bojilova
  private Vector principal;
87 570 bojilova
  private int    permission;
88
  private String permType;
89
  private String permOrder;
90 802 bojilova
//  private String publicAcc;
91 570 bojilova
  private String beginTime;
92
  private String endTime;
93
  private int    ticketCount;
94 684 bojilova
  private int    serverCode = 1;
95 802 bojilova
96
  private Vector aclObjects = new Vector();
97 859 berkley
  private boolean instarttag = true;
98
  private String tagName = "";
99 4140 daigle
100
  private static Logger logMetacat = Logger.getLogger(AccessControlList.class);
101 555 bojilova
  /**
102
   * Construct an instance of the AccessControlList class.
103 688 bojilova
   * It is used by the permission check up from DBQuery or DocumentImpl
104
   * and from "getaccesscontrol" action
105 570 bojilova
   *
106 684 bojilova
   * @param conn the JDBC connection where acl info is get
107 570 bojilova
   */
108 1214 tao
  public AccessControlList(DBConnection conn) throws SQLException
109 570 bojilova
  {
110 1214 tao
    this.connection = conn;
111 570 bojilova
  }
112 1214 tao
113 570 bojilova
114 1214 tao
115
116 570 bojilova
  /**
117
   * Construct an instance of the AccessControlList class.
118 555 bojilova
   * It parse acl file and loads acl data into db connection.
119
   *
120
   * @param conn the JDBC connection where acl data are loaded
121 684 bojilova
   * @param aclid the Accession# of the document with the acl data
122 570 bojilova
   * @param acl the acl file containing acl data
123 684 bojilova
   * @param user the user connected to MetaCat servlet and owns the document
124 802 bojilova
   * @param groups the groups to which user belongs
125 684 bojilova
   * @param serverCode the serverid from xml_replication on which this document
126
   *        resides.
127 555 bojilova
   */
128 4080 daigle
  public AccessControlList(DBConnection conn, String aclid, int rev,
129 802 bojilova
                           String user, String[] groups, int serverCode)
130 4080 daigle
                  throws SAXException, IOException, McdbException, PropertyNotFoundException
131 555 bojilova
  {
132 4213 daigle
		String parserName = PropertyService.getProperty("xml.saxparser");
133 4080 daigle
		this.server = SystemUtil.getSecureServerURL();
134 4212 daigle
		this.sep = PropertyService.getProperty("document.accNumSeparator");
135 555 bojilova
136 4080 daigle
		this.connection = conn;
137
		this.parserName = parserName;
138
		this.processingDTD = false;
139
		this.elementStack = new Stack();
140 819 bojilova
141 4080 daigle
		this.user = user;
142
		this.groups = groups;
143
		this.aclid = aclid;
144
		this.resourceURL = new Vector();
145
		this.resourceID = new Vector();
146
		this.principal = new Vector();
147
		this.permission = 0;
148
		this.ticketCount = 0;
149
		// this.publicAcc = null;
150
		this.serverCode = serverCode;
151 555 bojilova
152 4080 daigle
		// read the access file from db connection
153
		DocumentImpl acldoc = new DocumentImpl(aclid + sep + rev);
154
		String acl = acldoc.toString();
155
		this.rev = acldoc.getRev();
156
157
		// Initialize the parse
158
		XMLReader parser = initializeParser();
159
		// parse the access file and write the info to xml_access
160
		parser.parse(new InputSource(new StringReader(acl)));
161
	}
162
163 819 bojilova
// NOT USED
164 4080 daigle
// /**
165
// * Construct an instance of the AccessControlList class.
166 819 bojilova
//   * 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 2641 tao
            //DocumentIdentifier docID = new DocumentIdentifier(docid);
336
            //docid = docID.getIdentifier();
337
            // the docid get here has revision number, so we need to
338
            // remove it.
339
            //docid = MetaCatUtil.getDocIdFromAccessionNumber(docid);
340
            //System.out.println("The docid insert is!!!!!!!!!! "+ docid);
341 802 bojilova
            insertPermissions(docid,leavingTagName);
342
          }
343 968 tao
344 1330 tao
          // if acl is not in object list
345 968 tao
          //should insert permission for aclid itself into database
346 1336 tao
          /*if (!aclObjects.contains(aclid))
347 1330 tao
          {
348
            DocumentIdentifier aclIdItself = new DocumentIdentifier(aclid);
349
            String aclIdString = aclIdItself.getIdentifier();
350
            insertPermissions(aclIdString,leavingTagName);
351 1336 tao
          }*/
352 968 tao
353 802 bojilova
354 570 bojilova
        } catch (SQLException sqle) {
355
          throw new SAXException(sqle);
356 802 bojilova
        } catch (Exception e) {
357
          throw new SAXException(e);
358 570 bojilova
        }
359
      }
360
361 688 bojilova
      // reset the allow/deny permission
362 660 bojilova
      principal = new Vector();
363 555 bojilova
      permission = 0;
364 570 bojilova
      beginTime = null;
365
      endTime = null;
366
      ticketCount = 0;
367 555 bojilova
368 570 bojilova
    }
369 555 bojilova
370
  }
371 598 bojilova
372 688 bojilova
  /**
373
    * SAX Handler that receives notification of DOCTYPE. Sets the DTD.
374
    * @param name name of the DTD
375
    * @param publicId Public Identifier of the DTD
376
    * @param systemId System Identifier of the DTD
377
    */
378 598 bojilova
  public void startDTD(String name, String publicId, String systemId)
379
              throws SAXException {
380
    docname = name;
381
    doctype = publicId;
382
    systemid = systemId;
383
  }
384
385
  /**
386 688 bojilova
   * SAX Handler that receives notification of the start of entities.
387
   * @param name name of the entity
388 598 bojilova
   */
389
  public void startEntity(String name) throws SAXException {
390
    if (name.equals("[dtd]")) {
391
      processingDTD = true;
392
    }
393
  }
394
395
  /**
396 688 bojilova
   * SAX Handler that receives notification of the end of entities.
397
   * @param name name of the entity
398 598 bojilova
   */
399
  public void endEntity(String name) throws SAXException {
400
    if (name.equals("[dtd]")) {
401
      processingDTD = false;
402
    }
403
  }
404
405
  /**
406 688 bojilova
   * Get the document name.
407 598 bojilova
   */
408
  public String getDocname() {
409
    return docname;
410
  }
411
412
  /**
413 688 bojilova
   * Get the document processing state.
414 598 bojilova
   */
415
  public boolean processingDTD() {
416
    return processingDTD;
417
  }
418
419 802 bojilova
  /* Get all objects associated with @aclid from db.*/
420
  private Vector getACLObjects(String aclid)
421 638 bojilova
          throws SQLException
422
  {
423 802 bojilova
    Vector aclObjects = new Vector();
424 1214 tao
    DBConnection conn = null;
425
    int serialNumber = -1;
426
    PreparedStatement pstmt = null;
427
    try
428
    {
429
      //get connection from DBConnectionPool
430
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACLObject");
431
      serialNumber=conn.getCheckOutSerialNumber();
432
433
      // delete all acl records for resources related to @aclid if any
434
      pstmt = conn.prepareStatement(
435 802 bojilova
                             "SELECT object FROM xml_relation " +
436 830 jones
                             "WHERE subject = ? ");
437 1214 tao
      pstmt.setString(1,aclid);
438
      pstmt.execute();
439
      ResultSet rs = pstmt.getResultSet();
440
      boolean hasRows = rs.next();
441
      while (hasRows) {
442 2641 tao
        String object = rs.getString(1);
443
        //System.out.println("add acl object into vector !!!!!!!!!!!!!!!!!"+object);
444
        aclObjects.addElement(object);
445 1214 tao
        hasRows = rs.next();
446
      }//whil
447 802 bojilova
    }
448 1214 tao
    catch (SQLException e)
449
    {
450
      throw e;
451
    }
452
    finally
453
    {
454
      try
455
      {
456
        pstmt.close();
457
      }
458
      finally
459
      {
460
        //retrun DBConnection
461
        DBConnectionPool.returnDBConnection(conn,serialNumber);
462
      }
463
    }
464 802 bojilova
465
    return aclObjects;
466 638 bojilova
  }
467
468 802 bojilova
  /* Delete from db all permission for resources related to @aclid if any.*/
469
  private void deletePermissionsForRelatedResources(String aclid)
470 638 bojilova
          throws SQLException
471
  {
472 1214 tao
    //DBConnection conn = null;
473
    //int serialNumber = -1;
474
    Statement stmt = null;
475
    try
476
    {
477
      //check out DBConenction
478
      //conn=DBConnectionPool.getDBConnection("AccessControlList.deltePerm");
479
      //serialNumber=conn.getCheckOutSerialNumber();
480
      // delete all acl records for resources related to @aclid if any
481
      stmt = connection.createStatement();
482
      // Increase DBConnection usage count
483
      connection.increaseUsageCount(1);
484 4140 daigle
      logMetacat.debug("running sql: " + stmt.toString());
485 1214 tao
      stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + aclid
486
                                                                      + "'");
487
      //increase usageCount!!!!!!
488
      //conn.increaseUsageCount(1);
489
    }
490
    catch (SQLException e)
491
    {
492
      throw e;
493
    }
494
    finally
495
    {
496
      stmt.close();
497
      //retrun DBConnection
498
      //DBConnectionPool.returnDBConnection(conn,serialNumber);
499
    }
500 645 bojilova
  }
501
502 1214 tao
  /* Insert into db calculated permission for the list of principals
503
   * The DBConnection it is use is class field. Because we want to keep rollback
504
   * features and it need use same connection
505
  */
506
507 802 bojilova
  private void insertPermissions(String docid, String permType )
508 1214 tao
                                            throws SQLException
509 555 bojilova
  {
510 1214 tao
    PreparedStatement pstmt = null;
511
    //DBConnection conn = null;
512
    //int serialNumber = -1;
513 555 bojilova
    try {
514 1214 tao
      //Check out DBConnection
515
      //conn=DBConnectionPool.getDBConnection("AccessControlList.insertPerm");
516
      //serialNumber=conn.getCheckOutSerialNumber();
517
518
      pstmt = connection.prepareStatement(
519 555 bojilova
              "INSERT INTO xml_access " +
520 645 bojilova
              "(docid, principal_name, permission, perm_type, perm_order," +
521 1750 tao
              "ticket_count, accessfileid) VALUES " +
522
              "(?,?,?,?,?,?,?)");
523 1214 tao
      // Increase DBConnection usage count
524
      connection.increaseUsageCount(1);
525 555 bojilova
      // Bind the values to the query
526 802 bojilova
      pstmt.setString(1, docid);
527 570 bojilova
      pstmt.setInt(3, permission);
528
      pstmt.setString(4, permType);
529
      pstmt.setString(5, permOrder);
530 1750 tao
      pstmt.setString(7, aclid);
531 570 bojilova
      if ( ticketCount > 0 ) {
532 2604 tao
        pstmt.setInt(6, ticketCount);
533 570 bojilova
      } else {
534 2604 tao
        pstmt.setInt(6, 0);
535 570 bojilova
      }
536 1214 tao
537
      //incrase usagecount for DBConnection
538
      //conn.increaseUsageCount(1);
539 688 bojilova
      String prName;
540 802 bojilova
      for ( int j = 0; j < principal.size(); j++ ) {
541
        prName = (String)principal.elementAt(j);
542
        pstmt.setString(2, prName);
543 4140 daigle
        logMetacat.debug("running sql: " + pstmt.toString());
544 802 bojilova
        pstmt.execute();
545
      /*
546
        // check if there are conflict with permission's order
547
        String permOrderOpos = permOrder;
548
        int perm = getPermissions(permission, prName, docid, permOrder);
549
        if (  perm != 0 ) {
550
          if ( permOrder.equals("allowFirst") ) {
551
            permOrderOpos = "denyFirst";
552
          } else if ( permOrder.equals("denyFirst") ) {
553
            permOrderOpos = "allowFirst";
554 688 bojilova
          }
555 802 bojilova
          throw new SQLException("Permission(s) " + txtValue(perm) +
556
                    " for \"" + prName + "\" on document #" + docid +
557
                    " has/have been used with \"" + permOrderOpos + "\"");
558 665 bojilova
        }
559 802 bojilova
      */
560 570 bojilova
      }
561 672 bojilova
      pstmt.close();
562 555 bojilova
563 570 bojilova
    } catch (SQLException e) {
564
      throw new
565
      SQLException("AccessControlList.insertPermissions(): " + e.getMessage());
566 672 bojilova
    }
567 1214 tao
    finally
568
    {
569
      pstmt.close();
570
      //return the DBConnection
571
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
572
    }
573 672 bojilova
  }
574
575 688 bojilova
  /* Get permissions with permission order different than @permOrder. */
576
  private int getPermissions(int permission, String principal,
577
                             String docid, String permOrder)
578
          throws SQLException
579
  {
580 1214 tao
    PreparedStatement pstmt = null;
581
    DBConnection conn = null;
582
    int serialNumber = -1;
583
    try
584
    {
585
      //check out DBConnection
586
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPermissions");
587
      serialNumber=conn.getCheckOutSerialNumber();
588
      pstmt = conn.prepareStatement(
589 688 bojilova
            "SELECT permission FROM xml_access " +
590 765 bojilova
            "WHERE docid = ? " +
591
            "AND principal_name = ? " +
592
            "AND perm_order NOT = ?");
593 1214 tao
      pstmt.setString(1, docid);
594
      pstmt.setString(2, principal);
595
      pstmt.setString(3, permOrder);
596 4140 daigle
      logMetacat.debug("running sql: " + pstmt.toString());
597 1214 tao
      pstmt.execute();
598
      ResultSet rs = pstmt.getResultSet();
599
      boolean hasRow = rs.next();
600
      int perm = 0;
601
      while ( hasRow ) {
602
        perm = rs.getInt(1);
603
        perm = permission & perm;
604
        if ( perm != 0 ) {
605
          pstmt.close();
606
          return perm;
607
        }
608
        hasRow = rs.next();
609
      }
610
    }//try
611
    catch (SQLException e)
612
    {
613
      throw e;
614
    }
615
    finally
616
    {
617
      try
618
      {
619 1139 tao
        pstmt.close();
620 688 bojilova
      }
621 1214 tao
      finally
622
      {
623
        DBConnectionPool.returnDBConnection(conn, serialNumber);
624
      }
625 688 bojilova
    }
626
    return 0;
627
  }
628
629
  /* Get the int value of READ, WRITE or ALL. */
630 1368 tao
  public static int intValue ( String permission )
631 688 bojilova
  {
632 1368 tao
    if ( permission.equalsIgnoreCase("READ") ) {
633 688 bojilova
      return READ;
634 1368 tao
    } else if ( permission.equalsIgnoreCase("WRITE") ) {
635 688 bojilova
      return WRITE;
636 1368 tao
    } else if ( permission.equalsIgnoreCase("ALL") ) {
637 688 bojilova
      return ALL;
638
    }
639
640
    return -1;
641
  }
642
643
  /* Get the text value of READ, WRITE or ALL. */
644
  private String txtValue ( int permission )
645
  {
646
    StringBuffer txtPerm = new StringBuffer("\"");
647
    if ( (permission & READ) != 0 ) {
648
      txtPerm.append("read");
649
    }
650
    if ( (permission & WRITE) != 0 ) {
651
      if ( txtPerm.length() > 0 ) txtPerm.append(",");
652
      txtPerm.append("write");
653
    }
654
    if ( (permission & ALL) != 0 ) {
655
      if ( txtPerm.length() > 0 ) txtPerm.append(",");
656
      txtPerm.append("all");
657
    }
658
659
    return txtPerm.append("\"").toString();
660
  }
661
662 802 bojilova
  /**
663 688 bojilova
    * Get Access Control List information for document from db connetion.
664
    * User or Group should have permissions for reading
665
    * access control information for a document specified by @docid.
666
    * @param docid document identifier which acl info to get
667
    * @param user name of user connected to Metacat system
668 802 bojilova
    * @param groups names of user's groups to which user belongs
669 688 bojilova
    */
670 802 bojilova
  public String getACL(String docid, String user, String[] groups)
671 959 tao
          throws SQLException, Exception
672 570 bojilova
  {
673 688 bojilova
    StringBuffer output = new StringBuffer();
674
    StringBuffer outTemp = new StringBuffer();
675 4213 daigle
    String accDoctype = PropertyService.getProperty("xml.accessdoctype");
676
    String server = PropertyService.getProperty("server.name");
677 688 bojilova
    String docurl = "metacat://" + server + "/?docid=" + docid;
678
    String systemID;
679
    boolean isOwned = false;
680
    boolean hasPermission = false;
681
    String publicAcc;
682 570 bojilova
683 688 bojilova
    String acfid = "";
684
    String acfid_prev = "";
685
    String principal;
686
    Vector principalArr = new Vector();
687
    int permission;
688
    int perm_prev = -1;
689
    String permType;
690
    String permOrder = "";
691
    String permOrder_prev = "";
692
    String beginTime = "";
693
    String begin_prev = "";
694
    String endTime = "";
695
    String end_prev = "";
696
    int ticketCount = -1;
697
    int ticket_prev = -1;
698 1214 tao
    DBConnection conn = null;
699
    int serialNumber = -1;
700
    PreparedStatement pstmt = null;
701 638 bojilova
    try {
702 688 bojilova
703 1214 tao
      //check out DBConnection
704
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACL");
705
      serialNumber=conn.getCheckOutSerialNumber();
706
707 688 bojilova
      isOwned = isOwned(docid, user);
708 944 tao
      systemID = getSystemID((String)MetaCatUtil.
709
                                      getOptionList(accDoctype).elementAt(0));
710 688 bojilova
      publicAcc = getPublicAccess(docid);
711
712
      output.append("<?xml version=\"1.0\"?>\n");
713
      output.append("<!DOCTYPE acl PUBLIC \"" + accDoctype + "\" \"" +
714
                    systemID + "\">\n");
715
      output.append("<acl authSystem=\"\">\n");
716
717 1214 tao
718 688 bojilova
      pstmt = conn.prepareStatement(
719
              "SELECT distinct accessfileid, principal_name, permission, " +
720
              "perm_type, perm_order, to_char(begin_time,'mm/dd/yyyy'), " +
721
              "to_char(end_time,'mm/dd/yyyy'), ticket_count " +
722 765 bojilova
              "FROM xml_access WHERE docid = ? " +
723 688 bojilova
              "ORDER BY accessfileid, perm_order, perm_type, permission");
724
      // Bind the values to the query
725
      pstmt.setString(1, docid);
726 4140 daigle
      logMetacat.debug("running sql: " + pstmt.toString());
727 688 bojilova
      pstmt.execute();
728
      ResultSet rs = pstmt.getResultSet();
729
      boolean hasRows = rs.next();
730
      while (hasRows) {
731
732
        acfid = rs.getString(1);
733
        principal = rs.getString(2);
734
        permission = rs.getInt(3);
735
        permType = rs.getString(4);
736
        permOrder = rs.getString(5);
737
        beginTime = rs.getString(6);
738
        endTime = rs.getString(7);
739
        ticketCount = rs.getInt(8);
740
741
        // if @docid is not owned by @user, only ACL info from that
742 802 bojilova
        // access files to which @user/@groups has "read" permission
743 688 bojilova
        // is extracted
744
        if ( !isOwned ) {
745
          if ( !acfid.equals(acfid_prev) ) {
746
            acfid_prev = acfid;
747 1426 tao
            //hasPermission = this.hasPermission("READ",user,groups,acfid);
748
             PermissionController controller = new PermissionController(acfid);
749
             hasPermission = controller.hasPermission(user,groups,
750
                                            AccessControlInterface.READSTRING);
751 688 bojilova
          }
752
          if ( !hasPermission ) {
753
            rs.next();
754
            continue;
755
          }
756
        }
757
758
        // open <resource> tag
759
        if ( !permOrder.equals(permOrder_prev) ) {
760
          // close </resource> tag if any was opened
761
          output.append(outTemp.toString());
762
          outTemp = new StringBuffer();
763
          if ( !permOrder_prev.equals("") ) {
764
            output.append("  </resource>\n");
765
          }
766
          output.append("  <resource order=\"" + permOrder + "\" public=\"" +
767
                        publicAcc + "\">\n");
768
          output.append("    <resourceIdentifier>" + docurl +
769
                        "</resourceIdentifier>\n");
770
          permOrder_prev = permOrder;
771
        }
772
773
        // close </allow> or </deny> tag then open new one
774
        if ( permission != perm_prev ||
775
             (endTime == null) && (end_prev != null) ||
776
             (beginTime == null) && (begin_prev != null) ||
777
             endTime != null && !endTime.equals(end_prev)  ||
778
             beginTime != null && !beginTime.equals(begin_prev) ||
779
             ticketCount != ticket_prev )  {
780
          output.append(outTemp.toString());
781
          outTemp = new StringBuffer();
782
          principalArr.removeAllElements();
783
          output.append("    <" + permType + ">\n");
784
        }
785
786
        // put all principals here for the same
787
        // permission, duration and ticket_count
788
        if ( !principalArr.contains(principal) ) {
789
          principalArr.addElement(principal);
790
          output.append("      <principal>" + principal + "</principal>\n");
791
        }
792
793
        // prepare <permission> tags, <duration> and <ticketCount>
794
        // if any to put within <allow> (<deny>) by next cicle
795
        if ( permission != perm_prev ||
796
             (endTime == null) && (end_prev != null) ||
797
             (beginTime == null) && (begin_prev != null) ||
798
             endTime != null && !endTime.equals(end_prev)  ||
799
             beginTime != null && !beginTime.equals(begin_prev) ||
800
             ticketCount != ticket_prev )  {
801
          if ( (permission & READ) != 0 ) {
802
            outTemp.append("      <permission>read</permission>\n");
803
          }
804
          if ( (permission & WRITE) != 0 ) {
805
            outTemp.append("      <permission>write</permission>\n");
806
          }
807
          if ( (permission & ALL) != 0 ) {
808
            outTemp.append("      <permission>all</permission>\n");
809
          }
810
          if ( (beginTime != null) || (endTime != null) ) {
811
            outTemp.append("      <duration>" + beginTime + " " + endTime +
812
                          "</duration>\n");
813
          }
814
          if ( ticketCount > 0 ) {
815
            outTemp.append("      <ticketCount>" + ticketCount +
816
                          "</ticketCount>\n");
817
          }
818
          outTemp.append("    </" + permType + ">\n");
819
          perm_prev = permission;
820
          ticket_prev = ticketCount;
821
          begin_prev = beginTime;
822
          end_prev = endTime;
823
        }
824
825
        hasRows = rs.next();
826 652 bojilova
      }
827 688 bojilova
828
      // close <allow> or <deny> if anything left in outTemp var
829
      output.append(outTemp.toString());
830
831
      // If there are no any acl info for @docid accessible by @user/@group,
832
      // extract only the following information
833
      if ( permOrder.equals("") ) {
834
        output.append("  <resource public=\"" + publicAcc + "\">\n");
835
        output.append("    <resourceIdentifier>" + docurl +
836
                      "</resourceIdentifier>\n");
837
      }
838
839
      // always close them
840
      output.append("  </resource>\n");
841
      output.append("</acl>\n");
842
843
      pstmt.close();
844
845
      return output.toString();
846
847
    } catch (SQLException e) {
848
      throw new
849
      SQLException("AccessControlList.getACL(). " + e.getMessage());
850 638 bojilova
    }
851 1214 tao
    finally
852
    {
853
      try
854
      {
855
        pstmt.close();
856
      }
857
      finally
858
      {
859
        DBConnectionPool.returnDBConnection(conn, serialNumber);
860
      }
861
    }
862 688 bojilova
  }
863
864
  /* Check if @user is owner of @docid from db conn. */
865
  private boolean isOwned(String docid, String user) throws SQLException {
866
867 1214 tao
    PreparedStatement pstmt = null;
868
    DBConnection conn = null;
869
    int serialNumber = -1;
870
    try
871
    {
872
      //check out DBConnection
873
      conn=DBConnectionPool.getDBConnection("AccessControlList.isOwned");
874
      serialNumber=conn.getCheckOutSerialNumber();
875
      pstmt = conn.prepareStatement("SELECT 'x' FROM xml_documents " +
876 765 bojilova
                                  "WHERE docid = ? " +
877
                                  "AND user_owner = ?");
878 1214 tao
      pstmt.setString(1, docid);
879
      pstmt.setString(2, user);
880
      pstmt.execute();
881
      ResultSet rs = pstmt.getResultSet();
882
      boolean hasRow = rs.next();
883
      return hasRow;
884
    }
885
    finally
886
    {
887
      try
888
      {
889
        pstmt.close();
890
      }
891
      finally
892
      {
893
        DBConnectionPool.returnDBConnection(conn, serialNumber);
894
      }
895
    }
896 688 bojilova
  }
897 652 bojilova
898 688 bojilova
  /* Get the flag for public "read" access for @docid from db conn. */
899
  private String getPublicAccess(String docid) throws SQLException {
900
901
    int publicAcc = 0;
902 1214 tao
    PreparedStatement pstmt = null;
903
    DBConnection conn = null;
904
    int serialNumber = -1;
905
    try
906
    {
907
      //check out DBConnection
908
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPublicAcces");
909
      serialNumber=conn.getCheckOutSerialNumber();
910
      pstmt = conn.prepareStatement("SELECT public_access FROM xml_documents " +
911 765 bojilova
                                  "WHERE docid = ?");
912 1214 tao
      pstmt.setString(1, docid);
913
      pstmt.execute();
914
      ResultSet rs = pstmt.getResultSet();
915
      boolean hasRow = rs.next();
916
      if ( hasRow ) {
917
        publicAcc = rs.getInt(1);
918
      }
919
920
      return (publicAcc == 1) ? "yes" : "no";
921 1139 tao
    }
922 1214 tao
    finally
923
    {
924
      try
925
      {
926
        pstmt.close();
927
      }
928
      finally
929
      {
930
        DBConnectionPool.returnDBConnection(conn, serialNumber);
931
      }
932
    }
933 688 bojilova
  }
934
935
  /* Get SystemID for @publicID from Metacat DB Catalog. */
936 4080 daigle
  private String getSystemID(String publicID) throws SQLException, PropertyNotFoundException {
937 688 bojilova
938 4080 daigle
		String systemID = "";
939
		PreparedStatement pstmt = null;
940
		DBConnection conn = null;
941
		int serialNumber = -1;
942
943
		try {
944
			//check out DBConnection
945
			conn = DBConnectionPool.getDBConnection("AccessControlList.getSystemID");
946
			serialNumber = conn.getCheckOutSerialNumber();
947
948
			pstmt = conn.prepareStatement("SELECT system_id FROM xml_catalog "
949
					+ "WHERE entry_type = 'DTD' " + "AND public_id = ?");
950
			pstmt.setString(1, publicID);
951
			pstmt.execute();
952
			ResultSet rs = pstmt.getResultSet();
953
			boolean hasRow = rs.next();
954
			if (hasRow) {
955
				systemID = rs.getString(1);
956
				// system id may not have server url on front.  Add it if not.
957
				if (!systemID.startsWith("http://")) {
958 4123 daigle
					systemID = SystemUtil.getContextURL() + systemID;
959 4080 daigle
				}
960
			}
961
962
			return systemID;
963
		}//try
964
		finally {
965
			try {
966
				pstmt.close();
967
			} finally {
968
				DBConnectionPool.returnDBConnection(conn, serialNumber);
969
			}
970
		}//finally
971
	}
972
973 555 bojilova
}