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-03-25 14:41:15 -0700 (Wed, 25 Mar 2009) $'
11
 * '$Revision: 4861 $'
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, CHMOD or ALL. */
635
	public static int intValue(String permission) {
636
		int thisPermission = 0;
637
		if (permission.toUpperCase().contains(CHMODSTRING)) {
638
			thisPermission |= CHMOD;
639
		} 
640
		if (permission.toUpperCase().contains(READSTRING)) {
641
			thisPermission |= READ;
642
		} 
643
		if (permission.toUpperCase().contains(WRITESTRING)) {
644
			thisPermission |= WRITE;
645
		} 
646
		if (permission.toUpperCase().contains(ALLSTRING)) {
647
			thisPermission |= ALL;
648
		}
649

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

    
678
		return txtPerm.toString();
679
	}
680

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

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

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

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

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

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

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

    
881
      return output.toString();
882

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

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

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

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

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

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

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

    
1055
}
(3-3/72)