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-18 17:02:45 -0800 (Mon, 18 Mar 2002) $'
12
 * '$Revision: 975 $'
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
          //should insert permission for aclid itself into database
338
          DocumentIdentifier aclIdItself = new DocumentIdentifier(aclid);
339
          String aclIdString = aclIdItself.getIdentifier();
340
          insertPermissions(aclIdString,leavingTagName);
341
          
342

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

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

    
359
  }
360

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

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

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

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

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

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

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

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

    
489
    } catch (SQLException e) {
490
      throw new 
491
      SQLException("AccessControlList.insertPermissions(): " + e.getMessage());
492
    }
493
  }
494

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

    
526
  /* Get the int value of READ, WRITE or ALL. */
527
  private int intValue ( String permission )
528
  {
529
    if ( permission.equals("READ") ) {
530
      return READ;
531
    } else if ( permission.equals("WRITE") ) {
532
      return WRITE;
533
    } else if ( permission.equals("ALL") ) {
534
      return ALL;
535
    }
536
    
537
    return -1;
538
  }
539

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

    
556
    return txtPerm.append("\"").toString();
557
  }
558

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

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

    
1300
    pstmt.execute();
1301
    pstmt.close();
1302
  }
1303
 
1304
 
1305
  /**
1306
    * Get Access Control List information for document from db connetion.
1307
    * User or Group should have permissions for reading
1308
    * access control information for a document specified by @docid.
1309
    * @param docid document identifier which acl info to get
1310
    * @param user name of user connected to Metacat system
1311
    * @param groups names of user's groups to which user belongs
1312
    */
1313
  public String getACL(String docid, String user, String[] groups) 
1314
          throws SQLException, Exception
1315
  {
1316
    StringBuffer output = new StringBuffer();
1317
    StringBuffer outTemp = new StringBuffer();
1318
    MetaCatUtil util = new MetaCatUtil();
1319
    String accDoctype = util.getOption("accessdoctype");
1320
    String server = util.getOption("server");
1321
    String docurl = "metacat://" + server + "/?docid=" + docid;
1322
    String systemID;
1323
    boolean isOwned = false;
1324
    boolean hasPermission = false;
1325
    String publicAcc;
1326
    
1327
    String acfid = "";
1328
    String acfid_prev = "";
1329
    String principal;
1330
    Vector principalArr = new Vector();
1331
    int permission;
1332
    int perm_prev = -1;
1333
    String permType;
1334
    String permOrder = "";
1335
    String permOrder_prev = "";
1336
    String beginTime = "";
1337
    String begin_prev = "";
1338
    String endTime = "";
1339
    String end_prev = "";
1340
    int ticketCount = -1;
1341
    int ticket_prev = -1;
1342
    
1343
    try {
1344
      
1345
      isOwned = isOwned(docid, user);
1346
      systemID = getSystemID((String)MetaCatUtil.
1347
                                      getOptionList(accDoctype).elementAt(0));
1348
      publicAcc = getPublicAccess(docid);
1349
        
1350
      output.append("<?xml version=\"1.0\"?>\n");
1351
      output.append("<!DOCTYPE acl PUBLIC \"" + accDoctype + "\" \"" +
1352
                    systemID + "\">\n");
1353
      output.append("<acl authSystem=\"\">\n");
1354

    
1355
      PreparedStatement pstmt;
1356
      pstmt = conn.prepareStatement(
1357
              "SELECT distinct accessfileid, principal_name, permission, " +
1358
              "perm_type, perm_order, to_char(begin_time,'mm/dd/yyyy'), " +
1359
              "to_char(end_time,'mm/dd/yyyy'), ticket_count " +
1360
              "FROM xml_access WHERE docid = ? " +
1361
              "ORDER BY accessfileid, perm_order, perm_type, permission");
1362
      // Bind the values to the query
1363
      pstmt.setString(1, docid);
1364
      pstmt.execute();
1365
      ResultSet rs = pstmt.getResultSet();
1366
      boolean hasRows = rs.next();
1367
      while (hasRows) {
1368

    
1369
        acfid = rs.getString(1);
1370
        principal = rs.getString(2);
1371
        permission = rs.getInt(3);
1372
        permType = rs.getString(4);
1373
        permOrder = rs.getString(5);
1374
        beginTime = rs.getString(6);
1375
        endTime = rs.getString(7);
1376
        ticketCount = rs.getInt(8);
1377

    
1378
        // if @docid is not owned by @user, only ACL info from that
1379
        // access files to which @user/@groups has "read" permission
1380
        // is extracted
1381
        if ( !isOwned ) {
1382
          if ( !acfid.equals(acfid_prev) ) {
1383
            acfid_prev = acfid;
1384
            hasPermission = this.hasPermission("READ",user,groups,acfid);
1385
          }
1386
          if ( !hasPermission ) {
1387
            rs.next();
1388
            continue;
1389
          }
1390
        }
1391
        
1392
        // open <resource> tag
1393
        if ( !permOrder.equals(permOrder_prev) ) {
1394
          // close </resource> tag if any was opened 
1395
          output.append(outTemp.toString());
1396
          outTemp = new StringBuffer();
1397
          if ( !permOrder_prev.equals("") ) {
1398
            output.append("  </resource>\n");
1399
          }
1400
          output.append("  <resource order=\"" + permOrder + "\" public=\"" +
1401
                        publicAcc + "\">\n");
1402
          output.append("    <resourceIdentifier>" + docurl + 
1403
                        "</resourceIdentifier>\n");
1404
          permOrder_prev = permOrder;
1405
        }
1406
        
1407
        // close </allow> or </deny> tag then open new one
1408
        if ( permission != perm_prev ||
1409
             (endTime == null) && (end_prev != null) ||
1410
             (beginTime == null) && (begin_prev != null) ||
1411
             endTime != null && !endTime.equals(end_prev)  ||
1412
             beginTime != null && !beginTime.equals(begin_prev) ||
1413
             ticketCount != ticket_prev )  {
1414
          output.append(outTemp.toString());
1415
          outTemp = new StringBuffer();
1416
          principalArr.removeAllElements();
1417
          output.append("    <" + permType + ">\n");
1418
        }
1419
        
1420
        // put all principals here for the same 
1421
        // permission, duration and ticket_count
1422
        if ( !principalArr.contains(principal) ) {
1423
          principalArr.addElement(principal);
1424
          output.append("      <principal>" + principal + "</principal>\n");
1425
        } 
1426
        
1427
        // prepare <permission> tags, <duration> and <ticketCount>
1428
        // if any to put within <allow> (<deny>) by next cicle
1429
        if ( permission != perm_prev || 
1430
             (endTime == null) && (end_prev != null) ||
1431
             (beginTime == null) && (begin_prev != null) ||
1432
             endTime != null && !endTime.equals(end_prev)  ||
1433
             beginTime != null && !beginTime.equals(begin_prev) ||
1434
             ticketCount != ticket_prev )  {
1435
          if ( (permission & READ) != 0 ) {
1436
            outTemp.append("      <permission>read</permission>\n");
1437
          }
1438
          if ( (permission & WRITE) != 0 ) {
1439
            outTemp.append("      <permission>write</permission>\n");
1440
          }
1441
          if ( (permission & ALL) != 0 ) {
1442
            outTemp.append("      <permission>all</permission>\n");
1443
          }
1444
          if ( (beginTime != null) || (endTime != null) ) {
1445
            outTemp.append("      <duration>" + beginTime + " " + endTime +
1446
                          "</duration>\n");
1447
          }
1448
          if ( ticketCount > 0 ) {
1449
            outTemp.append("      <ticketCount>" + ticketCount + 
1450
                          "</ticketCount>\n");
1451
          }
1452
          outTemp.append("    </" + permType + ">\n");
1453
          perm_prev = permission;
1454
          ticket_prev = ticketCount;
1455
          begin_prev = beginTime;
1456
          end_prev = endTime;
1457
        }
1458
        
1459
        hasRows = rs.next();
1460
      }
1461

    
1462
      // close <allow> or <deny> if anything left in outTemp var
1463
      output.append(outTemp.toString());
1464

    
1465
      // If there are no any acl info for @docid accessible by @user/@group,
1466
      // extract only the following information
1467
      if ( permOrder.equals("") ) {
1468
        output.append("  <resource public=\"" + publicAcc + "\">\n");
1469
        output.append("    <resourceIdentifier>" + docurl + 
1470
                      "</resourceIdentifier>\n");
1471
      }
1472
      
1473
      // always close them
1474
      output.append("  </resource>\n");
1475
      output.append("</acl>\n");
1476
      
1477
      pstmt.close();
1478

    
1479
      return output.toString();
1480

    
1481
    } catch (SQLException e) {
1482
      throw new 
1483
      SQLException("AccessControlList.getACL(). " + e.getMessage());
1484
    }
1485
  }
