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: 2009-08-04 14:32:58 -0700 (Tue, 04 Aug 2009) $'
11
 * '$Revision: 5015 $'
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.database.DBConnection;
51
import edu.ucsb.nceas.metacat.database.DBConnectionPool;
52
import edu.ucsb.nceas.metacat.database.DatabaseService;
53
import edu.ucsb.nceas.metacat.service.PropertyService;
54
import edu.ucsb.nceas.metacat.util.MetacatUtil;
55
import edu.ucsb.nceas.metacat.util.SystemUtil;
56
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
57

    
58
/** 
59
 * A Class that loads eml-access.xml file containing ACL for a metadata
60
 * document into relational DB. It extends DefaultHandler class to handle
61
 * SAX parsing events when processing the XML stream.
62
 */
63
public class AccessControlList extends DefaultHandler 
64
                               implements AccessControlInterface 
65
{
66

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

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

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

    
117
  
118

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

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

    
144
		this.user = user;
145
		this.groups = groups;
146
		this.aclid = aclid;
147
		this.resourceURL = new Vector();
148
		this.resourceID = new Vector();
149
		this.principal = new Vector();
150
		this.permission = 0;
151
		this.ticketCount = 0;
152
		// this.publicAcc = null;
153
		this.serverCode = serverCode;
154

    
155
		// read the access file from db connection
156
		DocumentImpl acldoc = new DocumentImpl(aclid + sep + rev);
157
		String acl = acldoc.toString();
158
		this.rev = acldoc.getRev();
159

    
160
		// Initialize the parse
161
		XMLReader parser = initializeParser();
162
		// parse the access file and write the info to xml_access
163
		if (acl != null) {
164
			parser.parse(new InputSource(new StringReader(acl)));
165
		} else {
166
			throw new McdbException("Could not retrieve access control list for:  " + aclid + sep + rev);
167
		}
168
	}
169

    
170
// NOT USED
171
// /**
172
// * Construct an instance of the AccessControlList class.
173
//   * It parses eml-access file and loads acl data into db connection.
174
//   * It is used from command line execution.
175
//   *
176
//   * @param conn the JDBC connection where acl data are loaded
177
//   * @param docid the Accession# of the document with the acl data
178
//   * @param aclfilename the name of acl file containing acl data
179
//   * @param user the user connected to MetaCat servlet and owns the document
180
//   * @param groups the groups to which user belongs
181
//   */
182
//  public AccessControlList( Connection conn, String aclid, String aclfilename,
183
//                           String user, String[] groups )
184
//                  throws SAXException, IOException, McdbException
185
//  {
186
//    this(conn, aclid, new FileReader(new File(aclfilename).toString()), 
187
//         user, groups, 1);
188
//  }
189
  
190
  /* Set up the SAX parser for reading the XML serialized ACL */
191
  private XMLReader initializeParser() throws SAXException 
192
  {
193
    XMLReader parser = null;
194

    
195
    // Get an instance of the parser
196
    parser = XMLReaderFactory.createXMLReader(parserName);
197

    
198
    // Turn off validation
199
    parser.setFeature("http://xml.org/sax/features/validation", true);
200
      
201
    // Set Handlers in the parser
202
    // Set the ContentHandler to this instance
203
    parser.setContentHandler((ContentHandler)this);
204

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

    
210
    // Set the ErrorHandler to this instance
211
    parser.setErrorHandler((ErrorHandler)this);
212

    
213
    return parser; 
214
  }
215
  
216
  /**
217
   * Callback method used by the SAX Parser when beginning of the document
218
   */
219
  public void startDocument() throws SAXException 
220
  {
221
    //delete all previously submitted permissions @ relations
222
    //this happens only on UPDATE of the access file
223
    try {
224
      this.aclObjects = getACLObjects(aclid);
225

    
226
      //delete all permissions for resources related to @aclid if any
227
      if ( aclid != null ) {
228
        deletePermissionsForRelatedResources(aclid);
229
      }
230
    } catch (SQLException sqle) {
231
      throw new SAXException(sqle);
232
    }
233
  }
234
  
235
  /**
236
   * Callback method used by the SAX Parser when the start tag of an 
237
   * element is detected. Used in this context to parse and store
238
   * the acl information in class variables.
239
   */
