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
 *    Release: @release@
9
 *
10
 *   '$Author: tao $'
11
 *     '$Date: 2003-07-23 11:58:03 -0700 (Wed, 23 Jul 2003) $'
12
 * '$Revision: 1750 $'
13
 *
14
 * This program is free software; you can redistribute it and/or modify
15
 * it under the terms of the GNU General Public License as published by
16
 * the Free Software Foundation; either version 2 of the License, or
17
 * (at your option) any later version.
18
 *
19
 * This program is distributed in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22
 * GNU General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software
26
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
27
 */
28

    
29
package edu.ucsb.nceas.metacat;
30

    
31
import java.io.*;
32
import java.sql.*;
33
import java.util.Stack;
34
import java.util.Vector;
35
import java.util.Hashtable;
36
import java.net.URL;
37
import java.net.MalformedURLException;
38

    
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
/** 
51
 * A Class that loads eml-access.xml file containing ACL for a metadata
52
 * document into relational DB. It extends DefaultHandler class to handle
53
 * SAX parsing events when processing the XML stream.
54
 */
55
public class AccessControlList extends DefaultHandler 
56
                               implements AccessControlInterface 
57
{
58

    
59
 
60
  private static String sysdate = MetaCatUtil.dbAdapter.getDateTimeFunction();
61
  private static String isnull = MetaCatUtil.dbAdapter.getIsNULLFunction();
62
  
63
  private DBConnection connection;
64
  private String parserName;
65
  private Stack elementStack;
66
  private String server;
67
  private String sep;
68
 
69
  private boolean	processingDTD;
70
  private String  user;
71
  private String[] groups;
72
  private String  aclid;
73
  private int     rev;
74
  private String 	docname;
75
  private String 	doctype;
76
  private String 	systemid;
77

    
78
  private String docurl;
79
  private Vector resourceURL;
80
  private Vector resourceID;
81
  private Vector principal;
82
  private int    permission;
83
  private String permType;
84
  private String permOrder;
85
//  private String publicAcc;
86
  private String beginTime;
87
  private String endTime;
88
  private int    ticketCount;
89
  private int    serverCode = 1;
90

    
91
  private Vector aclObjects = new Vector();
92
  private boolean instarttag = true;
93
  private String tagName = "";
94
  /**
95
   * Construct an instance of the AccessControlList class.
96
   * It is used by the permission check up from DBQuery or DocumentImpl
97
   * and from "getaccesscontrol" action
98
   *
99
   * @param conn the JDBC connection where acl info is get
100
   */
101
  public AccessControlList(DBConnection conn) throws SQLException
102
  {
103
    this.connection = conn;
104
  }
105
  
106

    
107
  
108

    
109
  /**
110
   * Construct an instance of the AccessControlList class.
111
   * It parse acl file and loads acl data into db connection.
112
   *
113
   * @param conn the JDBC connection where acl data are loaded
114
   * @param aclid the Accession# of the document with the acl data
115
   * @param acl the acl file containing acl data
116
   * @param user the user connected to MetaCat servlet and owns the document
117
   * @param groups the groups to which user belongs
118
   * @param serverCode the serverid from xml_replication on which this document
119
   *        resides.
120
   */
121
  public AccessControlList(DBConnection conn, String aclid, //Reader acl,
122
                           String user, String[] groups, int serverCode)
123
                  throws SAXException, IOException, McdbException
124
  {
125
    String parserName = MetaCatUtil.getOption("saxparser");
126
    this.server = MetaCatUtil.getOption("server");
127
    this.sep = MetaCatUtil.getOption("accNumSeparator");
128

    
129
    this.connection = conn;
130
    this.parserName = parserName;
131
    this.processingDTD = false;
132
    this.elementStack = new Stack();
133
    
134
    this.user = user;
135
    this.groups = groups;
136
    this.aclid = aclid;
137
    this.resourceURL = new Vector();
138
    this.resourceID = new Vector();
139
    this.principal = new Vector();
140
    this.permission = 0;
141
    this.ticketCount = 0;
142
  //  this.publicAcc = null;
143
    this.serverCode = serverCode;
144
    
145
    // read the access file from db connection
146
    DocumentImpl acldoc = new DocumentImpl(aclid);
147
    String acl = acldoc.toString();
148
    this.rev = acldoc.getRev();
149

    
150
    // Initialize the parse
151
    XMLReader parser = initializeParser();
152
    // parse the access file and write the info to xml_access
153
    parser.parse(new InputSource(new StringReader(acl)));
154
    
155
  }
156

    
157
// NOT USED
158
//  /**
159
//   * Construct an instance of the AccessControlList class.
160
//   * It parses eml-access file and loads acl data into db connection.
161
//   * It is used from command line execution.
162
//   *
163
//   * @param conn the JDBC connection where acl data are loaded
164
//   * @param docid the Accession# of the document with the acl data
165
//   * @param aclfilename the name of acl file containing acl data
166
//   * @param user the user connected to MetaCat servlet and owns the document
167
//   * @param groups the groups to which user belongs
168
//   */
169
//  public AccessControlList( Connection conn, String aclid, String aclfilename,
170
//                           String user, String[] groups )
171
//                  throws SAXException, IOException, McdbException
172
//  {
173
//    this(conn, aclid, new FileReader(new File(aclfilename).toString()), 
174
//         user, groups, 1);
175
//  }
176
  
177
  /* Set up the SAX parser for reading the XML serialized ACL */
178
  private XMLReader initializeParser() throws SAXException 
179
  {
180
    XMLReader parser = null;
181

    
182
    // Get an instance of the parser
183
    parser = XMLReaderFactory.createXMLReader(parserName);
184

    
185
    // Turn off validation
186
    parser.setFeature("http://xml.org/sax/features/validation", true);
187
      
188
    // Set Handlers in the parser
189
    // Set the ContentHandler to this instance
190
    parser.setContentHandler((ContentHandler)this);
191

    
192
    // make a DBEntityResolver instance
193
    // Set the EntityReslover to DBEntityResolver instance
194
    EntityResolver eresolver = new DBEntityResolver(connection,this,null);
195
    parser.setEntityResolver((EntityResolver)eresolver);
196

    
197
    // Set the ErrorHandler to this instance
198
    parser.setErrorHandler((ErrorHandler)this);
199

    
200
    return parser; 
201
  }
202
  
203
  /**
204
   * Callback method used by the SAX Parser when beginning of the document
205
   */
206
  public void startDocument() throws SAXException 
207
  {
208
    //delete all previously submitted permissions @ relations
209
    //this happens only on UPDATE of the access file
210
    try {
211
      this.aclObjects = getACLObjects(aclid);
212

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

    
254
  /**
255
   * Callback method used by the SAX Parser when the text sequences of an 
256
   * xml stream are detected. Used in this context to parse and store
257
   * the acl information in class variables.
258
   */ 
259
  public void characters(char ch[], int start, int length)
260
         throws SAXException 
261
  {
262
    if(!instarttag)
263
    {
264
      return;
265
    }
266
    String inputString = new String(ch, start, length);
267
    inputString = inputString.trim(); 
268
    //System.out.println("==============inputString: " + inputString);
269
    BasicNode currentNode = (BasicNode)elementStack.peek(); 
270
    String currentTag = currentNode.getTagName();
271

    
272
      if (currentTag.equals("principal")) {
273

    
274
        principal.addElement(inputString);
275

    
276
      } else if (currentTag.equals("permission")) {
277

    
278
        if ( inputString.trim().toUpperCase().equals("READ") ) {
279
          permission = permission | READ;
280
        } else if ( inputString.trim().toUpperCase().equals("WRITE") ) {
281
          permission = permission | WRITE;
282
        } else if ( inputString.trim().toUpperCase().equals("CHANGEPERMISSION")) 
283
        {
284
          permission = permission | CHMOD;
285
        } else if ( inputString.trim().toUpperCase().equals("ALL") ) {
286
          permission = permission | ALL;
287
        }/*else{
288
          throw new SAXException("Unknown permission type: " + inputString);
289
        }*/
290

    
291
      } else if ( currentTag.equals("startDate") && beginTime == null ) {
292
        beginTime = inputString.trim();
293

    
294
      } else if ( currentTag.equals("stopDate") && endTime == null) {
295
        endTime = inputString.trim();
296

    
297
      } else if (currentTag.equals("ticketCount") && ticketCount == 0 ) {
298
        try {
299
          ticketCount = (new Integer(inputString.trim())).intValue();
300
        } catch (NumberFormatException nfe) {
301
          throw new SAXException("Wrong integer format for:" + inputString);
302
        }
303
      }
304
  }
305

    
306
  /**
307
   * Callback method used by the SAX Parser when the end tag of an 
308
   * element is detected. Used in this context to parse and store
309
   * the acl information in class variables.
310
   */
311
  public void endElement (String uri, String localName, String qName)
312
         throws SAXException 
313
  {
314
    instarttag = false;
315
    BasicNode leaving = (BasicNode)elementStack.pop();
316
    String leavingTagName = leaving.getTagName();
317

    
318
    if ( leavingTagName.equals("allow") ||
319
         leavingTagName.equals("deny")    ) {
320
      
321
      if ( permission > 0 ) {
322

    
323
        // insert into db calculated permission for the list of principals
324
        try {
325
          // go through the objects in xml_relation about this acl doc
326
          for (int i=0; i < aclObjects.size(); i++) {
327
            // docid of the current object
328
            String docid = (String)aclObjects.elementAt(i); 
329
            DocumentIdentifier docID = new DocumentIdentifier(docid);
330
            docid = docID.getIdentifier();
331
            insertPermissions(docid,leavingTagName);
332
          }
333
          
334
          // if acl is not in object list
335
          //should insert permission for aclid itself into database
336
          /*if (!aclObjects.contains(aclid))
337
          {
338
            DocumentIdentifier aclIdItself = new DocumentIdentifier(aclid);
339
            String aclIdString = aclIdItself.getIdentifier();
340
            insertPermissions(aclIdString,leavingTagName);
341
          }*/
342
          
343

    
344
        } catch (SQLException sqle) {
345
          throw new SAXException(sqle);
346
        } catch (Exception e) {
347
          throw new SAXException(e);
348
        }
349
      }
350

    
351
      // reset the allow/deny permission
352
      principal = new Vector();
353
      permission = 0;
354
      beginTime = null;
355
      endTime = null;
356
      ticketCount = 0;
357
    
358
    }
359

    
360
  }
361

    
362
  /** 
363
    * SAX Handler that receives notification of DOCTYPE. Sets the DTD.
364
    * @param name name of the DTD
365
    * @param publicId Public Identifier of the DTD
366
    * @param systemId System Identifier of the DTD
367
    */
368
  public void startDTD(String name, String publicId, String systemId) 
369
              throws SAXException {
370
    docname = name;
371
    doctype = publicId;
372
    systemid = systemId;
373
  }
374

    
375
  /** 
376
   * SAX Handler that receives notification of the start of entities.
377
   * @param name name of the entity
378
   */
379
  public void startEntity(String name) throws SAXException {
380
    if (name.equals("[dtd]")) {
381
      processingDTD = true;
382
    }
383
  }
384

    
385
  /** 
386
   * SAX Handler that receives notification of the end of entities.
387
   * @param name name of the entity
388
   */
389
  public void endEntity(String name) throws SAXException {
390
    if (name.equals("[dtd]")) {
391
      processingDTD = false;
392
    }
393
  }
394

    
395
  /**
396
   * Get the document name.
397
   */
398
  public String getDocname() {
399
    return docname;
400
  }
401

    
402
  /**
403
   * Get the document processing state.
404
   */
405
  public boolean processingDTD() {
406
    return processingDTD;
407
  }
408
  
409
  /* Get all objects associated with @aclid from db.*/
410
  private Vector getACLObjects(String aclid) 
411
          throws SQLException 
412
  {
413
    Vector aclObjects = new Vector();
414
    DBConnection conn = null;
415
    int serialNumber = -1;
416
    PreparedStatement pstmt = null;
417
    try
418
    {
419
      //get connection from DBConnectionPool
420
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACLObject");
421
      serialNumber=conn.getCheckOutSerialNumber();
422
      
423
      // delete all acl records for resources related to @aclid if any
424
      pstmt = conn.prepareStatement(
425
                             "SELECT object FROM xml_relation " +
426
                             "WHERE subject = ? ");
427
      pstmt.setString(1,aclid);
428
      pstmt.execute();
429
      ResultSet rs = pstmt.getResultSet();
430
      boolean hasRows = rs.next();
431
      while (hasRows) {
432
        aclObjects.addElement(rs.getString(1));
433
        hasRows = rs.next();
434
      }//whil
435
    }
436
    catch (SQLException e)
437
    {
438
      throw e;
439
    }
440
    finally
441
    {
442
      try
443
      {
444
        pstmt.close();
445
      }
446
      finally
447
      {
448
        //retrun DBConnection
449
        DBConnectionPool.returnDBConnection(conn,serialNumber);
450
      }
451
    }
452
    
453
    return aclObjects;
454
  }
455

    
456
  /* Delete from db all permission for resources related to @aclid if any.*/
457
  private void deletePermissionsForRelatedResources(String aclid) 
458
          throws SQLException 
459
  {
460
    //DBConnection conn = null;
461
    //int serialNumber = -1;
462
    Statement stmt = null;
463
    try
464
    {
465
      //check out DBConenction
466
      //conn=DBConnectionPool.getDBConnection("AccessControlList.deltePerm");
467
      //serialNumber=conn.getCheckOutSerialNumber();
468
      // delete all acl records for resources related to @aclid if any
469
      stmt = connection.createStatement();
470
      // Increase DBConnection usage count
471
      connection.increaseUsageCount(1);
472
      stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + aclid 
473
                                                                      + "'");
474
      //increase usageCount!!!!!!
475
      //conn.increaseUsageCount(1);
476
    }
477
    catch (SQLException e)
478
    {
479
      throw e;
480
    }
481
    finally
482
    {
483
      stmt.close();
484
      //retrun DBConnection
485
      //DBConnectionPool.returnDBConnection(conn,serialNumber);
486
    }
487
  }
488

    
489
  /* Insert into db calculated permission for the list of principals 
490
   * The DBConnection it is use is class field. Because we want to keep rollback
491
   * features and it need use same connection
492
  */
493
  
494
  private void insertPermissions(String docid, String permType ) 
495
                                            throws SQLException 
496
  {
497
    PreparedStatement pstmt = null;
498
    //DBConnection conn = null;
499
    //int serialNumber = -1;
500
    try {
501
      //Check out DBConnection
502
      //conn=DBConnectionPool.getDBConnection("AccessControlList.insertPerm");
503
      //serialNumber=conn.getCheckOutSerialNumber();
504
      
505
      pstmt = connection.prepareStatement(
506
              "INSERT INTO xml_access " + 
507
              "(docid, principal_name, permission, perm_type, perm_order," +
508
              "ticket_count, accessfileid) VALUES " +
509
              "(?,?,?,?,?,?,?)");
510
      MetaCatUtil.debugMessage("1, new sql for todate:================== ", 1);
511
      // Increase DBConnection usage count
512
      connection.increaseUsageCount(1);
513
      // Bind the values to the query
514
      pstmt.setString(1, docid);
515
      pstmt.setInt(3, permission);
516
      pstmt.setString(4, permType);
517
      pstmt.setString(5, permOrder);
518
      pstmt.setString(7, aclid);
519
      if ( ticketCount > 0 ) {
520
        pstmt.setString(6, "" + ticketCount);
521
      } else {
522
        pstmt.setString(6, null);
523
      }
524
      
525
      //incrase usagecount for DBConnection
526
      //conn.increaseUsageCount(1);
527
      String prName;
528
      for ( int j = 0; j < principal.size(); j++ ) {
529
        prName = (String)principal.elementAt(j);
530
        pstmt.setString(2, prName);
531
        pstmt.execute();
532
      /*    
533
        // check if there are conflict with permission's order
534
        String permOrderOpos = permOrder;
535
        int perm = getPermissions(permission, prName, docid, permOrder);
536
        if (  perm != 0 ) {
537
          if ( permOrder.equals("allowFirst") ) {
538
            permOrderOpos = "denyFirst";
539
          } else if ( permOrder.equals("denyFirst") ) {
540
            permOrderOpos = "allowFirst";
541
          }
542
          throw new SQLException("Permission(s) " + txtValue(perm) + 
543
                    " for \"" + prName + "\" on document #" + docid +
544
                    " has/have been used with \"" + permOrderOpos + "\"");
545
        }
546
      */
547
      }
548
      pstmt.close();
549

    
550
    } catch (SQLException e) {
551
      throw new 
552
      SQLException("AccessControlList.insertPermissions(): " + e.getMessage());
553
    }
554
    finally
555
    {
556
      pstmt.close();
557
      //return the DBConnection
558
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
559
    }
560
  }
561

    
562
  /* Get permissions with permission order different than @permOrder. */
563
  private int getPermissions(int permission, String principal,
564
                             String docid, String permOrder)
565
          throws SQLException 
566
  {
567
    PreparedStatement pstmt = null;
568
    DBConnection conn = null;
569
    int serialNumber = -1;
570
    try
571
    {
572
      //check out DBConnection
573
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPermissions");
574
      serialNumber=conn.getCheckOutSerialNumber();
575
      pstmt = conn.prepareStatement(
576
            "SELECT permission FROM xml_access " +
577
            "WHERE docid = ? " +
578
            "AND principal_name = ? " +
579
            "AND perm_order NOT = ?");
580
      pstmt.setString(1, docid);
581
      pstmt.setString(2, principal);
582
      pstmt.setString(3, permOrder);
583
      pstmt.execute();
584
      ResultSet rs = pstmt.getResultSet();
585
      boolean hasRow = rs.next();
586
      int perm = 0;
587
      while ( hasRow ) {
588
        perm = rs.getInt(1);
589
        perm = permission & perm;
590
        if ( perm != 0 ) {
591
          pstmt.close();
592
          return perm;
593
        }
594
        hasRow = rs.next();
595
      }
596
    }//try
597
    catch (SQLException e)
598
    {
599
      throw e;
600
    }
601
    finally
602
    {
603
      try
604
      {
605
        pstmt.close();
606
      }
607
      finally
608
      {
609
        DBConnectionPool.returnDBConnection(conn, serialNumber);
610
      }
611
    }
612
    return 0;
613
  }
614

    
615
  /* Get the int value of READ, WRITE or ALL. */
616
  public static int intValue ( String permission )
617
  {
618
    if ( permission.equalsIgnoreCase("READ") ) {
619
      return READ;
620
    } else if ( permission.equalsIgnoreCase("WRITE") ) {
621
      return WRITE;
622
    } else if ( permission.equalsIgnoreCase("ALL") ) {
623
      return ALL;
624
    }
625
    
626
    return -1;
627
  }
628

    
629
  /* Get the text value of READ, WRITE or ALL. */
630
  private String txtValue ( int permission )
631
  {
632
    StringBuffer txtPerm = new StringBuffer("\"");
633
    if ( (permission & READ) != 0 ) {
634
      txtPerm.append("read");
635
    } 
636
    if ( (permission & WRITE) != 0 ) {
637
      if ( txtPerm.length() > 0 ) txtPerm.append(",");
638
      txtPerm.append("write");
639
    }
640
    if ( (permission & ALL) != 0 ) {
641
      if ( txtPerm.length() > 0 ) txtPerm.append(",");
642
      txtPerm.append("all");
643
    }
644

    
645
    return txtPerm.append("\"").toString();
646
  }
647

    
648
  /**
649
    * Get Access Control List information for document from db connetion.
650
    * User or Group should have permissions for reading
651
    * access control information for a document specified by @docid.
652
    * @param docid document identifier which acl info to get
653
    * @param user name of user connected to Metacat system
654
    * @param groups names of user's groups to which user belongs
655
    */
656
  public String getACL(String docid, String user, String[] groups) 
657
          throws SQLException, Exception
658
  {
659
    StringBuffer output = new StringBuffer();
660
    StringBuffer outTemp = new StringBuffer();
661
    MetaCatUtil util = new MetaCatUtil();
662
    String accDoctype = util.getOption("accessdoctype");
663
    String server = util.getOption("server");
664
    String docurl = "metacat://" + server + "/?docid=" + docid;
665
    String systemID;
666
    boolean isOwned = false;
667
    boolean hasPermission = false;
668
    String publicAcc;
669
    
670
    String acfid = "";
671
    String acfid_prev = "";
672
    String principal;
673
    Vector principalArr = new Vector();
674
    int permission;
675
    int perm_prev = -1;
676
    String permType;
677
    String permOrder = "";
678
    String permOrder_prev = "";
679
    String beginTime = "";
680
    String begin_prev = "";
681
    String endTime = "";
682
    String end_prev = "";
683
    int ticketCount = -1;
684
    int ticket_prev = -1;
685
    DBConnection conn = null;
686
    int serialNumber = -1;
687
    PreparedStatement pstmt = null;
688
    try {
689
      
690
      //check out DBConnection
691
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACL");
692
      serialNumber=conn.getCheckOutSerialNumber();
693
      
694
      isOwned = isOwned(docid, user);
695
      systemID = getSystemID((String)MetaCatUtil.
696
                                      getOptionList(accDoctype).elementAt(0));
697
      publicAcc = getPublicAccess(docid);
698
        
699
      output.append("<?xml version=\"1.0\"?>\n");
700
      output.append("<!DOCTYPE acl PUBLIC \"" + accDoctype + "\" \"" +
701
                    systemID + "\">\n");
702
      output.append("<acl authSystem=\"\">\n");
703

    
704
      
705
      pstmt = conn.prepareStatement(
706
              "SELECT distinct accessfileid, principal_name, permission, " +
707
              "perm_type, perm_order, to_char(begin_time,'mm/dd/yyyy'), " +
708
              "to_char(end_time,'mm/dd/yyyy'), ticket_count " +
709
              "FROM xml_access WHERE docid = ? " +
710
              "ORDER BY accessfileid, perm_order, perm_type, permission");
711
      // Bind the values to the query
712
      pstmt.setString(1, docid);
713
      pstmt.execute();
714
      ResultSet rs = pstmt.getResultSet();
715
      boolean hasRows = rs.next();
716
      while (hasRows) {
717

    
718
        acfid = rs.getString(1);
719
        principal = rs.getString(2);
720
        permission = rs.getInt(3);
721
        permType = rs.getString(4);
722
        permOrder = rs.getString(5);
723
        beginTime = rs.getString(6);
724
        endTime = rs.getString(7);
725
        ticketCount = rs.getInt(8);
726

    
727
        // if @docid is not owned by @user, only ACL info from that
728
        // access files to which @user/@groups has "read" permission
729
        // is extracted
730
        if ( !isOwned ) {
731
          if ( !acfid.equals(acfid_prev) ) {
732
            acfid_prev = acfid;
733
            //hasPermission = this.hasPermission("READ",user,groups,acfid);
734
             PermissionController controller = new PermissionController(acfid);
735
             hasPermission = controller.hasPermission(user,groups,
736
                                            AccessControlInterface.READSTRING);
737
          }
738
          if ( !hasPermission ) {
739
            rs.next();
740
            continue;
741
          }
742
        }
743
        
744
        // open <resource> tag
745
        if ( !permOrder.equals(permOrder_prev) ) {
746
          // close </resource> tag if any was opened 
747
          output.append(outTemp.toString());
748
          outTemp = new StringBuffer();
749
          if ( !permOrder_prev.equals("") ) {
750
            output.append("  </resource>\n");
751
          }
752
          output.append("  <resource order=\"" + permOrder + "\" public=\"" +
753
                        publicAcc + "\">\n");
754
          output.append("    <resourceIdentifier>" + docurl + 
755
                        "</resourceIdentifier>\n");
756
          permOrder_prev = permOrder;
757
        }
758
        
759
        // close </allow> or </deny> tag then open new one
760
        if ( permission != perm_prev ||
761
             (endTime == null) && (end_prev != null) ||
762
             (beginTime == null) && (begin_prev != null) ||
763
             endTime != null && !endTime.equals(end_prev)  ||
764
             beginTime != null && !beginTime.equals(begin_prev) ||
765
             ticketCount != ticket_prev )  {
766
          output.append(outTemp.toString());
767
          outTemp = new StringBuffer();
768
          principalArr.removeAllElements();
769
          output.append("    <" + permType + ">\n");
770
        }
771
        
772
        // put all principals here for the same 
773
        // permission, duration and ticket_count
774
        if ( !principalArr.contains(principal) ) {
775
          principalArr.addElement(principal);
776
          output.append("      <principal>" + principal + "</principal>\n");
777
        } 
778
        
779
        // prepare <permission> tags, <duration> and <ticketCount>
780
        // if any to put within <allow> (<deny>) by next cicle
781
        if ( permission != perm_prev || 
782
             (endTime == null) && (end_prev != null) ||
783
             (beginTime == null) && (begin_prev != null) ||
784
             endTime != null && !endTime.equals(end_prev)  ||
785
             beginTime != null && !beginTime.equals(begin_prev) ||
786
             ticketCount != ticket_prev )  {
787
          if ( (permission & READ) != 0 ) {
788
            outTemp.append("      <permission>read</permission>\n");
789
          }
790
          if ( (permission & WRITE) != 0 ) {
791
            outTemp.append("      <permission>write</permission>\n");
792
          }
793
          if ( (permission & ALL) != 0 ) {
794
            outTemp.append("      <permission>all</permission>\n");
795
          }
796
          if ( (beginTime != null) || (endTime != null) ) {
797
            outTemp.append("      <duration>" + beginTime + " " + endTime +
798
                          "</duration>\n");
799
          }
800
          if ( ticketCount > 0 ) {
801
            outTemp.append("      <ticketCount>" + ticketCount + 
802
                          "</ticketCount>\n");
803
          }
804
          outTemp.append("    </" + permType + ">\n");
805
          perm_prev = permission;
806
          ticket_prev = ticketCount;
807
          begin_prev = beginTime;
808
          end_prev = endTime;
809
        }
810
        
811
        hasRows = rs.next();
812
      }
813

    
814
      // close <allow> or <deny> if anything left in outTemp var
815
      output.append(outTemp.toString());
816

    
817
      // If there are no any acl info for @docid accessible by @user/@group,
818
      // extract only the following information
819
      if ( permOrder.equals("") ) {
820
        output.append("  <resource public=\"" + publicAcc + "\">\n");
821
        output.append("    <resourceIdentifier>" + docurl + 
822
                      "</resourceIdentifier>\n");
823
      }
824
      
825
      // always close them
826
      output.append("  </resource>\n");
827
      output.append("</acl>\n");
828
      
829
      pstmt.close();
830

    
831
      return output.toString();
832

    
833
    } catch (SQLException e) {
834
      throw new 
835
      SQLException("AccessControlList.getACL(). " + e.getMessage());
836
    }
837
    finally
838
    {
839
      try
840
      {
841
        pstmt.close();
842
      }
843
      finally
844
      {
845
        DBConnectionPool.returnDBConnection(conn, serialNumber);
846
      }
847
    }
848
  }
849
  
850
  /* Check if @user is owner of @docid from db conn. */
851
  private boolean isOwned(String docid, String user) throws SQLException {
852
    
853
    PreparedStatement pstmt = null;
854
    DBConnection conn = null;
855
    int serialNumber = -1;
856
    try
857
    {
858
      //check out DBConnection
859
      conn=DBConnectionPool.getDBConnection("AccessControlList.isOwned");
860
      serialNumber=conn.getCheckOutSerialNumber();
861
      pstmt = conn.prepareStatement("SELECT 'x' FROM xml_documents " +
862
                                  "WHERE docid = ? " + 
863
                                  "AND user_owner = ?");
864
      pstmt.setString(1, docid);
865
      pstmt.setString(2, user);
866
      pstmt.execute();
867
      ResultSet rs = pstmt.getResultSet();
868
      boolean hasRow = rs.next();
869
      return hasRow;
870
    }
871
    finally
872
    {
873
      try
874
      {
875
        pstmt.close();
876
      }
877
      finally
878
      {
879
        DBConnectionPool.returnDBConnection(conn, serialNumber);
880
      }
881
    }
882
  }
883

    
884
  /* Get the flag for public "read" access for @docid from db conn. */
885
  private String getPublicAccess(String docid) throws SQLException {
886
    
887
    int publicAcc = 0;
888
    PreparedStatement pstmt = null;
889
    DBConnection conn = null;
890
    int serialNumber = -1;
891
    try
892
    {
893
      //check out DBConnection
894
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPublicAcces");
895
      serialNumber=conn.getCheckOutSerialNumber();
896
      pstmt = conn.prepareStatement("SELECT public_access FROM xml_documents " +
897
                                  "WHERE docid = ?");
898
      pstmt.setString(1, docid);
899
      pstmt.execute();
900
      ResultSet rs = pstmt.getResultSet();
901
      boolean hasRow = rs.next();
902
      if ( hasRow ) {
903
        publicAcc = rs.getInt(1);
904
      }
905
    
906
      return (publicAcc == 1) ? "yes" : "no";
907
    }
908
    finally
909
    {
910
      try
911
      {
912
        pstmt.close();
913
      }
914
      finally
915
      {
916
        DBConnectionPool.returnDBConnection(conn, serialNumber);
917
      }
918
    }
919
  }
920

    
921
  /* Get SystemID for @publicID from Metacat DB Catalog. */
922
  private String getSystemID(String publicID) throws SQLException {
923
    
924
    String systemID = "";
925
    PreparedStatement pstmt = null;
926
    DBConnection conn = null;
927
    int serialNumber = -1;
928
    
929
    try
930
    {
931
      //check out DBConnection
932
      conn=DBConnectionPool.getDBConnection("AccessControlList.getSystemID");
933
      serialNumber=conn.getCheckOutSerialNumber();
934
    
935
      pstmt = conn.prepareStatement("SELECT system_id FROM xml_catalog " +
936
                                  "WHERE entry_type = 'DTD' " + 
937
                                  "AND public_id = ?");
938
      pstmt.setString(1, publicID);
939
      pstmt.execute();
940
      ResultSet rs = pstmt.getResultSet();
941
      boolean hasRow = rs.next();
942
      if ( hasRow ) {
943
        systemID = rs.getString(1);
944
      }
945
    
946
      return systemID;
947
    }//try
948
    finally
949
    {
950
      
951
      try
952
      {
953
        pstmt.close();
954
      }
955
      finally
956
      {
957
        DBConnectionPool.returnDBConnection(conn, serialNumber);
958
      }
959
    }//finally
960
  }
961

    
962
}
(3-3/57)