Project

General

Profile

1
/**
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: daigle $'
10
 *     '$Date: 2008-11-03 10:58:21 -0800 (Mon, 03 Nov 2008) $'
11
 * '$Revision: 4497 $'
12
 *
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
 */
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
import java.util.Hashtable;
35
import java.net.URL;
36
import java.net.MalformedURLException;
37

    
38
import org.apache.log4j.Logger;
39
import org.xml.sax.Attributes;
40
import org.xml.sax.InputSource;
41
import org.xml.sax.ContentHandler;
42
import org.xml.sax.EntityResolver;
43
import org.xml.sax.ErrorHandler;
44
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
import edu.ucsb.nceas.metacat.service.DatabaseService;
51
import edu.ucsb.nceas.metacat.service.PropertyService;
52
import edu.ucsb.nceas.metacat.util.MetaCatUtil;
53
import edu.ucsb.nceas.metacat.util.SystemUtil;
54
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
55

    
56
/** 
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
public class AccessControlList extends DefaultHandler 
62
                               implements AccessControlInterface 
63
{
64

    
65
 
66
  private static String sysdate = DatabaseService.getDBAdapter().getDateTimeFunction();
67
  private static String isnull = DatabaseService.getDBAdapter().getIsNULLFunction();
68
  
69
  private DBConnection connection;
70
  private String parserName;
71
  private Stack elementStack;
72
  private String server;
73
  private String sep;
74
 
75
  private boolean	processingDTD;
76
  private String  user;
77
  private String[] groups;
78
  private String  aclid;
79
  private int     rev;
80
  private String 	docname;
81
  private String 	doctype;
82
  private String 	systemid;
83

    
84
  private String docurl;
85
  private Vector resourceURL;
86
  private Vector resourceID;
87
  private Vector principal;
88
  private int    permission;
89
  private String permType;
90
  private String permOrder;
91
//  private String publicAcc;
92
  private String beginTime;
93
  private String endTime;
94
  private int    ticketCount;
95
  private int    serverCode = 1;
96

    
97
  private Vector aclObjects = new Vector();
98
  private boolean instarttag = true;
99
  private String tagName = "";
100
  
101
  private static Logger logMetacat = Logger.getLogger(AccessControlList.class);
102
  /**
103
   * Construct an instance of the AccessControlList class.
104
   * It is used by the permission check up from DBQuery or DocumentImpl
105
   * and from "getaccesscontrol" action
106
   *
107
   * @param conn the JDBC connection where acl info is get
108
   */
109
  public AccessControlList(DBConnection conn) throws SQLException
110
  {
111
    this.connection = conn;
112
  }
113
  
114

    
115
  
116

    
117
  /**
118
   * Construct an instance of the AccessControlList class.
119
   * It parse acl file and loads acl data into db connection.
120
   *
121
   * @param conn the JDBC connection where acl data are loaded
122
   * @param aclid the Accession# of the document with the acl data
123
   * @param acl the acl file containing acl data
124
   * @param user the user connected to MetaCat servlet and owns the document
125
   * @param groups the groups to which user belongs
126
   * @param serverCode the serverid from xml_replication on which this document
127
   *        resides.
128
   */
129
  public AccessControlList(DBConnection conn, String aclid, int rev,
130
                           String user, String[] groups, int serverCode)
131
                  throws SAXException, IOException, McdbException, PropertyNotFoundException
132
  {
133
		String parserName = PropertyService.getProperty("xml.saxparser");
134
		this.server = SystemUtil.getSecureServerURL();
135
		this.sep = PropertyService.getProperty("document.accNumSeparator");
136

    
137
		this.connection = conn;
138
		this.parserName = parserName;
139
		this.processingDTD = false;
140
		this.elementStack = new Stack();
141

    
142
		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

    
153
		// 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
		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
	}
167

    
168
// NOT USED
169
// /**
170
// * Construct an instance of the AccessControlList class.
171
//   * 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
  
188
  /* Set up the SAX parser for reading the XML serialized ACL */
189
  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
    // Turn off validation
197
    parser.setFeature("http://xml.org/sax/features/validation", true);
198
      
199
    // Set Handlers in the parser
200
    // Set the ContentHandler to this instance
201
    parser.setContentHandler((ContentHandler)this);
202

    
203
    // make a DBEntityResolver instance
204
    // Set the EntityReslover to DBEntityResolver instance
205
    EntityResolver eresolver = new DBEntityResolver(connection,this,null);