240
  public void startElement (String uri, String localName, 
241
                            String qName, Attributes atts) 
242
         throws SAXException 
243
  {
244
    instarttag = true;
245
    if(localName.equals("allow"))
246
    {
247
      tagName = "allow";
248
    }
249
    else if(localName.equals("deny"))
250
    {
251
      tagName = "deny";
252
    }
253
    BasicNode currentNode = new BasicNode(localName);
254
    if (atts != null) {
255
      int len = atts.getLength();
256
      for (int i = 0; i < len; i++) {
257
        currentNode.setAttribute(atts.getLocalName(i), atts.getValue(i));
258
      }
259
    }
260
    if ( currentNode.getTagName().equals("acl") ) {
261
      permOrder = currentNode.getAttribute("order");
262
    //  publicAcc = currentNode.getAttribute("public");
263
    }
264
    elementStack.push(currentNode); 
265
  }
266

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

    
285
      if (currentTag.equals("principal")) {
286

    
287
        principal.addElement(inputString);
288

    
289
      } else if (currentTag.equals("permission")) {
290

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

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

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

    
310
      } else if (currentTag.equals("ticketCount") && ticketCount == 0 ) {
311
        try {
312
          ticketCount = (new Integer(inputString.trim())).intValue();
313
        } catch (NumberFormatException nfe) {
314
          throw new SAXException("Wrong integer format for:" + inputString);
315
        }
316
      }
317
  }
318

    
319
  /**
320
   * Callback method used by the SAX Parser when the end tag of an 
321
   * element is detected. Used in this context to parse and store
322
   * the acl information in class variables.
323
   */
324
  public void endElement (String uri, String localName, String qName)
325
         throws SAXException 
326
  {
327
    instarttag = false;
328
    BasicNode leaving = (BasicNode)elementStack.pop();
329
    String leavingTagName = leaving.getTagName();
330

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

    
336
        // insert into db calculated permission for the list of principals
337
        try {
338
          // go through the objects in xml_relation about this acl doc
339
          for (int i=0; i < aclObjects.size(); i++) {
340
            // docid of the current object
341
            String docid = (String)aclObjects.elementAt(i); 
342
            //DocumentIdentifier docID = new DocumentIdentifier(docid);
343
            //docid = docID.getIdentifier();
344
            // the docid get here has revision number, so we need to 
345
            // remove it.
346
            //docid = MetacatUtil.getDocIdFromAccessionNumber(docid);
347
            //System.out.println("The docid insert is!!!!!!!!!! "+ docid);
348
            insertPermissions(docid,leavingTagName);
349
          }
350
          
351
          // if acl is not in object list
352
          //should insert permission for aclid itself into database
353
          /*if (!aclObjects.contains(aclid))
354
          {
355
            DocumentIdentifier aclIdItself = new DocumentIdentifier(aclid);
356
            String aclIdString = aclIdItself.getIdentifier();
357
            insertPermissions(aclIdString,leavingTagName);
358
          }*/
359
          
360

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

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

    
377
  }
378

    
379
  /** 
380
    * SAX Handler that receives notification of DOCTYPE. Sets the DTD.
381
    * @param name name of the DTD
382
    * @param publicId Public Identifier of the DTD
383
    * @param systemId System Identifier of the DTD
384
    */
385
  public void startDTD(String name, String publicId, String systemId) 
386
              throws SAXException {
387
    docname = name;
388
    doctype = publicId;
389
    systemid = systemId;
390
  }
391

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

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

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

    
419
  /**
420
   * Get the document processing state.
421
   */
422
  public boolean processingDTD() {
423
    return processingDTD;
424
  }
425
  
426
  /* Get all objects associated with @aclid from db.*/
427
  private Vector getACLObjects(String aclid) 
428
          throws SQLException 
429
  {
430
    Vector aclObjects = new Vector();
431
    DBConnection conn = null;
432
    int serialNumber = -1;
433
    PreparedStatement pstmt = null;
434
    try
435
    {
436
      //get connection from DBConnectionPool
437
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACLObject");
438
      serialNumber=conn.getCheckOutSerialNumber();
439
      
440
      // delete all acl records for resources related to @aclid if any
441
      pstmt = conn.prepareStatement(
442
                             "SELECT object FROM xml_relation " +
443
                             "WHERE subject = ? ");
444
      pstmt.setString(1,aclid);
445
      pstmt.execute();
446
      ResultSet rs = pstmt.getResultSet();
447
      boolean hasRows = rs.next();
448
      while (hasRows) {
449
        String object = rs.getString(1);
450
        //System.out.println("add acl object into vector !!!!!!!!!!!!!!!!!"+object);
451
        aclObjects.addElement(object);
452
        hasRows = rs.next();
453
      }//whil
454
    }
455
    catch (SQLException e)
456
    {
457
      throw e;
458
    }
459
    finally
460
    {
461
      try
462
      {
463
        pstmt.close();
464
      }
465
      finally
466
      {
467
        //retrun DBConnection
468
        DBConnectionPool.returnDBConnection(conn,serialNumber);
469
      }
470
    }
471
    
472
    return aclObjects;
473
  }
474

    
475
  /* Delete from db all permission for resources related to @aclid if any.*/
476
  private void deletePermissionsForRelatedResources(String aclid) 
477
          throws SQLException 
478
  {
479
    //DBConnection conn = null;
480
    //int serialNumber = -1;
481
    Statement stmt = null;
482
    try
483
    {
484
      //check out DBConenction
485
      //conn=DBConnectionPool.getDBConnection("AccessControlList.deltePerm");
486
      //serialNumber=conn.getCheckOutSerialNumber();
487
      // delete all acl records for resources related to @aclid if any
488
      stmt = connection.createStatement();
489
      // Increase DBConnection usage count
490
      connection.increaseUsageCount(1);
491
      logMetacat.debug("running sql: " + stmt.toString());
492
      stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + aclid 
493
                                                                      + "'");
494
      //increase usageCount!!!!!!
495
      //conn.increaseUsageCount(1);
496
    }
497
    catch (SQLException e)
498
    {
499
      throw e;
500
    }
501
    finally
502
    {
503
      stmt.close();
504
      //retrun DBConnection
505
      //DBConnectionPool.returnDBConnection(conn,serialNumber);
506
    }
507
  }
