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: 2002-03-04 20:34:47 -0800 (Mon, 04 Mar 2002) $'
12
 * '$Revision: 952 $'
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

    
57
  private static final int CHMOD = 1;
58
  private static final int WRITE = 2;
59
  private static final int READ = 4;
60
  private static final int ALL = 7;
61
  private static final String ALLOWFIRST="allowFirst";
62
  private static final String DENYFIRST="denyFirst";
63
  private static final String ALLOW="allow";
64
  private static final String DENY="deny";
65
  private static final String PUBLIC="public";
66
  private static String sysdate = MetaCatUtil.dbAdapter.getDateTimeFunction();
67
  private static String isnull = MetaCatUtil.dbAdapter.getIsNULLFunction();
68

    
69
  private Connection conn;
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
   * Construct an instance of the AccessControlList class.
102
   * It is used by the permission check up from DBQuery or DocumentImpl
103
   * and from "getaccesscontrol" action
104
   *
105
   * @param conn the JDBC connection where acl info is get
106
   */
107
  public AccessControlList(Connection conn) throws SQLException
108
  {
109
    this.conn = conn;
110
  }
111

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

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

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

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

    
185
    // Get an instance of the parser
186
    parser = XMLReaderFactory.createXMLReader(parserName);
187

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

    
195
    // make a DBEntityResolver instance
196
    // Set the EntityReslover to DBEntityResolver instance
197
    EntityResolver eresolver = new DBEntityResolver(conn,this,null);
198
    parser.setEntityResolver((EntityResolver)eresolver);
199

    
200
    // Set the ErrorHandler to this instance
201
    parser.setErrorHandler((ErrorHandler)this);
202

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

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

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

    
275
      if (currentTag.equals("principal")) {
276

    
277
        principal.addElement(inputString);
278

    
279
      } else if (currentTag.equals("permission")) {
280

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

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

    
297
      } else if ( currentTag.equals("stopDate") && endTime == null) {
298
        endTime = inputString.trim();
299

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

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

    
321
    if ( leavingTagName.equals("allow") ||
322
         leavingTagName.equals("deny")    ) {
323
      
324
      if ( permission > 0 ) {
325

    
326
        // insert into db calculated permission for the list of principals
327
        try {
328
          // go through the objects in xml_relation about this acl doc
329
          for (int i=0; i < aclObjects.size(); i++) {
330
            // docid of the current object
331
            String docid = (String)aclObjects.elementAt(i); 
332
            DocumentIdentifier docID = new DocumentIdentifier(docid);
333
            docid = docID.getIdentifier();
334
            insertPermissions(docid,leavingTagName);
335
          }
336

    
337
        } catch (SQLException sqle) {
338
          throw new SAXException(sqle);
339
        } catch (Exception e) {
340
          throw new SAXException(e);
341
        }
342
      }
343

    
344
      // reset the allow/deny permission
345
      principal = new Vector();
346
      permission = 0;
347
      beginTime = null;
348
      endTime = null;
349
      ticketCount = 0;
350
    
351
    }
352

    
353
  }
354

    
355
  /** 
356
    * SAX Handler that receives notification of DOCTYPE. Sets the DTD.
357
    * @param name name of the DTD
358
    * @param publicId Public Identifier of the DTD
359
    * @param systemId System Identifier of the DTD
360
    */
361
  public void startDTD(String name, String publicId, String systemId) 
362
              throws SAXException {
363
    docname = name;
364
    doctype = publicId;
365
    systemid = systemId;
366
  }
367

    
368
  /** 
369
   * SAX Handler that receives notification of the start of entities.
370
   * @param name name of the entity
371
   */
372
  public void startEntity(String name) throws SAXException {
373
    if (name.equals("[dtd]")) {
374
      processingDTD = true;
375
    }
376
  }
377

    
378
  /** 
379
   * SAX Handler that receives notification of the end of entities.
380
   * @param name name of the entity
381
   */
382
  public void endEntity(String name) throws SAXException {
383
    if (name.equals("[dtd]")) {
384
      processingDTD = false;
385
    }
386
  }
387

    
388
  /**
389
   * Get the document name.
390
   */
391
  public String getDocname() {
392
    return docname;
393
  }
394

    
395
  /**
396
   * Get the document processing state.
397
   */
398
  public boolean processingDTD() {
399
    return processingDTD;
400
  }
401
  
402
  /* Get all objects associated with @aclid from db.*/
403
  private Vector getACLObjects(String aclid) 
404
          throws SQLException 
405
  {
406
    Vector aclObjects = new Vector();
407
    // delete all acl records for resources related to @aclid if any
408
    PreparedStatement pstmt = conn.prepareStatement(
409
                             "SELECT object FROM xml_relation " +
410
                             "WHERE subject = ? ");
411
    pstmt.setString(1,aclid);
412
    pstmt.execute();
413
    ResultSet rs = pstmt.getResultSet();
414
    boolean hasRows = rs.next();
415
    while (hasRows) {
416
      aclObjects.addElement(rs.getString(1));
417
      hasRows = rs.next();
418
    }
419
    
420
    pstmt.close();
421
    
422
    return aclObjects;
423
  }
424

    
425
  /* Delete from db all permission for resources related to @aclid if any.*/
426
  private void deletePermissionsForRelatedResources(String aclid) 
427
          throws SQLException 
428
  {
429
    // delete all acl records for resources related to @aclid if any
430
    Statement stmt = conn.createStatement();
431
    stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + aclid + "'");
432
    stmt.close();
433
  }
434

    
435
  /* Insert into db calculated permission for the list of principals */
436
  private void insertPermissions(String docid, String permType ) 
437
          throws SQLException 