206
    parser.setEntityResolver((EntityResolver)eresolver);
207

    
208
    // Set the ErrorHandler to this instance
209
    parser.setErrorHandler((ErrorHandler)this);
210

    
211
    return parser; 
212
  }
213
  
214
  /**
215
   * Callback method used by the SAX Parser when beginning of the document
216
   */
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
      this.aclObjects = getACLObjects(aclid);
223

    
224
      //delete all permissions for resources related to @aclid if any
225
      if ( aclid != null ) {
226
        deletePermissionsForRelatedResources(aclid);
227
      }
228
    } catch (SQLException sqle) {
229
      throw new SAXException(sqle);
230
    }
231
  }
232
  
233
  /**
234
   * Callback method used by the SAX Parser when the start tag of an 
235
   * 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
    instarttag = true;
243
    if(localName.equals("allow"))
244
    {
245
      tagName = "allow";
246
    }
247
    else if(localName.equals("deny"))
248
    {
249
      tagName = "deny";
250
    }
251
    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
    if ( currentNode.getTagName().equals("acl") ) {
259
      permOrder = currentNode.getAttribute("order");
260
    //  publicAcc = currentNode.getAttribute("public");
261
    }
262
    elementStack.push(currentNode); 
263
  }
264

    
265
  /**
266
   * Callback method used by the SAX Parser when the text sequences of an 
267
   * xml stream are detected. Used in this context to parse and store
268
   * the acl information in class variables.
269
   */ 
270
  public void characters(char ch[], int start, int length)
271
         throws SAXException 
272
  {
273
    if(!instarttag)
274
    {
275
      return;
276
    }
277
    String inputString = new String(ch, start, length);
278
    inputString = inputString.trim(); 
279
    //System.out.println("==============inputString: " + inputString);
280
    BasicNode currentNode = (BasicNode)elementStack.peek(); 
281
    String currentTag = currentNode.getTagName();
282

    
283
      if (currentTag.equals("principal")) {
284

    
285
        principal.addElement(inputString);
286

    
287
      } else if (currentTag.equals("permission")) {
288

    
289
        if ( inputString.trim().toUpperCase().equals("READ") ) {
290
          permission = permission | READ;
291
        } else if ( inputString.trim().toUpperCase().equals("WRITE") ) {
292
          permission = permission | WRITE;
293
        } else if ( inputString.trim().toUpperCase().equals("CHANGEPERMISSION")) 
294
        {
295
          permission = permission | CHMOD;
296
        } else if ( inputString.trim().toUpperCase().equals("ALL") ) {
297
          permission = permission | ALL;
298
        }/*else{
299
          throw new SAXException("Unknown permission type: " + inputString);
300
        }*/
301

    
302
      } else if ( currentTag.equals("startDate") && beginTime == null ) {
303
        beginTime = inputString.trim();
304

    
305
      } else if ( currentTag.equals("stopDate") && endTime == null) {
306
        endTime = inputString.trim();
307

    
308
      } 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
      }
315
  }
316

    
317
  /**
318
   * Callback method used by the SAX Parser when the end tag of an 
319
   * 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
    instarttag = false;
326
    BasicNode leaving = (BasicNode)elementStack.pop();
327
    String leavingTagName = leaving.getTagName();
328

    
329
    if ( leavingTagName.equals("allow") ||
330
         leavingTagName.equals("deny")    ) {
331
      
332
      if ( permission > 0 ) {
333

    
334
        // insert into db calculated permission for the list of principals
335
        try {
336
          // 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
            //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
            //docid = MetaCatUtil.getDocIdFromAccessionNumber(docid);
345
            //System.out.println("The docid insert is!!!!!!!!!! "+ docid);
346
            insertPermissions(docid,leavingTagName);
347
          }
348
          
349
          // if acl is not in object list
350
          //should insert permission for aclid itself into database
351
          /*if (!aclObjects.contains(aclid))
352
          {
353
            DocumentIdentifier aclIdItself = new DocumentIdentifier(aclid);
354
            String aclIdString = aclIdItself.getIdentifier();
355
            insertPermissions(aclIdString,leavingTagName);
356
          }*/
357
          
358

    
359
        } catch (SQLException sqle) {
360
          throw new SAXException(sqle);
361
        } catch (Exception e) {
362
          throw new SAXException(e);
363
        }
364
      }
365

    
366
      // reset the allow/deny permission
367
      principal = new Vector();
368
      permission = 0;
369
      beginTime = null;