508

    
509
  /* Insert into db calculated permission for the list of principals 
510
   * The DBConnection it is use is class field. Because we want to keep rollback
511
   * features and it need use same connection
512
  */
513
  
514
  private void insertPermissions(String docid, String permType ) 
515
                                            throws SQLException 
516
  {
517
    PreparedStatement pstmt = null;
518
    //DBConnection conn = null;
519
    //int serialNumber = -1;
520
    try {
521
      //Check out DBConnection
522
      //conn=DBConnectionPool.getDBConnection("AccessControlList.insertPerm");
523
      //serialNumber=conn.getCheckOutSerialNumber();
524
      
525
      pstmt = connection.prepareStatement(
526
              "INSERT INTO xml_access " + 
527
              "(docid, principal_name, permission, perm_type, perm_order," +
528
              "ticket_count, accessfileid) VALUES " +
529
              "(?,?,?,?,?,?,?)");
530
      // Increase DBConnection usage count
531
      connection.increaseUsageCount(1);
532
      // Bind the values to the query
533
      pstmt.setString(1, docid);
534
      pstmt.setInt(3, permission);
535
      pstmt.setString(4, permType);
536
      pstmt.setString(5, permOrder);
537
      pstmt.setString(7, aclid);
538
      if ( ticketCount > 0 ) {
539
        pstmt.setInt(6, ticketCount);
540
      } else {
541
        pstmt.setInt(6, 0);
542
      }
543
      
544
      //incrase usagecount for DBConnection
545
      //conn.increaseUsageCount(1);
546
      String prName;
547
      for ( int j = 0; j < principal.size(); j++ ) {
548
        prName = (String)principal.elementAt(j);
549
        pstmt.setString(2, prName);
550
        logMetacat.debug("running sql: " + pstmt.toString());
551
        pstmt.execute();
552
      /*    
553
        // check if there are conflict with permission's order
554
        String permOrderOpos = permOrder;
555
        int perm = getPermissions(permission, prName, docid, permOrder);
556
        if (  perm != 0 ) {
557
          if ( permOrder.equals("allowFirst") ) {
558
            permOrderOpos = "denyFirst";
559
          } else if ( permOrder.equals("denyFirst") ) {
560
            permOrderOpos = "allowFirst";
561
          }
562
          throw new SQLException("Permission(s) " + txtValue(perm) + 
563
                    " for \"" + prName + "\" on document #" + docid +
564
                    " has/have been used with \"" + permOrderOpos + "\"");
565
        }
566
      */
567
      }
568
      pstmt.close();
569

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

    
582
  /* Get permissions with permission order different than @permOrder. */
583
  private int getPermissions(int permission, String principal,
584
                             String docid, String permOrder)
585
          throws SQLException 
586
  {
587
    PreparedStatement pstmt = null;
588
    DBConnection conn = null;
589
    int serialNumber = -1;
590
    try
591
    {
592
      //check out DBConnection
593
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPermissions");
594
      serialNumber=conn.getCheckOutSerialNumber();
595
      pstmt = conn.prepareStatement(
596
            "SELECT permission FROM xml_access " +
597
            "WHERE docid = ? " +
598
            "AND principal_name = ? " +
599
            "AND perm_order NOT = ?");
600
      pstmt.setString(1, docid);
601
      pstmt.setString(2, principal);
602
      pstmt.setString(3, permOrder);
603
      logMetacat.debug("running sql: " + pstmt.toString());
604
      pstmt.execute();
605
      ResultSet rs = pstmt.getResultSet();
606
      boolean hasRow = rs.next();
607
      int perm = 0;
608
      while ( hasRow ) {
609
        perm = rs.getInt(1);
610
        perm = permission & perm;
611
        if ( perm != 0 ) {
612
          pstmt.close();
613
          return perm;
614
        }
615
        hasRow = rs.next();
616
      }
617
    }//try
618
    catch (SQLException e)
619
    {
620
      throw e;
621
    }
622
    finally
623
    {
624
      try
625
      {
626
        pstmt.close();
627
      }
628
      finally
629
      {
630
        DBConnectionPool.returnDBConnection(conn, serialNumber);
631
      }
632
    }
633
    return 0;
634
  }
635

    
636
    /* Get the int value of READ, WRITE, CHMOD or ALL. */
637
	public static int intValue(String permission) {
638
		int thisPermission = 0;
639
		if (permission.toUpperCase().contains(CHMODSTRING)) {
640
			thisPermission |= CHMOD;
641
		} 
642
		if (permission.toUpperCase().contains(READSTRING)) {
643
			thisPermission |= READ;
644
		} 
645
		if (permission.toUpperCase().contains(WRITESTRING)) {
646
			thisPermission |= WRITE;
647
		} 
648
		if (permission.toUpperCase().contains(ALLSTRING)) {
649
			thisPermission |= ALL;
650
		}
651

    
652
		if (thisPermission == 0) {
653
			return -1;
654
		} else {
655
			return thisPermission;
656
		}
657
	}
658
  
659
  /* Get the text value of READ, WRITE, CHMOD or ALL. */
660
	public static String txtValue(int permission) {
661
		StringBuffer txtPerm = new StringBuffer();
662
		
663
		if ((permission & ALL) == ALL) {
664
			return ALLSTRING;
665
		}		
666
		if ((permission & CHMOD) == CHMOD) {
667
			txtPerm.append(CHMODSTRING);
668
		}
669
		if ((permission & READ) == READ) {
670
			if (txtPerm.length() > 0)
671
				txtPerm.append(",");
672
			txtPerm.append(READSTRING);
673
		}
674
		if ((permission & WRITE) == WRITE) {
675
			if (txtPerm.length() > 0)
676
				txtPerm.append(",");
677
			txtPerm.append(WRITESTRING);
678
		}
679

    
680
		return txtPerm.toString();
681
	}
682

    
683
// /* Get the text value of READ, WRITE or ALL. */
684
//  public static String txtValue ( int permission )
685
//  {
686
//    StringBuffer txtPerm = new StringBuffer();
687
//    if (permission == READ) {
688
//      txtPerm.append("READ");
689
//    } 
690
//    if (permission == WRITE) {
691
//      txtPerm.append("WRITE");
692
//    }
693
//    if (permission == ALL) {
694
//      txtPerm.append("ALL");
695
//    }
696
//
697
//    return txtPerm.toString();
698
//  }
699

    
700
  /**
701
    * Get Access Control List information for document from db connetion.
702
    * User or Group should have permissions for reading
703
    * access control information for a document specified by @docid.
704
    * @param docid document identifier which acl info to get
705
    * @param user name of user connected to Metacat system
706
    * @param groups names of user's groups to which user belongs
707
    */
708
  public String getACL(String docid, String user, String[] groups) 
709
          throws SQLException, Exception
710
  {
711
    StringBuffer output = new StringBuffer();
712
    StringBuffer outTemp = new StringBuffer();
713
    String accDoctype = PropertyService.getProperty("xml.accessdoctype");
714
    String server = PropertyService.getProperty("server.name");
715
    String docurl = "metacat://" + server + "/?docid=" + docid;
716
    String systemID;
717
    boolean isOwned = false;
718
    boolean hasPermission = false;
719
    String publicAcc;
720
    
721
    String acfid = "";
722
    String acfid_prev = "";
723
    String principal;
724
    Vector principalArr = new Vector();
725
    int permission;
726
    int perm_prev = -1;
727
    String permType;
728
    String permOrder = "";
729
    String permOrder_prev = "";
730
    String beginTime = "";
731
    String begin_prev = "";
732
    String endTime = "";
733
    String end_prev = "";
734
    int ticketCount = -1;
735
    int ticket_prev = -1;
736
    DBConnection conn = null;
737
    int serialNumber = -1;
738
    PreparedStatement pstmt = null;
739
    try {
740
      
741
      //check out DBConnection
742
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACL");
743
      serialNumber=conn.getCheckOutSerialNumber();
744
      
745
      isOwned = isOwned(docid, user);
746
      systemID = getSystemID((String)MetacatUtil.
747
                                      getOptionList(accDoctype).elementAt(0));
748
      publicAcc = getPublicAccess(docid);
749
        
750
      output.append("<?xml version=\"1.0\"?>\n");
751
      output.append("<!DOCTYPE acl PUBLIC \"" + accDoctype + "\" \"" +
752
                    systemID + "\">\n");
753
      output.append("<acl authSystem=\"\">\n");
754

    
755
      
756
      pstmt = conn.prepareStatement(
757
              "SELECT distinct accessfileid, principal_name, permission, " +
758
              "perm_type, perm_order, to_char(begin_time,'mm/dd/yyyy'), " +
759
              "to_char(end_time,'mm/dd/yyyy'), ticket_count " +
760
              "FROM xml_access WHERE docid = ? " +
761
              "ORDER BY accessfileid, perm_order, perm_type, permission");
762
      // Bind the values to the query
763
      pstmt.setString(1, docid);
764
      logMetacat.debug("running sql: " + pstmt.toString());
765
      pstmt.execute();
766
      ResultSet rs = pstmt.getResultSet();
767
      boolean hasRows = rs.next();
768
      while (hasRows) {
769

    
770
        acfid = rs.getString(1);
771
        principal = rs.getString(2);
772
        permission = rs.getInt(3);
773
        permType = rs.getString(4);
774
        permOrder = rs.getString(5);
775
        beginTime = rs.getString(6);
776
        endTime = rs.getString(7);
777
        ticketCount = rs.getInt(8);
778

    
779
        // if @docid is not owned by @user, only ACL info from that
780
        // access files to which @user/@groups has "read" permission
781
        // is extracted
782
        if ( !isOwned ) {
783
          if ( !acfid.equals(acfid_prev) ) {
784
            acfid_prev = acfid;
785
            //hasPermission = this.hasPermission("READ",user,groups,acfid);
786
             PermissionController controller = new PermissionController(acfid);
787
             hasPermission = controller.hasPermission(user,groups,
788
                                            AccessControlInterface.READSTRING);
789
          }
790
          if ( !hasPermission ) {
791
            rs.next();
792
            continue;
793
          }
794
        }
795
        
796
        // open <resource> tag
797
        if ( !permOrder.equals(permOrder_prev) ) {
798
          // close </resource> tag if any was opened 
799
          output.append(outTemp.toString());
800
          outTemp = new StringBuffer();
801
          if ( !permOrder_prev.equals("") ) {
802
            output.append("  </resource>\n");
803
          }
804
          output.append("  <resource order=\"" + permOrder + "\" public=\"" +
805
                        publicAcc + "\">\n");
806
          output.append("    <resourceIdentifier>" + docurl + 
807
                        "</resourceIdentifier>\n");
808
          permOrder_prev = permOrder;
809
        }
810
        
811
        // close </allow> or </deny> tag then open new one
812
        if ( permission != perm_prev ||
813
             (endTime == null) && (end_prev != null) ||
814
             (beginTime == null) && (begin_prev != null) ||
815
             endTime != null && !endTime.equals(end_prev)  ||
816
             beginTime != null && !beginTime.equals(begin_prev) ||
817
             ticketCount != ticket_prev )  {
818
          output.append(outTemp.toString());
819
          outTemp = new StringBuffer();
820
          principalArr.removeAllElements();
821
          output.append("    <" + permType + ">\n");
822
        }
823
        
824
        // put all principals here for the same 
825
        // permission, duration and ticket_count
826
        if ( !principalArr.contains(principal) ) {
827
          principalArr.addElement(principal);
828
          output.append("      <principal>" + principal + "</principal>\n");
829
        } 
830
        
831
        // prepare <permission> tags, <duration> and <ticketCount>
832
        // if any to put within <allow> (<deny>) by next cicle
833
        if ( permission != perm_prev || 
834
             (endTime == null) && (end_prev != null) ||
835
             (beginTime == null) && (begin_prev != null) ||
836
             endTime != null && !endTime.equals(end_prev)  ||
837
             beginTime != null && !beginTime.equals(begin_prev) ||
838
             ticketCount != ticket_prev )  {
839
          if ( (permission & READ) != 0 ) {
840
            outTemp.append("      <permission>read</permission>\n");
841
          }
842
          if ( (permission & WRITE) != 0 ) {
843
            outTemp.append("      <permission>write</permission>\n");
844
          }
845
          if ( (permission & ALL) != 0 ) {
846
            outTemp.append("      <permission>all</permission>\n");
847
          }
848
          if ( (beginTime != null) || (endTime != null) ) {
849
            outTemp.append("      <duration>" + beginTime + " " + endTime +
850
                          "</duration>\n");
851
          }
852
          if ( ticketCount > 0 ) {
853
            outTemp.append("      <ticketCount>" + ticketCount + 
854
                          "</ticketCount>\n");
855
          }
856
          outTemp.append("    </" + permType + ">\n");
857
          perm_prev = permission;
858
          ticket_prev = ticketCount;
859
          begin_prev = beginTime;
860
          end_prev = endTime;
861
        }
862
        
863
        hasRows = rs.next();
864
      }
865

    
866
      // close <allow> or <deny> if anything left in outTemp var
867
      output.append(outTemp.toString());
868

    
869
      // If there are no any acl info for @docid accessible by @user/@group,
870
      // extract only the following information
871
      if ( permOrder.equals("") ) {
872
        output.append("  <resource public=\"" + publicAcc + "\">\n");
873
        output.append("    <resourceIdentifier>" + docurl + 
874
                      "</resourceIdentifier>\n");
875
      }
876
      
877
      // always close them
878
      output.append("  </resource>\n");
879
      output.append("</acl>\n");
880
      
881
      pstmt.close();
882

    
883
      return output.toString();
884

    
885
    } catch (SQLException e) {
886
      throw new 
887
      SQLException("AccessControlList.getACL(). " + e.getMessage());
888
    }
889
    finally
890
    {
891
      try
892
      {
893
        pstmt.close();
894
      }
895
      finally
896
      {
897
        DBConnectionPool.returnDBConnection(conn, serialNumber);
898
      }
899
    }
900
  }
901
  
902
  /* Check if @user is owner of @docid from db conn. */
903
  private boolean isOwned(String docid, String user) throws SQLException {
904
    
905
    PreparedStatement pstmt = null;
906
    DBConnection conn = null;
907
    int serialNumber = -1;
908
    try
909
    {
910
      //check out DBConnection
911
      conn=DBConnectionPool.getDBConnection("AccessControlList.isOwned");
912
      serialNumber=conn.getCheckOutSerialNumber();
913
      pstmt = conn.prepareStatement("SELECT 'x' FROM xml_documents " +
914
                                  "WHERE docid = ? " + 
915
                                  "AND user_owner = ?");
916
      pstmt.setString(1, docid);
917
      pstmt.setString(2, user);
918
      pstmt.execute();
919
      ResultSet rs = pstmt.getResultSet();
920
      boolean hasRow = rs.next();
921
      return hasRow;
922
    }
923
    finally
924
    {
925
      try
926
      {
927
        pstmt.close();
928
      }
929
      finally
930
      {
931
        DBConnectionPool.returnDBConnection(conn, serialNumber);
932
      }
933
    }
934
  }
935

    
936
  /* Get the flag for public "read" access for @docid from db conn. */
937
  private String getPublicAccess(String docid) throws SQLException {
938
    
939
    int publicAcc = 0;
940
    PreparedStatement pstmt = null;
941
    DBConnection conn = null;
942
    int serialNumber = -1;
943
    try
944
    {
945
      //check out DBConnection
946
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPublicAcces");
947
      serialNumber=conn.getCheckOutSerialNumber();
948
      pstmt = conn.prepareStatement("SELECT public_access FROM xml_documents " +
949
                                  "WHERE docid = ?");
950
      pstmt.setString(1, docid);
951
      pstmt.execute();
952
      ResultSet rs = pstmt.getResultSet();
953
      boolean hasRow = rs.next();
954
      if ( hasRow ) {
955
        publicAcc = rs.getInt(1);
956
      }
957
    
958
      return (publicAcc == 1) ? "yes" : "no";
959
    }
960
    finally
961
    {
962
      try
963
      {
964
        pstmt.close();
965
      }
966
      finally
967
      {
968
        DBConnectionPool.returnDBConnection(conn, serialNumber);
969
      }
970
    }
971
  }
972

    
973
  /* Get SystemID for @publicID from Metacat DB Catalog. */
974
  private String getSystemID(String publicID) throws SQLException, PropertyNotFoundException {
975

    
976
		String systemID = "";
977
		PreparedStatement pstmt = null;
978
		DBConnection conn = null;
979
		int serialNumber = -1;
980

    
981
		try {
982
			//check out DBConnection
983
			conn = DBConnectionPool.getDBConnection("AccessControlList.getSystemID");
984
			serialNumber = conn.getCheckOutSerialNumber();
985

    
986
			pstmt = conn.prepareStatement("SELECT system_id FROM xml_catalog "
987
					+ "WHERE entry_type = 'DTD' " + "AND public_id = ?");
988
			pstmt.setString(1, publicID);
989
			pstmt.execute();
990
			ResultSet rs = pstmt.getResultSet();
991
			boolean hasRow = rs.next();
992
			if (hasRow) {
993
				systemID = rs.getString(1);
994
				// system id may not have server url on front.  Add it if not.
995
				if (!systemID.startsWith("http://")) {
996
					systemID = SystemUtil.getContextURL() + systemID;
997
				}
998
			}
999

    
1000
			return systemID;
1001
		}//try
1002
		finally {
1003
			try {
1004
				pstmt.close();
1005
			} finally {
1006
				DBConnectionPool.returnDBConnection(conn, serialNumber);
1007
			}
1008
		}//finally
1009
	}
1010
  
1011
  public static void main(String[] args) {
1012
	  System.out.println("text value for CHMOD (" + CHMOD + "): " + txtValue(CHMOD));
1013
	  System.out.println("text value for READ: (" + READ + "): " + txtValue(READ));
1014
	  System.out.println("text value for WRITE: (" + WRITE + "): " + txtValue(WRITE));
1015
	  System.out.println("text value for ALL: (" + ALL + "): " + txtValue(ALL));
1016
	  int chmod_read = CHMOD|READ;
1017
	  System.out.println("text value for CHMOD|READ: (" + chmod_read + "): " + txtValue(CHMOD|READ));
1018
	  int chmod_write = CHMOD|WRITE;
1019
	  System.out.println("text value for CHMOD|WRITE: (" + chmod_write + "): " + txtValue(CHMOD|WRITE));
1020
	  int chmod_all = CHMOD|ALL;
1021
	  System.out.println("text value for CHMOD|ALL: (" + chmod_all + "): " + txtValue(CHMOD|ALL));
1022
	  int read_write = READ|WRITE;
1023
	  System.out.println("text value for READ|WRITE: (" + read_write + "): " + txtValue(READ|WRITE));
1024
	  int read_all = READ|ALL;
1025
	  System.out.println("text value for READ|ALL: (" + read_all + "): " + txtValue(READ|ALL));
1026
	  int write_all = WRITE|ALL;
1027
	  System.out.println("text value for WRITE|ALL: (" + write_all + "): " + txtValue(WRITE|ALL));
1028
	  int chmod_read_write = CHMOD|READ|WRITE;
1029
	  System.out.println("text value for CHMOD|READ|WRITE: (" + chmod_read_write + "): " + txtValue(CHMOD|READ|WRITE));
1030
	  int chmod_read_all = CHMOD|READ|ALL;
1031
	  System.out.println("text value for CHMOD|READ|ALL: (" + chmod_read_all + "): " + txtValue(CHMOD|READ|ALL));
1032
	  int chmod_write_all = CHMOD|WRITE|ALL;
1033
	  System.out.println("text value for CHMOD|WRITE|ALL: (" + chmod_write_all + "): " + txtValue(CHMOD|WRITE|ALL));
1034
	  int read_write_all = READ|WRITE|ALL;
1035
	  System.out.println("text value for READ|WRITE|ALL: (" + read_write_all + "): " + txtValue(READ|WRITE|ALL));
1036
	  int chmod_read_write_all = CHMOD|READ|WRITE|ALL;
1037
	  System.out.println("text value for CHMOD|READ|WRITE|ALL: (" + chmod_read_write_all + "): " + txtValue(CHMOD|READ|WRITE|ALL));
1038
	  System.out.println();
1039
	  System.out.println("int value for GOOBER: " + intValue("GOOBER"));
1040
	  System.out.println("int value for CHANGEPERMISSION: " + intValue("CHANGEPERMISSION"));
1041
	  System.out.println("int value for READ: " + intValue("READ"));
1042
	  System.out.println("int value for WRITE: " + intValue("WRITE"));
1043
	  System.out.println("int value for ALL: " + intValue("ALL"));
1044
	  System.out.println("int value for CHANGEPERMISSION,READ: " + intValue("CHANGEPERMISSION,READ"));
1045
	  System.out.println("int value for CHANGEPERMISSION,WRITE: " + intValue("CHANGEPERMISSION,WRITE"));
1046
	  System.out.println("int value for CHANGEPERMISSION,ALL: " + intValue("CHANGEPERMISSION,ALL"));
1047
	  System.out.println("int value for READ,WRITE: " + intValue("READ,WRITE"));
1048
	  System.out.println("int value for READ,ALL: " + intValue("READ,ALL"));
1049
	  System.out.println("int value for WRITE,ALL: " + intValue("WRITE,ALL"));
1050
	  System.out.println("int value for CHANGEPERMISSION,READ,WRITE: " + intValue("CHANGEPERMISSION,READ,WRITE"));
1051
	  System.out.println("int value for CHANGEPERMISSION,READ,ALL: " + intValue("CHANGEPERMISSION,READ,ALL"));
1052
	  System.out.println("int value for CHANGEPERMISSION,READ,ALL: " + intValue("CHANGEPERMISSION,WRITE,ALL"));
1053
	  System.out.println("int value for READ,WRITE,ALL: " + intValue("READ,WRITE,ALL"));
1054
	  System.out.println("int value for CHANGEPERMISSION,READ,WRITE,ALL: " + intValue("CHANGEPERMISSION,READ,WRITE,ALL"));
1055
  }
1056

    
1057
}
(3-3/63)