438
  {
439
    PreparedStatement pstmt;
440
    try {
441
      pstmt = conn.prepareStatement(
442
              "INSERT INTO xml_access " + 
443
              "(docid, principal_name, permission, perm_type, perm_order," +
444
              "begin_time,end_time,ticket_count, accessfileid) VALUES " +
445
              "(?,?,?,?,?,to_date(?,'mm/dd/yy'),to_date(?,'mm/dd/yy'),?,?)");
446
      // Bind the values to the query
447
      pstmt.setString(1, docid);
448
      pstmt.setInt(3, permission);
449
      pstmt.setString(4, permType);
450
      pstmt.setString(5, permOrder);
451
      pstmt.setString(6, beginTime);
452
      pstmt.setString(7, endTime);
453
      pstmt.setString(9, aclid);
454
      if ( ticketCount > 0 ) {
455
        pstmt.setString(8, "" + ticketCount);
456
      } else {
457
        pstmt.setString(8, null);
458
      }
459

    
460
      String prName;
461
      for ( int j = 0; j < principal.size(); j++ ) {
462
        prName = (String)principal.elementAt(j);
463
        pstmt.setString(2, prName);
464
        pstmt.execute();
465
      /*    
466
        // check if there are conflict with permission's order
467
        String permOrderOpos = permOrder;
468
        int perm = getPermissions(permission, prName, docid, permOrder);
469
        if (  perm != 0 ) {
470
          if ( permOrder.equals("allowFirst") ) {
471
            permOrderOpos = "denyFirst";
472
          } else if ( permOrder.equals("denyFirst") ) {
473
            permOrderOpos = "allowFirst";
474
          }
475
          throw new SQLException("Permission(s) " + txtValue(perm) + 
476
                    " for \"" + prName + "\" on document #" + docid +
477
                    " has/have been used with \"" + permOrderOpos + "\"");
478
        }
479
      */
480
      }
481
      pstmt.close();
482

    
483
    } catch (SQLException e) {
484
      throw new 
485
      SQLException("AccessControlList.insertPermissions(): " + e.getMessage());
486
    }
487
  }
488

    
489
  /* Get permissions with permission order different than @permOrder. */
490
  private int getPermissions(int permission, String principal,
491
                             String docid, String permOrder)
492
          throws SQLException 
493
  {
494
    PreparedStatement pstmt;
495
    pstmt = conn.prepareStatement(
496
            "SELECT permission FROM xml_access " +
497
            "WHERE docid = ? " +
498
            "AND principal_name = ? " +
499
            "AND perm_order NOT = ?");
500
    pstmt.setString(1, docid);
501
    pstmt.setString(2, principal);
502
    pstmt.setString(3, permOrder);
503
    pstmt.execute();
504
    ResultSet rs = pstmt.getResultSet();
505
    boolean hasRow = rs.next();
506
    int perm = 0;
507
    while ( hasRow ) {
508
      perm = rs.getInt(1);
509
      perm = permission & perm;
510
      if ( perm != 0 ) {
511
        pstmt.close();
512
        return perm;
513
      }
514
      hasRow = rs.next();
515
    }
516
    pstmt.close();
517
    return 0;
518
  }
519

    
520
  /* Get the int value of READ, WRITE or ALL. */
521
  private int intValue ( String permission )
522
  {
523
    if ( permission.equals("READ") ) {
524
      return READ;
525
    } else if ( permission.equals("WRITE") ) {
526
      return WRITE;
527
    } else if ( permission.equals("ALL") ) {
528
      return ALL;
529
    }
530
    
531
    return -1;
532
  }
533

    
534
  /* Get the text value of READ, WRITE or ALL. */
535
  private String txtValue ( int permission )
536
  {
537
    StringBuffer txtPerm = new StringBuffer("\"");
538
    if ( (permission & READ) != 0 ) {
539
      txtPerm.append("read");
540
    } 
541
    if ( (permission & WRITE) != 0 ) {
542
      if ( txtPerm.length() > 0 ) txtPerm.append(",");
543
      txtPerm.append("write");
544
    }
545
    if ( (permission & ALL) != 0 ) {
546
      if ( txtPerm.length() > 0 ) txtPerm.append(",");
547
      txtPerm.append("all");
548
    }
549

    
550
    return txtPerm.append("\"").toString();
551
  }
552

    
553
  
554
  /**
555
    * Check if a document id is a access document. Access document need user
556
    * has "all" permission to access it.
557
    * @param docId, the document id need to be checked
558
    */
559
    private boolean isAccessDocument(String docId) throws SQLException
560
    {
561
      //detele the rev number if docid contains it
562
      docId=MetaCatUtil.getDocIdFromString(docId);
563
      PreparedStatement pStmt=null;
564
      try
565
      {
566
        pStmt = conn.prepareStatement("select 'x' from xml_access where " +
567
                                      "accessfileid like '" + docId +  "'");
568
        pStmt.execute();
569
        ResultSet rs = pStmt.getResultSet();
570
        boolean hasRow = rs.next();
571
        pStmt.close();
572
        if(hasRow)
573
        {
574
          return true;
575
        }
576
      }
577
      catch(SQLException e)
578
      {
579
        pStmt.close();
580
        throw new SQLException("AccessControlList.hasPermission():2 " +
581
                     "Error checking ownership for " + principal +
582
                     " on document #" + docId + ". " + e.getMessage());
583
      }
584
      return false;
585
    }//isAccessDocument
586
     
587
  /**
588
    * To create a part of query: "docid like '" +str1+ "', " +"docid like '" 
589
    * +str2+"'" ... We need to check user, group and public together for the 
590
    * permission. So we need the principal in an array and according the array
591
    * to create a part of query which will be used in other methods
592
    * @param principals, a string array storing the username, groups name and
593
    * public.
594
    */
595
   private String partQueryAboutDocId( String [] principals)