370
      endTime = null;
371
      ticketCount = 0;
372
    
373
    }
374

    
375
  }
376

    
377
  /** 
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
  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
   * SAX Handler that receives notification of the start of entities.
392
   * @param name name of the entity
393
   */
394
  public void startEntity(String name) throws SAXException {
395
    if (name.equals("[dtd]")) {
396
      processingDTD = true;
397
    }
398
  }
399

    
400
  /** 
401
   * SAX Handler that receives notification of the end of entities.
402
   * @param name name of the entity
403
   */
404
  public void endEntity(String name) throws SAXException {
405
    if (name.equals("[dtd]")) {
406
      processingDTD = false;
407
    }
408
  }
409

    
410
  /**
411
   * Get the document name.
412
   */
413
  public String getDocname() {
414
    return docname;
415
  }
416

    
417
  /**
418
   * Get the document processing state.
419
   */
420
  public boolean processingDTD() {
421
    return processingDTD;
422
  }
423
  
424
  /* Get all objects associated with @aclid from db.*/
425
  private Vector getACLObjects(String aclid) 
426
          throws SQLException 
427
  {
428
    Vector aclObjects = new Vector();
429
    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
                             "SELECT object FROM xml_relation " +
441
                             "WHERE subject = ? ");
442
      pstmt.setString(1,aclid);
443
      pstmt.execute();
444
      ResultSet rs = pstmt.getResultSet();
445
      boolean hasRows = rs.next();
446
      while (hasRows) {
447
        String object = rs.getString(1);
448
        //System.out.println("add acl object into vector !!!!!!!!!!!!!!!!!"+object);
449
        aclObjects.addElement(object);
450
        hasRows = rs.next();
451
      }//whil
452
    }
453
    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
    
470
    return aclObjects;
471
  }
472

    
473
  /* Delete from db all permission for resources related to @aclid if any.*/
474
  private void deletePermissionsForRelatedResources(String aclid) 
475
          throws SQLException 
476
  {
477
    //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
      logMetacat.debug("running sql: " + stmt.toString());
490
      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
  }
506

    
507
  /* 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
  private void insertPermissions(String docid, String permType ) 
513
                                            throws SQLException 
514
  {
515
    PreparedStatement pstmt = null;
516
    //DBConnection conn = null;
517
    //int serialNumber = -1;
518
    try {
519
      //Check out DBConnection
520
      //conn=DBConnectionPool.getDBConnection("AccessControlList.insertPerm");
521
      //serialNumber=conn.getCheckOutSerialNumber();
522
      
523
      pstmt = connection.prepareStatement(
524
              "INSERT INTO xml_access " + 
525
              "(docid, principal_name, permission, perm_type, perm_order," +
526
              "ticket_count, accessfileid) VALUES " +
527
              "(?,?,?,?,?,?,?)");
528
      // Increase DBConnection usage count
529
      connection.increaseUsageCount(1);
530
      // Bind the values to the query
531
      pstmt.setString(1, docid);
532
      pstmt.setInt(3, permission);
533
      pstmt.setString(4, permType);
534
      pstmt.setString(5, permOrder);
535
      pstmt.setString(7, aclid);
536
      if ( ticketCount > 0 ) {
537
        pstmt.setInt(6, ticketCount);
538
      } else {
539
        pstmt.setInt(6, 0);
540
      }
541
      
542
      //incrase usagecount for DBConnection
543
      //conn.increaseUsageCount(1);
544
      String prName;
545
      for ( int j = 0; j < principal.size(); j++ ) {
546
        prName = (String)principal.elementAt(j);
547
        pstmt.setString(2, prName);
548
        logMetacat.debug("running sql: " + pstmt.toString());
549
        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
          }
560
          throw new SQLException("Permission(s) " + txtValue(perm) + 
561
                    " for \"" + prName + "\" on document #" + docid +
562
                    " has/have been used with \"" + permOrderOpos + "\"");
563
        }
564
      */
565
      }
566
      pstmt.close();
567

    
568
    } catch (SQLException e) {
569
      throw new 
570
      SQLException("AccessControlList.insertPermissions(): " + e.getMessage());
571
    }
572
    finally
573
    {
574
      pstmt.close();
575
      //return the DBConnection
576
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
577
    }
578
  }