1486
  
1487
  /* Check if @user is owner of @docid from db conn. */
1488
  private boolean isOwned(String docid, String user) throws SQLException {
1489
    
1490
    PreparedStatement pstmt;
1491
    pstmt = conn.prepareStatement("SELECT 'x' FROM xml_documents " +
1492
                                  "WHERE docid = ? " + 
1493
                                  "AND user_owner = ?");
1494
    pstmt.setString(1, docid);
1495
    pstmt.setString(2, user);
1496
    pstmt.execute();
1497
    ResultSet rs = pstmt.getResultSet();
1498
    boolean hasRow = rs.next();
1499
    
1500
    return hasRow;
1501
  }
1502

    
1503
  /* Get the flag for public "read" access for @docid from db conn. */
1504
  private String getPublicAccess(String docid) throws SQLException {
1505
    
1506
    int publicAcc = 0;
1507
    PreparedStatement pstmt;
1508
    pstmt = conn.prepareStatement("SELECT public_access FROM xml_documents " +
1509
                                  "WHERE docid = ?");
1510
    pstmt.setString(1, docid);
1511
    pstmt.execute();
1512
    ResultSet rs = pstmt.getResultSet();
1513
    boolean hasRow = rs.next();
1514
    if ( hasRow ) {
1515
      publicAcc = rs.getInt(1);
1516
    }
1517
    
1518
    return (publicAcc == 1) ? "yes" : "no";
1519
  }
1520

    
1521
  /* Get SystemID for @publicID from Metacat DB Catalog. */
1522
  private String getSystemID(String publicID) throws SQLException {
1523
    
1524
    String systemID = "";
1525
    PreparedStatement pstmt;
1526
    pstmt = conn.prepareStatement("SELECT system_id FROM xml_catalog " +
1527
                                  "WHERE entry_type = 'DTD' " + 
1528
                                  "AND public_id = ?");
1529
    pstmt.setString(1, publicID);
1530
    pstmt.execute();
1531
    ResultSet rs = pstmt.getResultSet();
1532
    boolean hasRow = rs.next();
1533
    if ( hasRow ) {
1534
      systemID = rs.getString(1);
1535
    }
1536
    
1537
    return systemID;
1538
  }
1539

    
1540
}
(1-1/41)