596
   {
597
     String partQuery="";
598
     int lengthOfArray=principals.length;
599
     
600
     for (int i=0;i<(lengthOfArray-1);i++)
601
     {
602
        partQuery=partQuery+"docid like '"+principals[i]+"',";
603
     }
604
     
605
     //the last one dosen't has "'"
606
     partQuery=partQuery+"docid like '"+principals[(lengthOfArray-1)]+"'";
607
     return partQuery;
608
     
609
   }
610
  
611
  /**
612
    * Check if a stirng array contains a given documents' owner
613
    * @param principals, a string array storing the username, groups name and
614
    * public.
615
    * @param docid, the id of given documents 
616
    */ 
617
  private boolean containDocumentOwner( String [] principals, String docId)
618
                    throws SQLException
619
  {
620
    int lengthOfArray=principals.length;
621
    boolean hasRow; 
622
    PreparedStatement pStmt=null;
623
    try
624
    {
625
      pStmt = conn.prepareStatement(
626
                "SELECT 'x' FROM xml_documents " +
627
                "WHERE docid = ? AND user_owner = ?"); 
628
      //check every element in the string array too see if it conatains
629
      //the owner of document
630
      for (int i=0; i<lengthOfArray; i++)
631
      {
632
             
633
        // Bind the values to the query
634
        pStmt.setString(1, docId);
635
        pStmt.setString(2, principals[i]);
636

    
637
        pStmt.execute();
638
        ResultSet rs = pStmt.getResultSet();
639
        hasRow = rs.next();
640
        if (hasRow) 
641
        {
642
          pStmt.close();
643
          return true;
644
        }//if    
645
     
646
      }//for
647
    }//try
648
    catch (SQLException e) 
649
    {
650
        pStmt.close();
651
       
652
        throw new 
653
        SQLException("AccessControlList.hasPermission(). " +
654
                     "Error checking ownership for " + principals[0] +
655
                     " on document #" + docId + ". " + e.getMessage());
656
    }//catch
657
     
658
    
659
    pStmt.close();
660
   
661
    return false; 
662
  }//containDocumentOwner
663
  
664
  /**
665
    * Check if the permission order for user at that documents is allowFirst
666
    * @param principals, list of names of principals to check for 
667
    * @param docid, document identifier to check for
668
    */
669
  private boolean isAllowFirst(String [] principals, String docId)
670
                  throws SQLException, Exception
671
  {
672
    int lengthOfArray=principals.length;
673
    boolean hasRow;
674
    
675
    //select permission order from database
676
    PreparedStatement pStmt = conn.prepareStatement(
677
                "SELECT perm_order FROM xml_access " +
678
                "WHERE principal_name= ? AND docid = ?");
679
   
680
   //check every name in the array
681
    for (int i=0; i<lengthOfArray;i++)
682
    {
683
      //bind value
684
      pStmt.setString(1, principals[i]);//user name
685
      pStmt.setString(2, docId);//docid
686
    
687
      pStmt.execute();
688
      ResultSet rs = pStmt.getResultSet();
689
      hasRow=rs.next();
690
      if (hasRow)
691
      {
692
        //get the permission order from data base
693
        String permissionOrder=rs.getString(1);
694
        //if the permission order is "allowFirst
695
        if (permissionOrder.compareTo(ALLOWFIRST)==0)
696
        {
697
          pStmt.close();
698
          return true;
699
        }
700
        else
701
        {
702
          pStmt.close();
703
          return false;
704
        }
705
      }//if
706
    }//for
707
    
708
    //if reach here, means there is no permssion record for given names and 
709
    //docid. So throw a exception.
710
    pStmt.close();
711
    throw new Exception("There is no permission record for user"+principals[0]+
712
                        "at document "+docId);
713
        
714
  }//isAllowFirst
715
  
716
  /**
717
    * Check if the users array has allow rules for given users, docid and 
718
    * permission.
719
    * If it has permission rule and ticket count is greater than 0, the ticket
720
    * number will decrease one for every allow rule
721
    * @param principals, list of names of principals to check for 
722
    * @param docid, document identifier to check for
723
    * @param permission, the permssion need to check
724
    */
725
  private boolean hasAllowRule(String [] principals, String docId, 
726
                                  String permission)
727
                  throws SQLException, Exception
728
 {
729
   int lengthOfArray=principals.length;
730
   boolean allow=false;//initial value is no allow rule
731
   ResultSet rs;
732
   PreparedStatement pStmt;
733
   int permissionValue=intValue(permission);
734
   int permissionValueInTable;
735
   int ticketCount;
736
   
737
   //This sql statement will select entry with 
738
   //begin_time<=currentTime<=end_time in xml_access table
739
   //If begin_time or end_time is null in table, isnull(begin_time, sysdate)
740
   //function will assign begin_time=sysdate
741
   pStmt = conn.prepareStatement(
742
                "SELECT permission, ticket_count " +
743
                "FROM xml_access " +
744
                "WHERE docid = ? " + 
745
                "AND principal_name = ? " +
746
                "AND perm_type = ? " +
747
                "AND " + sysdate + 
748
                " BETWEEN " + isnull + "(begin_time," + sysdate + ") " +
749
                     "AND " + isnull + "(end_time," + sysdate + ")");
750
   //bind docid, perm_type
751
   pStmt.setString(1, docId);
752
   pStmt.setString(3, ALLOW);
753
   
754
   //bind every elenment in user name array
755
    for (int i=0;i<lengthOfArray; i++)
756
    {
757
      pStmt.setString(2, principals[i]);
758
      pStmt.execute();
759
      rs=pStmt.getResultSet();
760
      while (rs.next())//check every entry for one user
761
      {
762
        permissionValueInTable=rs.getInt(1);
763
        ticketCount=rs.getInt(2);
764
       
765
        //permission is ok and ticketcount geat than 0 or ticket is null, 
766
        //the user have a permission to access the file
767
        if ((( permissionValueInTable & permissionValue )== permissionValue )
768
              && (rs.wasNull()||ticketCount > 0))
769
        {
770
           //ticket count should minus one 
771
           //ticketCount isnot null and greater than 0, order is allowfirst
772
           if (!rs.wasNull() && ticketCount>0 && isAllowFirst(principals,docId))
773
           {
774
              decreaseNumberOfAccess(permissionValueInTable, principals[i],
775
                                              docId, ALLOW, ALLOWFIRST);
776
            }
777
           //ticketCount isnot null and greater than 0, order is not allowfirst
778
           if (!rs.wasNull() &&ticketCount>0 && !isAllowFirst(principals,docId))
779
           {
780
              decreaseNumberOfAccess(permissionValueInTable, principals[i],
781
                                              docId, ALLOW, DENYFIRST);
782
           }
783
          
784
           allow=true;//has allow rule entry
785
         }//if
786
      }//while
787
    }//for
788
    pStmt.close();
789
    return allow;
790
 }//hasAllowRule