579

    
580
  /* 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
    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
            "SELECT permission FROM xml_access " +
595
            "WHERE docid = ? " +
596
            "AND principal_name = ? " +
597
            "AND perm_order NOT = ?");
598
      pstmt.setString(1, docid);
599
      pstmt.setString(2, principal);
600
      pstmt.setString(3, permOrder);
601
      logMetacat.debug("running sql: " + pstmt.toString());
602
      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
        pstmt.close();
625
      }
626
      finally
627
      {
628
        DBConnectionPool.returnDBConnection(conn, serialNumber);
629
      }
630
    }
631
    return 0;
632
  }
633

    
634
  /* Get the int value of READ, WRITE or ALL. */
635
  public static int intValue ( String permission )
636
  {
637
    if ( permission.equalsIgnoreCase("READ") ) {
638
      return READ;
639
    } else if ( permission.equalsIgnoreCase("WRITE") ) {
640
      return WRITE;
641
    } else if ( permission.equalsIgnoreCase("ALL") ) {
642
      return ALL;
643
    }
644
    
645
    return -1;
646
  }
647

    
648
  /* Get the text value of READ, WRITE or ALL. */
649
  public static String txtValue ( int permission )
650
  {
651
    StringBuffer txtPerm = new StringBuffer();
652
    if (permission == READ) {
653
      txtPerm.append("READ");
654
    } 
655
    if (permission == WRITE) {
656
      txtPerm.append("WRITE");
657
    }
658
    if (permission == ALL) {
659
      txtPerm.append("ALL");
660
    }
661

    
662
    return txtPerm.toString();
663
  }
664

    
665
  /**
666
    * 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
    * @param groups names of user's groups to which user belongs
672
    */
673
  public String getACL(String docid, String user, String[] groups) 
674
          throws SQLException, Exception
675
  {
676
    StringBuffer output = new StringBuffer();
677
    StringBuffer outTemp = new StringBuffer();
678
    String accDoctype = PropertyService.getProperty("xml.accessdoctype");
679
    String server = PropertyService.getProperty("server.name");
680
    String docurl = "metacat://" + server + "/?docid=" + docid;
681
    String systemID;
682
    boolean isOwned = false;
683
    boolean hasPermission = false;
684
    String publicAcc;
685
    
686
    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
    DBConnection conn = null;
702
    int serialNumber = -1;
703
    PreparedStatement pstmt = null;
704
    try {
705
      
706
      //check out DBConnection
707
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACL");
708
      serialNumber=conn.getCheckOutSerialNumber();
709
      
710
      isOwned = isOwned(docid, user);
711
      systemID = getSystemID((String)MetaCatUtil.
712
                                      getOptionList(accDoctype).elementAt(0));
713
      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
      
721
      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
              "FROM xml_access WHERE docid = ? " +
726
              "ORDER BY accessfileid, perm_order, perm_type, permission");
727
      // Bind the values to the query
728
      pstmt.setString(1, docid);
729
      logMetacat.debug("running sql: " + pstmt.toString());
730
      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
        // access files to which @user/@groups has "read" permission
746
        // is extracted
747
        if ( !isOwned ) {
748
          if ( !acfid.equals(acfid_prev) ) {
749
            acfid_prev = acfid;
750
            //hasPermission = this.hasPermission("READ",user,groups,acfid);
751
             PermissionController controller = new PermissionController(acfid);
752
             hasPermission = controller.hasPermission(user,groups,
753
                                            AccessControlInterface.READSTRING);
754
          }
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
      }
830

    
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
    }
854
    finally
855
    {
856
      try
857
      {
858
        pstmt.close();
859
      }
860
      finally
861
      {
862
        DBConnectionPool.returnDBConnection(conn, serialNumber);
863
      }
864
    }
865
  }
866
  
867
  /* Check if @user is owner of @docid from db conn. */
868
  private boolean isOwned(String docid, String user) throws SQLException {
869
    
870
    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
                                  "WHERE docid = ? " + 
880
                                  "AND user_owner = ?");
881
      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
  }
900

    
901
  /* 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
    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
                                  "WHERE docid = ?");
915
      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
    }
925
    finally
926
    {
927
      try
928
      {
929
        pstmt.close();
930
      }
931
      finally
932
      {
933
        DBConnectionPool.returnDBConnection(conn, serialNumber);
934
      }
935
    }
936
  }
937

    
938
  /* Get SystemID for @publicID from Metacat DB Catalog. */
939
  private String getSystemID(String publicID) throws SQLException, PropertyNotFoundException {
940

    
941
		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
					systemID = SystemUtil.getContextURL() + systemID;
962
				}
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
}
(3-3/69)