791
 
792
  /**
793
    * Check if the users array has allow rules for given users, docid and 
794
    * permission.
795
    * If it has permission rule and ticket count is greater than 0, the ticket
796
    * number will decrease one
797
    * @param principals, list of names of principals to check for 
798
    * @param docid, document identifier to check for
799
    * @param permission, the permssion need to check
800
    */
801
  private boolean hasAllowRuleBackup(String [] principals, String docId, 
802
                                  String permission)
803
                  throws SQLException, Exception
804
 {
805
   int lengthOfArray=principals.length;
806
   ResultSet rs;
807
   PreparedStatement pStmt;
808
   int permissionValue=intValue(permission);
809
   int permissionValueInTable;
810
   int ticketCount;
811
   
812
   //This sql statement will select entry with 
813
   //begin_time<=currentTime<=end_time in xml_access table
814
   //If begin_time or end_time is null in table, isnull(begin_time, sysdate)
815
   //function will assign begin_time=sysdate
816
   pStmt = conn.prepareStatement(
817
                "SELECT permission, ticket_count " +
818
                "FROM xml_access " +
819
                "WHERE docid = ? " + 
820
                "AND principal_name = ? " +
821
                "AND perm_type = ? " +
822
                "AND " + sysdate + 
823
                " BETWEEN " + isnull + "(begin_time," + sysdate + ") " +
824
                     "AND " + isnull + "(end_time," + sysdate + ")");
825
   //bind docid, perm_type
826
   pStmt.setString(1, docId);
827
   pStmt.setString(3, ALLOW);
828
   
829
   //bind every elenment in user name array
830
    for (int i=0;i<lengthOfArray; i++)
831
    {
832
      pStmt.setString(2, principals[i]);
833
      pStmt.execute();
834
      rs=pStmt.getResultSet();
835
      while (rs.next())//check every entry for one user
836
      {
837
        permissionValueInTable=rs.getInt(1);
838
        ticketCount=rs.getInt(2);
839
       
840
        //permission is ok and ticketcount geat than 0 or ticket is null, 
841
        //the user have a permission to access the file
842
        if ((( permissionValueInTable & permissionValue )== permissionValue )
843
              && (rs.wasNull()||ticketCount > 0))
844
        {
845
           //ticket count should minus one 
846
           //ticketCount isnot null and greater than 0, order is allowfirst
847
           if (!rs.wasNull() && ticketCount>0 && isAllowFirst(principals,docId))
848
           {
849
              decreaseNumberOfAccess(permissionValueInTable, principals[i],
850
                                              docId, ALLOW, ALLOWFIRST);
851
            }
852
           //ticketCount isnot null and greater than 0, order is not allowfirst
853
           if (!rs.wasNull() &&ticketCount>0 && !isAllowFirst(principals,docId))
854
           {
855
              decreaseNumberOfAccess(permissionValueInTable, principals[i],
856
                                              docId, ALLOW, DENYFIRST);
857
           }
858
           pStmt.close();
859
           return true;
860
         }//if
861
      }//while
862
    }//for
863
    pStmt.close();
864
    return false;//no allow rule
865
 }//hasAllowRule
866
   
867
   /**
868
    * Check if the users array has explicit deny rules for given users, docid 
869
    * and permission. That means the perm_type is deny and current time is
870
    * less than end_time and greater than begin time, or no time limit.
871
    * @param principals, list of names of principals to check for 
872
    * @param docid, document identifier to check for
873
    * @param permission, the permssion need to check
874
    */
875
  private boolean hasExplicitDenyRule(String [] principals, String docId, 
876
                                  String permission)
877
                  throws SQLException
878
 {
879
   int lengthOfArray=principals.length;
880
   ResultSet rs;
881
   PreparedStatement pStmt;
882
   int permissionValue=intValue(permission);
883
   int permissionValueInTable;
884
 
885
   
886
   //This sql statement will select entry with 
887
   //begin_time<=currentTime<=end_time in xml_access table
888
   //If begin_time or end_time is null in table, isnull(begin_time, sysdate)
889
   //function will assign begin_time=sysdate
890
   pStmt = conn.prepareStatement(
891
                "SELECT permission " +
892
                "FROM xml_access " +
893
                "WHERE docid = ? " + 
894
                "AND principal_name = ? " +
895
                "AND perm_type = ? " +
896
                "AND " + sysdate + 
897
                " BETWEEN " + isnull + "(begin_time," + sysdate + ") " +
898
                     "AND " + isnull + "(end_time," + sysdate + ")");
899
   //bind docid, perm_type
900
   pStmt.setString(1, docId);
901
   pStmt.setString(3, DENY);
902
   
903
   //bind every elenment in user name array
904
    for (int i=0;i<lengthOfArray; i++)
905
    {
906
      pStmt.setString(2, principals[i]);
907
      pStmt.execute();
908
      rs=pStmt.getResultSet();
909
      while (rs.next())//check every entry for one user
910
      {
911
        permissionValueInTable=rs.getInt(1);
912
        
913
        //permission is ok the user doesn't have permission to access the file
914
        if (( permissionValueInTable & permissionValue )== permissionValue )
915
             
916
        {
917
           pStmt.close();
918
           return true;
919
         }//if
920
      }//while
921
    }//for
922
    pStmt.close();
923
    return false;//no deny rule
924
  }//hasExplicitDenyRule 
925
   
926
   /**
927
    * Check if the users array has implicit deny rules for given users, docid 
928
    * and permission. That means the though perm_type is "allow" but current 
929
    * time is less than begin_time or greater than end time, or ticket count
930
    * is 0.
931
    * @param principals, list of names of principals to check for 
932
    * @param docid, document identifier to check for
933
    * @param permission, the permssion need to check
934
    */
935
  private boolean hasImplicitDenyRule(String [] principals, String docId, 
936
                                  String permission)
937
                  throws SQLException
938
 {
939
   int lengthOfArray=principals.length;
940
   ResultSet rs;
941
   PreparedStatement pStmt;
942
   int permissionValue=intValue(permission);
943
   int permissionValueInTable;
944
 
945
   
946
   //This sql statement will select entry with  perm_type =allow and
947
   //currentTime is less than begin_time or greater than end time
948
   //in xml_access table. This is an implicit deny rule (allow is out of date) 
949
   pStmt = conn.prepareStatement(
950
                "SELECT permission " +
951
                "FROM xml_access " +
952
                "WHERE docid = ? " + 
953
                "AND principal_name = ? " +
954
                "AND perm_type = ? " +
955
                "AND " + sysdate + 
956
                " < " + isnull + "(begin_time," + sysdate + ") " +
957
                "OR " + sysdate + " > "+ isnull + "(end_time," + sysdate + ")");
958
   //bind docid, perm_type
959
   pStmt.setString(1, docId);
960
   pStmt.setString(3, ALLOW);//It is allow
961
   
962
   //bind every elenment in user name array
963
    for (int i=0;i<lengthOfArray; i++)
964
    {
965
      pStmt.setString(2, principals[i]);
966
      pStmt.execute();
967
      rs=pStmt.getResultSet();
968
      while (rs.next())//check every entry for one user
969
      {
970
        permissionValueInTable=rs.getInt(1);
971
        
972
        //permission is ok the user doesn't have permission to access the file
973
        if (( permissionValueInTable & permissionValue )== permissionValue )
974
             
975
        {
976
           pStmt.close();
977
           //has a implicit deny rule: allow is out of date
978
           return true;
979
         }//if
980
      }//while
981
    }//for
982
    pStmt.close();
983
    
984
    //Now, there is no implicit deny rule which is allow is out of date
985
    //another implicit deny rule need to be check: allow is out of ticketCount
986
    //ticketCount=0
987
    pStmt = conn.prepareStatement(
988
                "SELECT permission " +
989
                "FROM xml_access " +
990
                "WHERE docid = ? " + 
991
                "AND principal_name = ? " +
992
                "AND perm_type = ? " +
993
                "AND ticket_count = ?");
994
   //bind docid, perm_type, ticket_count
995
   pStmt.setString(1, docId);
996
   pStmt.setString(3, ALLOW);//It is allow!
997
   pStmt.setInt(4,0);
998
   
999
   //bind every elenment in user name array
1000
    for (int i=0;i<lengthOfArray; i++)
1001
    {
1002
      pStmt.setString(2, principals[i]);
1003
      pStmt.execute();
1004
      rs=pStmt.getResultSet();
1005
      while (rs.next())//check every entry for one user
1006
      {
1007
        permissionValueInTable=rs.getInt(1);
1008
        
1009
        //permission is ok the user doesn't have permission to access the file
1010
        if (( permissionValueInTable & permissionValue )== permissionValue )
1011
             
1012
        {
1013
           
1014
           pStmt.close();
1015
           //has a implicit deny rule: allow is out of ticketCount
1016
           return true;
1017
         }//if
1018
      }//while
1019
    }//for
1020
    
1021
    pStmt.close();
1022
    return false;//no implicit deny rule
1023
  }//hasImplicitDenyRule
1024
  
1025
  /**
1026
    * Creat a users pakages to check permssion rule, user itself, public and
1027
    * the gourps the user belong will be include in this package
1028
    * @param user, the name of user
1029
    * @param groups, the string array of the groups that user belong to
1030
    */
1031
  private String [] createUsersPackage(String user, String [] groups)
1032
  {
1033
    String [] usersPackage=null;
1034
    int lengthOfPackage;
1035
    
1036
    if (groups!=null)
1037
    {
1038
      //if gouprs is not null and user is not public, we should create a array 
1039
      //to store the groups and user and public. 
1040
      //So the length of userPackage is the length of group plus two
1041
      if (user.compareTo(PUBLIC)!=0)
1042
      {
1043
        lengthOfPackage=(groups.length)+2;
1044
        usersPackage=new String [lengthOfPackage];
1045
        //the first two elements is user self and public
1046
        usersPackage[0]=user;
1047
        usersPackage[1]=PUBLIC;
1048
        //put groups element from index 0 to lengthOfPackage-3 into userPackage
1049
        //from index 2 to lengthOfPackage-1
1050
        for (int i=2; i<lengthOfPackage; i++)
1051
        {
1052
          usersPackage[i]=groups[i-2];
1053
        } //for
1054
      }//if user!=public
1055
      else//use=public
1056
      {
1057
        lengthOfPackage=(groups.length)+1;
1058
        usersPackage=new String [lengthOfPackage];
1059
        //the first lements is public
1060
        usersPackage[0]=PUBLIC;
1061
        //put groups element from index 0 to lengthOfPackage-2 into userPackage
1062
        //from index 1 to lengthOfPackage-1
1063
        for (int i=1; i<lengthOfPackage; i++)
1064
        {
1065
          usersPackage[i]=groups[i-1];
1066
        } //for
1067
      }//else user=public
1068
       
1069
    }//if groups!=null
1070
    else
1071
    {
1072
      //because no groups, the userPackage only need two elements
1073
      //one is for user, the other is for public
1074
      if (user.compareTo(PUBLIC)!=0)
1075
      {
1076
        lengthOfPackage=2;
1077
        usersPackage=new String [lengthOfPackage];
1078
        usersPackage[0]=user;
1079
        usersPackage[1]=PUBLIC;
1080
      }//if user!=public
1081
      else //user==public
1082
      {
1083
        //only put public into array
1084
        lengthOfPackage=1;
1085
        usersPackage=new String [lengthOfPackage];
1086
        usersPackage[0]=PUBLIC;
1087
      }
1088
    }//else groups==null
1089
    return usersPackage;
1090
  }//createUsersPackage
1091
   
1092
  /**
1093
    * Check from db connection if at least one of the list of @principals
1094
    * has @permission on @docid.
1095
    * @param permission permission type to check for
1096
    * @param principals list of names of principals to check for @permission
1097
    * @param docid document identifier to check on
1098
    */
1099
  public boolean hasPermission(String permission, String user,
1100
                               String[] groups, String docId )
1101
                 throws SQLException
1102
  {
1103
    //detele the rev number if docid contains it
1104
    docId=MetaCatUtil.getDocIdFromString(docId);
1105
    boolean hasPermission=false;
1106
    String [] userPackage=null;
1107
    
1108
    // b' of the command line invocation
1109
    if ( (user == null) && (groups == null || groups.length == 0) ) {
1110
      return true;
1111
    }
1112
    
1113
    
1114
    //create a userpackage including user, public and group member
1115
    userPackage=createUsersPackage(user, groups);
1116
    
1117
    //if the requested document is access documents the user should 
1118
    //have "all" permission not matter the requested permission
1119
    if (isAccessDocument(docId))
1120
    {
1121
      
1122
      // check for all permission on @docid for @userPackage
1123
      hasPermission = hasPermission(userPackage,docId,"all");
1124
      
1125
    }//if
1126
    else //if it is not access documents, just check the request permission
1127
    {
1128
    
1129
      // Check for @permission on @docid for @user and/or @groups
1130
      hasPermission = hasPermission(userPackage,docId, permission);
1131
     
1132
    }//else
1133
    
1134
    return hasPermission;
1135
  }
1136
 
1137
  /**
1138
    * Check from db connection if the users in String array @principals has
1139
    * @permission on @docid* 
1140
    * @param principals, names in userPakcage need to check for @permission
1141
    * @param docid, document identifier to check on
1142
    * @param permission, permission (write or all...) to check for 
1143
    */
1144
  private boolean hasPermission(String [] principals, String docId,
1145
                                            String permission)
1146
                         throws SQLException
1147
  {
1148
    try 
1149
    {
1150
      //first, if there is a docid owner in user package, return true
1151
      //because doc owner has all permssion 
1152
      if (containDocumentOwner(principals, docId))
1153
      {
1154
          
1155
          return true;
1156
      }
1157
      
1158
      //If there is no owner in user package, checking the table
1159
      //check perm_order
1160
      if (isAllowFirst(principals, docId))
1161
      {
1162
        
1163
        if (hasExplicitDenyRule(principals, docId, permission)||
1164
                            hasImplicitDenyRule(principals, docId, permission))
1165
        {
1166
          //if it is allowfirst and has deny rule(either explicit or implicit)
1167
          //deny access
1168
          return false;
1169
        }//if
1170
        else if ( hasAllowRule(principals, docId, permission))
1171
        {
1172
          //if it is allowfirst and hasn't deny rule and has allow rule
1173
          //allow access
1174
          return true;
1175
        }//else if
1176
        else
1177
        {
1178
          //other situation deny access
1179
          return false;
1180
        }//else
1181
     }//if isAllowFirst
1182
     else //denyFirst
1183
     {
1184
       if (hasAllowRule(principals, docId, permission))
1185
       {
1186
         //if it is denyFirst and has allow rule, allow access
1187
         return true;
1188
       }
1189
       else
1190
       {
1191
         //if it is denyfirst but no allow rule, deny access
1192
         return false;
1193
       }
1194
     }//else denyfirst
1195
    }//try
1196
    catch (Exception e)
1197
    {
1198
      MetaCatUtil.debugMessage("There is a exception in hasPermission method: "
1199
                         +e.getMessage());
1200
    }
1201
    return false;
1202
  }//hasPermission
1203
 
1204
  private boolean hasValidDenyEntry(String persmission, String principal, 
1205
                                      String docId)
1206
                  throws SQLException
1207
  {
1208
  //detele the rev number if docid contains it
1209
      docId=MetaCatUtil.getDocIdFromString(docId);
1210
      PreparedStatement pStmt;
1211
      String permissionType;
1212
      int accessValue;
1213
      
1214
      
1215
      try
1216
      {
1217
        pStmt = conn.prepareStatement("select perm_type, permission, begin_time"
1218
                                    + ", end_time from xml_access where " +
1219
                                      "docid like '" + docId +  "' and "
1220
                                    + "principal_name like '"+principal+"'");
1221
        pStmt.execute();
1222
        ResultSet rs = pStmt.getResultSet();
1223
        boolean hasRow = rs.next();
1224
        pStmt.close();
1225
        if(hasRow)
1226
        {
1227
          return true;
1228
        }
1229
      }
1230
      catch(SQLException e)
1231
      {
1232
        throw new SQLException("AccessControlList.hasPermission():2 " +
1233
                     "Error checking ownership for " + principal +
1234
                     " on document #" + docId + ". " + e.getMessage());
1235
      }
1236
      return false;
1237
  }
1238
  /* Decrease the number of access to @docid for @principal in db. */
1239
  private void decreaseNumberOfAccess(int permission, String principal,
1240
                                      String docid, String permType, 
1241
                                      String permOrder) 
1242
               throws SQLException
1243
  {
1244
    PreparedStatement pstmt;
1245
    pstmt = conn.prepareStatement(
1246
            "UPDATE xml_access SET ticket_count = ticket_count - 1 " +
1247
            "WHERE docid = ? " +
1248
            "AND principal_name = ? " +
1249
            "AND permission = ? " +
1250
            "AND perm_type = ? " +
1251
            "AND perm_order = ? " +
1252
            "AND " + sysdate + 
1253
            " BETWEEN " + isnull + "(begin_time," + sysdate + ") " +
1254
                 "AND " + isnull + "(end_time," + sysdate + ")");
1255
    // Bind the values to the query
1256
    pstmt.setString(1, docid);
1257
    pstmt.setString(2, principal);
1258
    pstmt.setInt(3, permission);
1259
    pstmt.setString(4, permType);
1260
    pstmt.setString(5, permOrder);
1261

    
1262
    pstmt.execute();
1263
    pstmt.close();
1264
  }
1265
 
1266
 
1267
  /**
1268
    * Get Access Control List information for document from db connetion.
1269
    * User or Group should have permissions for reading
1270
    * access control information for a document specified by @docid.
1271
    * @param docid document identifier which acl info to get
1272
    * @param user name of user connected to Metacat system
1273
    * @param groups names of user's groups to which user belongs
1274
    */
1275
  public String getACL(String docid, String user, String[] groups) 
1276
          throws SQLException
1277
  {
1278
    StringBuffer output = new StringBuffer();
1279
    StringBuffer outTemp = new StringBuffer();
1280
    MetaCatUtil util = new MetaCatUtil();
1281
    String accDoctype = util.getOption("accessdoctype");
1282
    String server = util.getOption("server");
1283
    String docurl = "metacat://" + server + "/?docid=" + docid;
1284
    String systemID;
1285
    boolean isOwned = false;
1286
    boolean hasPermission = false;
1287
    String publicAcc;
1288
    
1289
    String acfid = "";
1290
    String acfid_prev = "";
1291
    String principal;
1292
    Vector principalArr = new Vector();
1293
    int permission;
1294
    int perm_prev = -1;
1295
    String permType;
1296
    String permOrder = "";
1297
    String permOrder_prev = "";
1298
    String beginTime = "";
1299
    String begin_prev = "";
1300
    String endTime = "";
1301
    String end_prev = "";
1302
    int ticketCount = -1;
1303
    int ticket_prev = -1;
1304
    
1305
    try {
1306
      
1307
      isOwned = isOwned(docid, user);
1308
      systemID = getSystemID((String)MetaCatUtil.
1309
                                      getOptionList(accDoctype).elementAt(0));
1310
      publicAcc = getPublicAccess(docid);
1311
        
1312
      output.append("<?xml version=\"1.0\"?>\n");
1313
      output.append("<!DOCTYPE acl PUBLIC \"" + accDoctype + "\" \"" +
1314
                    systemID + "\">\n");
1315
      output.append("<acl authSystem=\"\">\n");
1316

    
1317
      PreparedStatement pstmt;
1318
      pstmt = conn.prepareStatement(
1319
              "SELECT distinct accessfileid, principal_name, permission, " +
1320
              "perm_type, perm_order, to_char(begin_time,'mm/dd/yyyy'), " +
1321
              "to_char(end_time,'mm/dd/yyyy'), ticket_count " +
1322
              "FROM xml_access WHERE docid = ? " +
1323
              "ORDER BY accessfileid, perm_order, perm_type, permission");
1324
      // Bind the values to the query
1325
      pstmt.setString(1, docid);
1326
      pstmt.execute();
1327
      ResultSet rs = pstmt.getResultSet();
1328
      boolean hasRows = rs.next();
1329
      while (hasRows) {
1330

    
1331
        acfid = rs.getString(1);
1332
        principal = rs.getString(2);
1333
        permission = rs.getInt(3);
1334
        permType = rs.getString(4);
1335
        permOrder = rs.getString(5);
1336
        beginTime = rs.getString(6);
1337
        endTime = rs.getString(7);
1338
        ticketCount = rs.getInt(8);
1339

    
1340
        // if @docid is not owned by @user, only ACL info from that
1341
        // access files to which @user/@groups has "read" permission
1342
        // is extracted
1343
        if ( !isOwned ) {
1344
          if ( !acfid.equals(acfid_prev) ) {
1345
            acfid_prev = acfid;
1346
            hasPermission = this.hasPermission("READ",user,groups,acfid);
1347
          }
1348
          if ( !hasPermission ) {
1349
            rs.next();
1350
            continue;
1351
          }
1352
        }
1353
        
1354
        // open <resource> tag
1355
        if ( !permOrder.equals(permOrder_prev) ) {
1356
          // close </resource> tag if any was opened 
1357
          output.append(outTemp.toString());
1358
          outTemp = new StringBuffer();
1359
          if ( !permOrder_prev.equals("") ) {
1360
            output.append("  </resource>\n");
1361
          }
1362
          output.append("  <resource order=\"" + permOrder + "\" public=\"" +
1363
                        publicAcc + "\">\n");
1364
          output.append("    <resourceIdentifier>" + docurl + 
1365
                        "</resourceIdentifier>\n");
1366
          permOrder_prev = permOrder;
1367
        }
1368
        
1369
        // close </allow> or </deny> tag then open new one
1370
        if ( permission != perm_prev ||
1371
             (endTime == null) && (end_prev != null) ||
1372
             (beginTime == null) && (begin_prev != null) ||
1373
             endTime != null && !endTime.equals(end_prev)  ||
1374
             beginTime != null && !beginTime.equals(begin_prev) ||
1375
             ticketCount != ticket_prev )  {
1376
          output.append(outTemp.toString());
1377
          outTemp = new StringBuffer();
1378
          principalArr.removeAllElements();
1379
          output.append("    <" + permType + ">\n");
1380
        }
1381
        
1382
        // put all principals here for the same 
1383
        // permission, duration and ticket_count
1384
        if ( !principalArr.contains(principal) ) {
1385
          principalArr.addElement(principal);
1386
          output.append("      <principal>" + principal + "</principal>\n");
1387
        } 
1388
        
1389
        // prepare <permission> tags, <duration> and <ticketCount>
1390
        // if any to put within <allow> (<deny>) by next cicle
1391
        if ( permission != perm_prev || 
1392
             (endTime == null) && (end_prev != null) ||
1393
             (beginTime == null) && (begin_prev != null) ||
1394
             endTime != null && !endTime.equals(end_prev)  ||
1395
             beginTime != null && !beginTime.equals(begin_prev) ||
1396
             ticketCount != ticket_prev )  {
1397
          if ( (permission & READ) != 0 ) {
1398
            outTemp.append("      <permission>read</permission>\n");
1399
          }
1400
          if ( (permission & WRITE) != 0 ) {
1401
            outTemp.append("      <permission>write</permission>\n");
1402
          }
1403
          if ( (permission & ALL) != 0 ) {
1404
            outTemp.append("      <permission>all</permission>\n");
1405
          }
1406
          if ( (beginTime != null) || (endTime != null) ) {
1407
            outTemp.append("      <duration>" + beginTime + " " + endTime +
1408
                          "</duration>\n");
1409
          }
1410
          if ( ticketCount > 0 ) {
1411
            outTemp.append("      <ticketCount>" + ticketCount + 
1412
                          "</ticketCount>\n");
1413
          }
1414
          outTemp.append("    </" + permType + ">\n");
1415
          perm_prev = permission;
1416
          ticket_prev = ticketCount;
1417
          begin_prev = beginTime;
1418
          end_prev = endTime;
1419
        }
1420
        
1421
        hasRows = rs.next();
1422
      }
1423

    
1424
      // close <allow> or <deny> if anything left in outTemp var
1425
      output.append(outTemp.toString());
1426

    
1427
      // If there are no any acl info for @docid accessible by @user/@group,
1428
      // extract only the following information
1429
      if ( permOrder.equals("") ) {
1430
        output.append("  <resource public=\"" + publicAcc + "\">\n");
1431
        output.append("    <resourceIdentifier>" + docurl + 
1432
                      "</resourceIdentifier>\n");
1433
      }
1434
      
1435
      // always close them
1436
      output.append("  </resource>\n");
1437
      output.append("</acl>\n");
1438
      
1439
      pstmt.close();
1440

    
1441
      return output.toString();
1442

    
1443
    } catch (SQLException e) {
1444
      throw new 
1445
      SQLException("AccessControlList.getACL(). " + e.getMessage());
1446
    }
1447
  }
1448
  
1449
  /* Check if @user is owner of @docid from db conn. */
1450
  private boolean isOwned(String docid, String user) throws SQLException {
1451
    
1452
    PreparedStatement pstmt;
1453
    pstmt = conn.prepareStatement("SELECT 'x' FROM xml_documents " +
1454
                                  "WHERE docid = ? " + 
1455
                                  "AND user_owner = ?");
1456
    pstmt.setString(1, docid);
1457
    pstmt.setString(2, user);
1458
    pstmt.execute();
1459
    ResultSet rs = pstmt.getResultSet();
1460
    boolean hasRow = rs.next();
1461
    
1462
    return hasRow;
1463
  }
1464

    
1465
  /* Get the flag for public "read" access for @docid from db conn. */
1466
  private String getPublicAccess(String docid) throws SQLException {
1467
    
1468
    int publicAcc = 0;
1469
    PreparedStatement pstmt;
1470
    pstmt = conn.prepareStatement("SELECT public_access FROM xml_documents " +
1471
                                  "WHERE docid = ?");
1472
    pstmt.setString(1, docid);
1473
    pstmt.execute();
1474
    ResultSet rs = pstmt.getResultSet();
1475
    boolean hasRow = rs.next();
1476
    if ( hasRow ) {
1477
      publicAcc = rs.getInt(1);
1478
    }
1479
    
1480
    return (publicAcc == 1) ? "yes" : "no";
1481
  }
1482

    
1483
  /* Get SystemID for @publicID from Metacat DB Catalog. */
1484
  private String getSystemID(String publicID) throws SQLException {
1485
    
1486
    String systemID = "";
1487
    PreparedStatement pstmt;
1488
    pstmt = conn.prepareStatement("SELECT system_id FROM xml_catalog " +
1489
                                  "WHERE entry_type = 'DTD' " + 
1490
                                  "AND public_id = ?");
1491
    pstmt.setString(1, publicID);
1492
    pstmt.execute();
1493
    ResultSet rs = pstmt.getResultSet();
1494
    boolean hasRow = rs.next();
1495
    if ( hasRow ) {
1496
      systemID = rs.getString(1);
1497
    }
1498
    
1499
    return systemID;
1500
  }
1501

    
1502
}
(1-1/40)