Project

General

Profile

1 555 bojilova
/**
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$'
11
 *     '$Date$'
12
 * '$Revision$'
13 669 jones
 *
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 555 bojilova
 */
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 652 bojilova
import java.util.Hashtable;
36
import java.net.URL;
37
import java.net.MalformedURLException;
38 555 bojilova
39
import org.xml.sax.Attributes;
40
import org.xml.sax.InputSource;
41 598 bojilova
import org.xml.sax.ContentHandler;
42
import org.xml.sax.EntityResolver;
43
import org.xml.sax.ErrorHandler;
44 555 bojilova
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 1368 tao
public class AccessControlList extends DefaultHandler
56
                               implements AccessControlInterface
57
{
58 555 bojilova
59 1368 tao
60 774 bojilova
  private static String sysdate = MetaCatUtil.dbAdapter.getDateTimeFunction();
61
  private static String isnull = MetaCatUtil.dbAdapter.getIsNULLFunction();
62 961 tao
63 1214 tao
  private DBConnection connection;
64 555 bojilova
  private String parserName;
65
  private Stack elementStack;
66 645 bojilova
  private String server;
67 802 bojilova
  private String sep;
68 961 tao
69 598 bojilova
  private boolean	processingDTD;
70 645 bojilova
  private String  user;
71 802 bojilova
  private String[] groups;
72 638 bojilova
  private String  aclid;
73 802 bojilova
  private int     rev;
74 598 bojilova
  private String 	docname;
75
  private String 	doctype;
76
  private String 	systemid;
77
78 665 bojilova
  private String docurl;
79
  private Vector resourceURL;
80
  private Vector resourceID;
81 660 bojilova
  private Vector principal;
82 570 bojilova
  private int    permission;
83
  private String permType;
84
  private String permOrder;
85 802 bojilova
//  private String publicAcc;
86 570 bojilova
  private String beginTime;
87
  private String endTime;
88
  private int    ticketCount;
89 684 bojilova
  private int    serverCode = 1;
90 802 bojilova
91
  private Vector aclObjects = new Vector();
92 859 berkley
  private boolean instarttag = true;
93
  private String tagName = "";
94 555 bojilova
  /**
95
   * Construct an instance of the AccessControlList class.
96 688 bojilova
   * It is used by the permission check up from DBQuery or DocumentImpl
97
   * and from "getaccesscontrol" action
98 570 bojilova
   *
99 684 bojilova
   * @param conn the JDBC connection where acl info is get
100 570 bojilova
   */
101 1214 tao
  public AccessControlList(DBConnection conn) throws SQLException
102 570 bojilova
  {
103 1214 tao
    this.connection = conn;
104 570 bojilova
  }
105 1214 tao
106 570 bojilova
107 1214 tao
108
109 570 bojilova
  /**
110
   * Construct an instance of the AccessControlList class.
111 555 bojilova
   * It parse acl file and loads acl data into db connection.
112
   *
113
   * @param conn the JDBC connection where acl data are loaded
114 684 bojilova
   * @param aclid the Accession# of the document with the acl data
115 570 bojilova
   * @param acl the acl file containing acl data
116 684 bojilova
   * @param user the user connected to MetaCat servlet and owns the document
117 802 bojilova
   * @param groups the groups to which user belongs
118 684 bojilova
   * @param serverCode the serverid from xml_replication on which this document
119
   *        resides.
120 555 bojilova
   */
121 1214 tao
  public AccessControlList(DBConnection conn, String aclid, //Reader acl,
122 802 bojilova
                           String user, String[] groups, int serverCode)
123 819 bojilova
                  throws SAXException, IOException, McdbException
124 555 bojilova
  {
125 802 bojilova
    String parserName = MetaCatUtil.getOption("saxparser");
126
    this.server = MetaCatUtil.getOption("server");
127
    this.sep = MetaCatUtil.getOption("accNumSeparator");
128 555 bojilova
129 1214 tao
    this.connection = conn;
130 555 bojilova
    this.parserName = parserName;
131 598 bojilova
    this.processingDTD = false;
132 570 bojilova
    this.elementStack = new Stack();
133
134 645 bojilova
    this.user = user;
135 802 bojilova
    this.groups = groups;
136 638 bojilova
    this.aclid = aclid;
137 665 bojilova
    this.resourceURL = new Vector();
138
    this.resourceID = new Vector();
139 660 bojilova
    this.principal = new Vector();
140 570 bojilova
    this.permission = 0;
141
    this.ticketCount = 0;
142 802 bojilova
  //  this.publicAcc = null;
143 684 bojilova
    this.serverCode = serverCode;
144 638 bojilova
145 819 bojilova
    // read the access file from db connection
146 1214 tao
    DocumentImpl acldoc = new DocumentImpl(aclid);
147 819 bojilova
    String acl = acldoc.toString();
148
    this.rev = acldoc.getRev();
149
150
    // Initialize the parse
151 555 bojilova
    XMLReader parser = initializeParser();
152 819 bojilova
    // parse the access file and write the info to xml_access
153
    parser.parse(new InputSource(new StringReader(acl)));
154
155 555 bojilova
  }
156
157 819 bojilova
// NOT USED
158
//  /**
159
//   * Construct an instance of the AccessControlList class.
160
//   * It parses eml-access file and loads acl data into db connection.
161
//   * It is used from command line execution.
162
//   *
163
//   * @param conn the JDBC connection where acl data are loaded
164
//   * @param docid the Accession# of the document with the acl data
165
//   * @param aclfilename the name of acl file containing acl data
166
//   * @param user the user connected to MetaCat servlet and owns the document
167
//   * @param groups the groups to which user belongs
168
//   */
169
//  public AccessControlList( Connection conn, String aclid, String aclfilename,
170
//                           String user, String[] groups )
171
//                  throws SAXException, IOException, McdbException
172
//  {
173
//    this(conn, aclid, new FileReader(new File(aclfilename).toString()),
174
//         user, groups, 1);
175
//  }
176 638 bojilova
177 660 bojilova
  /* Set up the SAX parser for reading the XML serialized ACL */
178 555 bojilova
  private XMLReader initializeParser() throws SAXException
179
  {
180
    XMLReader parser = null;
181
182
    // Get an instance of the parser
183
    parser = XMLReaderFactory.createXMLReader(parserName);
184
185 598 bojilova
    // Turn off validation
186 638 bojilova
    parser.setFeature("http://xml.org/sax/features/validation", true);
187 598 bojilova
188
    // Set Handlers in the parser
189 555 bojilova
    // Set the ContentHandler to this instance
190 598 bojilova
    parser.setContentHandler((ContentHandler)this);
191 555 bojilova
192 598 bojilova
    // make a DBEntityResolver instance
193
    // Set the EntityReslover to DBEntityResolver instance
194 1214 tao
    EntityResolver eresolver = new DBEntityResolver(connection,this,null);
195 598 bojilova
    parser.setEntityResolver((EntityResolver)eresolver);
196
197 555 bojilova
    // Set the ErrorHandler to this instance
198 598 bojilova
    parser.setErrorHandler((ErrorHandler)this);
199 555 bojilova
200 862 berkley
    return parser;
201 555 bojilova
  }
202
203
  /**
204 688 bojilova
   * Callback method used by the SAX Parser when beginning of the document
205 645 bojilova
   */
206
  public void startDocument() throws SAXException
207
  {
208
    //delete all previously submitted permissions @ relations
209
    //this happens only on UPDATE of the access file
210
    try {
211 819 bojilova
      this.aclObjects = getACLObjects(aclid);
212 802 bojilova
213 819 bojilova
      //delete all permissions for resources related to @aclid if any
214 645 bojilova
      if ( aclid != null ) {
215
        deletePermissionsForRelatedResources(aclid);
216
      }
217
    } catch (SQLException sqle) {
218
      throw new SAXException(sqle);
219
    }
220
  }
221
222
  /**
223 688 bojilova
   * Callback method used by the SAX Parser when the start tag of an
224 555 bojilova
   * element is detected. Used in this context to parse and store
225
   * the acl information in class variables.
226
   */
227
  public void startElement (String uri, String localName,
228
                            String qName, Attributes atts)
229
         throws SAXException
230
  {
231 859 berkley
    instarttag = true;
232
    if(localName.equals("allow"))
233
    {
234
      tagName = "allow";
235
    }
236
    else if(localName.equals("deny"))
237
    {
238
      tagName = "deny";
239
    }
240 555 bojilova
    BasicNode currentNode = new BasicNode(localName);
241
    if (atts != null) {
242
      int len = atts.getLength();
243
      for (int i = 0; i < len; i++) {
244
        currentNode.setAttribute(atts.getLocalName(i), atts.getValue(i));
245
      }
246
    }
247 802 bojilova
    if ( currentNode.getTagName().equals("acl") ) {
248 570 bojilova
      permOrder = currentNode.getAttribute("order");
249 802 bojilova
    //  publicAcc = currentNode.getAttribute("public");
250 570 bojilova
    }
251 555 bojilova
    elementStack.push(currentNode);
252
  }
253
254
  /**
255 688 bojilova
   * Callback method used by the SAX Parser when the text sequences of an
256 555 bojilova
   * xml stream are detected. Used in this context to parse and store
257
   * the acl information in class variables.
258 859 berkley
   */
259 555 bojilova
  public void characters(char ch[], int start, int length)
260
         throws SAXException
261
  {
262 859 berkley
    if(!instarttag)
263
    {
264
      return;
265
    }
266 555 bojilova
    String inputString = new String(ch, start, length);
267 859 berkley
    inputString = inputString.trim();
268 862 berkley
    //System.out.println("==============inputString: " + inputString);
269 555 bojilova
    BasicNode currentNode = (BasicNode)elementStack.peek();
270
    String currentTag = currentNode.getTagName();
271
272 802 bojilova
      if (currentTag.equals("principal")) {
273 645 bojilova
274 802 bojilova
        principal.addElement(inputString);
275 645 bojilova
276 802 bojilova
      } else if (currentTag.equals("permission")) {
277 645 bojilova
278 802 bojilova
        if ( inputString.trim().toUpperCase().equals("READ") ) {
279
          permission = permission | READ;
280
        } else if ( inputString.trim().toUpperCase().equals("WRITE") ) {
281
          permission = permission | WRITE;
282 944 tao
        } else if ( inputString.trim().toUpperCase().equals("CHANGEPERMISSION"))
283
        {
284 862 berkley
          permission = permission | CHMOD;
285 802 bojilova
        } else if ( inputString.trim().toUpperCase().equals("ALL") ) {
286
          permission = permission | ALL;
287 862 berkley
        }/*else{
288 802 bojilova
          throw new SAXException("Unknown permission type: " + inputString);
289 859 berkley
        }*/
290 645 bojilova
291 802 bojilova
      } else if ( currentTag.equals("startDate") && beginTime == null ) {
292
        beginTime = inputString.trim();
293 645 bojilova
294 802 bojilova
      } else if ( currentTag.equals("stopDate") && endTime == null) {
295
        endTime = inputString.trim();
296 645 bojilova
297 802 bojilova
      } else if (currentTag.equals("ticketCount") && ticketCount == 0 ) {
298
        try {
299
          ticketCount = (new Integer(inputString.trim())).intValue();
300
        } catch (NumberFormatException nfe) {
301
          throw new SAXException("Wrong integer format for:" + inputString);
302
        }
303 555 bojilova
      }
304
  }
305
306
  /**
307 688 bojilova
   * Callback method used by the SAX Parser when the end tag of an
308 555 bojilova
   * element is detected. Used in this context to parse and store
309
   * the acl information in class variables.
310
   */
311
  public void endElement (String uri, String localName, String qName)
312
         throws SAXException
313
  {
314 859 berkley
    instarttag = false;
315 688 bojilova
    BasicNode leaving = (BasicNode)elementStack.pop();
316
    String leavingTagName = leaving.getTagName();
317
318 802 bojilova
    if ( leavingTagName.equals("allow") ||
319
         leavingTagName.equals("deny")    ) {
320 570 bojilova
321
      if ( permission > 0 ) {
322 555 bojilova
323 570 bojilova
        // insert into db calculated permission for the list of principals
324
        try {
325 802 bojilova
          // go through the objects in xml_relation about this acl doc
326
          for (int i=0; i < aclObjects.size(); i++) {
327
            // docid of the current object
328
            String docid = (String)aclObjects.elementAt(i);
329
            DocumentIdentifier docID = new DocumentIdentifier(docid);
330
            docid = docID.getIdentifier();
331
            insertPermissions(docid,leavingTagName);
332
          }
333 968 tao
334 1330 tao
          // if acl is not in object list
335 968 tao
          //should insert permission for aclid itself into database
336 1336 tao
          /*if (!aclObjects.contains(aclid))
337 1330 tao
          {
338
            DocumentIdentifier aclIdItself = new DocumentIdentifier(aclid);
339
            String aclIdString = aclIdItself.getIdentifier();
340
            insertPermissions(aclIdString,leavingTagName);
341 1336 tao
          }*/
342 968 tao
343 802 bojilova
344 570 bojilova
        } catch (SQLException sqle) {
345
          throw new SAXException(sqle);
346 802 bojilova
        } catch (Exception e) {
347
          throw new SAXException(e);
348 570 bojilova
        }
349
      }
350
351 688 bojilova
      // reset the allow/deny permission
352 660 bojilova
      principal = new Vector();
353 555 bojilova
      permission = 0;
354 570 bojilova
      beginTime = null;
355
      endTime = null;
356
      ticketCount = 0;
357 555 bojilova
358 570 bojilova
    }
359 555 bojilova
360
  }
361 598 bojilova
362 688 bojilova
  /**
363
    * SAX Handler that receives notification of DOCTYPE. Sets the DTD.
364
    * @param name name of the DTD
365
    * @param publicId Public Identifier of the DTD
366
    * @param systemId System Identifier of the DTD
367
    */
368 598 bojilova
  public void startDTD(String name, String publicId, String systemId)
369
              throws SAXException {
370
    docname = name;
371
    doctype = publicId;
372
    systemid = systemId;
373
  }
374
375
  /**
376 688 bojilova
   * SAX Handler that receives notification of the start of entities.
377
   * @param name name of the entity
378 598 bojilova
   */
379
  public void startEntity(String name) throws SAXException {
380
    if (name.equals("[dtd]")) {
381
      processingDTD = true;
382
    }
383
  }
384
385
  /**
386 688 bojilova
   * SAX Handler that receives notification of the end of entities.
387
   * @param name name of the entity
388 598 bojilova
   */
389
  public void endEntity(String name) throws SAXException {
390
    if (name.equals("[dtd]")) {
391
      processingDTD = false;
392
    }
393
  }
394
395
  /**
396 688 bojilova
   * Get the document name.
397 598 bojilova
   */
398
  public String getDocname() {
399
    return docname;
400
  }
401
402
  /**
403 688 bojilova
   * Get the document processing state.
404 598 bojilova
   */
405
  public boolean processingDTD() {
406
    return processingDTD;
407
  }
408
409 802 bojilova
  /* Get all objects associated with @aclid from db.*/
410
  private Vector getACLObjects(String aclid)
411 638 bojilova
          throws SQLException
412
  {
413 802 bojilova
    Vector aclObjects = new Vector();
414 1214 tao
    DBConnection conn = null;
415
    int serialNumber = -1;
416
    PreparedStatement pstmt = null;
417
    try
418
    {
419
      //get connection from DBConnectionPool
420
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACLObject");
421
      serialNumber=conn.getCheckOutSerialNumber();
422
423
      // delete all acl records for resources related to @aclid if any
424
      pstmt = conn.prepareStatement(
425 802 bojilova
                             "SELECT object FROM xml_relation " +
426 830 jones
                             "WHERE subject = ? ");
427 1214 tao
      pstmt.setString(1,aclid);
428
      pstmt.execute();
429
      ResultSet rs = pstmt.getResultSet();
430
      boolean hasRows = rs.next();
431
      while (hasRows) {
432
        aclObjects.addElement(rs.getString(1));
433
        hasRows = rs.next();
434
      }//whil
435 802 bojilova
    }
436 1214 tao
    catch (SQLException e)
437
    {
438
      throw e;
439
    }
440
    finally
441
    {
442
      try
443
      {
444
        pstmt.close();
445
      }
446
      finally
447
      {
448
        //retrun DBConnection
449
        DBConnectionPool.returnDBConnection(conn,serialNumber);
450
      }
451
    }
452 802 bojilova
453
    return aclObjects;
454 638 bojilova
  }
455
456 802 bojilova
  /* Delete from db all permission for resources related to @aclid if any.*/
457
  private void deletePermissionsForRelatedResources(String aclid)
458 638 bojilova
          throws SQLException
459
  {
460 1214 tao
    //DBConnection conn = null;
461
    //int serialNumber = -1;
462
    Statement stmt = null;
463
    try
464
    {
465
      //check out DBConenction
466
      //conn=DBConnectionPool.getDBConnection("AccessControlList.deltePerm");
467
      //serialNumber=conn.getCheckOutSerialNumber();
468
      // delete all acl records for resources related to @aclid if any
469
      stmt = connection.createStatement();
470
      // Increase DBConnection usage count
471
      connection.increaseUsageCount(1);
472
      stmt.execute("DELETE FROM xml_access WHERE accessfileid = '" + aclid
473
                                                                      + "'");
474
      //increase usageCount!!!!!!
475
      //conn.increaseUsageCount(1);
476
    }
477
    catch (SQLException e)
478
    {
479
      throw e;
480
    }
481
    finally
482
    {
483
      stmt.close();
484
      //retrun DBConnection
485
      //DBConnectionPool.returnDBConnection(conn,serialNumber);
486
    }
487 645 bojilova
  }
488
489 1214 tao
  /* Insert into db calculated permission for the list of principals
490
   * The DBConnection it is use is class field. Because we want to keep rollback
491
   * features and it need use same connection
492
  */
493
494 802 bojilova
  private void insertPermissions(String docid, String permType )
495 1214 tao
                                            throws SQLException
496 555 bojilova
  {
497 1214 tao
    PreparedStatement pstmt = null;
498
    //DBConnection conn = null;
499
    //int serialNumber = -1;
500 555 bojilova
    try {
501 1214 tao
      //Check out DBConnection
502
      //conn=DBConnectionPool.getDBConnection("AccessControlList.insertPerm");
503
      //serialNumber=conn.getCheckOutSerialNumber();
504
505
      pstmt = connection.prepareStatement(
506 555 bojilova
              "INSERT INTO xml_access " +
507 645 bojilova
              "(docid, principal_name, permission, perm_type, perm_order," +
508 1750 tao
              "ticket_count, accessfileid) VALUES " +
509
              "(?,?,?,?,?,?,?)");
510 1214 tao
      // Increase DBConnection usage count
511
      connection.increaseUsageCount(1);
512 555 bojilova
      // Bind the values to the query
513 802 bojilova
      pstmt.setString(1, docid);
514 570 bojilova
      pstmt.setInt(3, permission);
515
      pstmt.setString(4, permType);
516
      pstmt.setString(5, permOrder);
517 1750 tao
      pstmt.setString(7, aclid);
518 570 bojilova
      if ( ticketCount > 0 ) {
519 1750 tao
        pstmt.setString(6, "" + ticketCount);
520 570 bojilova
      } else {
521 1750 tao
        pstmt.setString(6, null);
522 570 bojilova
      }
523 1214 tao
524
      //incrase usagecount for DBConnection
525
      //conn.increaseUsageCount(1);
526 688 bojilova
      String prName;
527 802 bojilova
      for ( int j = 0; j < principal.size(); j++ ) {
528
        prName = (String)principal.elementAt(j);
529
        pstmt.setString(2, prName);
530
        pstmt.execute();
531
      /*
532
        // check if there are conflict with permission's order
533
        String permOrderOpos = permOrder;
534
        int perm = getPermissions(permission, prName, docid, permOrder);
535
        if (  perm != 0 ) {
536
          if ( permOrder.equals("allowFirst") ) {
537
            permOrderOpos = "denyFirst";
538
          } else if ( permOrder.equals("denyFirst") ) {
539
            permOrderOpos = "allowFirst";
540 688 bojilova
          }
541 802 bojilova
          throw new SQLException("Permission(s) " + txtValue(perm) +
542
                    " for \"" + prName + "\" on document #" + docid +
543
                    " has/have been used with \"" + permOrderOpos + "\"");
544 665 bojilova
        }
545 802 bojilova
      */
546 570 bojilova
      }
547 672 bojilova
      pstmt.close();
548 555 bojilova
549 570 bojilova
    } catch (SQLException e) {
550
      throw new
551
      SQLException("AccessControlList.insertPermissions(): " + e.getMessage());
552 672 bojilova
    }
553 1214 tao
    finally
554
    {
555
      pstmt.close();
556
      //return the DBConnection
557
      //DBConnectionPool.returnDBConnection(conn, serialNumber);
558
    }
559 672 bojilova
  }
560
561 688 bojilova
  /* Get permissions with permission order different than @permOrder. */
562
  private int getPermissions(int permission, String principal,
563
                             String docid, String permOrder)
564
          throws SQLException
565
  {
566 1214 tao
    PreparedStatement pstmt = null;
567
    DBConnection conn = null;
568
    int serialNumber = -1;
569
    try
570
    {
571
      //check out DBConnection
572
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPermissions");
573
      serialNumber=conn.getCheckOutSerialNumber();
574
      pstmt = conn.prepareStatement(
575 688 bojilova
            "SELECT permission FROM xml_access " +
576 765 bojilova
            "WHERE docid = ? " +
577
            "AND principal_name = ? " +
578
            "AND perm_order NOT = ?");
579 1214 tao
      pstmt.setString(1, docid);
580
      pstmt.setString(2, principal);
581
      pstmt.setString(3, permOrder);
582
      pstmt.execute();
583
      ResultSet rs = pstmt.getResultSet();
584
      boolean hasRow = rs.next();
585
      int perm = 0;
586
      while ( hasRow ) {
587
        perm = rs.getInt(1);
588
        perm = permission & perm;
589
        if ( perm != 0 ) {
590
          pstmt.close();
591
          return perm;
592
        }
593
        hasRow = rs.next();
594
      }
595
    }//try
596
    catch (SQLException e)
597
    {
598
      throw e;
599
    }
600
    finally
601
    {
602
      try
603
      {
604 1139 tao
        pstmt.close();
605 688 bojilova
      }
606 1214 tao
      finally
607
      {
608
        DBConnectionPool.returnDBConnection(conn, serialNumber);
609
      }
610 688 bojilova
    }
611
    return 0;
612
  }
613
614
  /* Get the int value of READ, WRITE or ALL. */
615 1368 tao
  public static int intValue ( String permission )
616 688 bojilova
  {
617 1368 tao
    if ( permission.equalsIgnoreCase("READ") ) {
618 688 bojilova
      return READ;
619 1368 tao
    } else if ( permission.equalsIgnoreCase("WRITE") ) {
620 688 bojilova
      return WRITE;
621 1368 tao
    } else if ( permission.equalsIgnoreCase("ALL") ) {
622 688 bojilova
      return ALL;
623
    }
624
625
    return -1;
626
  }
627
628
  /* Get the text value of READ, WRITE or ALL. */
629
  private String txtValue ( int permission )
630
  {
631
    StringBuffer txtPerm = new StringBuffer("\"");
632
    if ( (permission & READ) != 0 ) {
633
      txtPerm.append("read");
634
    }
635
    if ( (permission & WRITE) != 0 ) {
636
      if ( txtPerm.length() > 0 ) txtPerm.append(",");
637
      txtPerm.append("write");
638
    }
639
    if ( (permission & ALL) != 0 ) {
640
      if ( txtPerm.length() > 0 ) txtPerm.append(",");
641
      txtPerm.append("all");
642
    }
643
644
    return txtPerm.append("\"").toString();
645
  }
646
647 802 bojilova
  /**
648 688 bojilova
    * Get Access Control List information for document from db connetion.
649
    * User or Group should have permissions for reading
650
    * access control information for a document specified by @docid.
651
    * @param docid document identifier which acl info to get
652
    * @param user name of user connected to Metacat system
653 802 bojilova
    * @param groups names of user's groups to which user belongs
654 688 bojilova
    */
655 802 bojilova
  public String getACL(String docid, String user, String[] groups)
656 959 tao
          throws SQLException, Exception
657 570 bojilova
  {
658 688 bojilova
    StringBuffer output = new StringBuffer();
659
    StringBuffer outTemp = new StringBuffer();
660
    MetaCatUtil util = new MetaCatUtil();
661
    String accDoctype = util.getOption("accessdoctype");
662
    String server = util.getOption("server");
663
    String docurl = "metacat://" + server + "/?docid=" + docid;
664
    String systemID;
665
    boolean isOwned = false;
666
    boolean hasPermission = false;
667
    String publicAcc;
668 570 bojilova
669 688 bojilova
    String acfid = "";
670
    String acfid_prev = "";
671
    String principal;
672
    Vector principalArr = new Vector();
673
    int permission;
674
    int perm_prev = -1;
675
    String permType;
676
    String permOrder = "";
677
    String permOrder_prev = "";
678
    String beginTime = "";
679
    String begin_prev = "";
680
    String endTime = "";
681
    String end_prev = "";
682
    int ticketCount = -1;
683
    int ticket_prev = -1;
684 1214 tao
    DBConnection conn = null;
685
    int serialNumber = -1;
686
    PreparedStatement pstmt = null;
687 638 bojilova
    try {
688 688 bojilova
689 1214 tao
      //check out DBConnection
690
      conn=DBConnectionPool.getDBConnection("AccessControlList.getACL");
691
      serialNumber=conn.getCheckOutSerialNumber();
692
693 688 bojilova
      isOwned = isOwned(docid, user);
694 944 tao
      systemID = getSystemID((String)MetaCatUtil.
695
                                      getOptionList(accDoctype).elementAt(0));
696 688 bojilova
      publicAcc = getPublicAccess(docid);
697
698
      output.append("<?xml version=\"1.0\"?>\n");
699
      output.append("<!DOCTYPE acl PUBLIC \"" + accDoctype + "\" \"" +
700
                    systemID + "\">\n");
701
      output.append("<acl authSystem=\"\">\n");
702
703 1214 tao
704 688 bojilova
      pstmt = conn.prepareStatement(
705
              "SELECT distinct accessfileid, principal_name, permission, " +
706
              "perm_type, perm_order, to_char(begin_time,'mm/dd/yyyy'), " +
707
              "to_char(end_time,'mm/dd/yyyy'), ticket_count " +
708 765 bojilova
              "FROM xml_access WHERE docid = ? " +
709 688 bojilova
              "ORDER BY accessfileid, perm_order, perm_type, permission");
710
      // Bind the values to the query
711
      pstmt.setString(1, docid);
712
      pstmt.execute();
713
      ResultSet rs = pstmt.getResultSet();
714
      boolean hasRows = rs.next();
715
      while (hasRows) {
716
717
        acfid = rs.getString(1);
718
        principal = rs.getString(2);
719
        permission = rs.getInt(3);
720
        permType = rs.getString(4);
721
        permOrder = rs.getString(5);
722
        beginTime = rs.getString(6);
723
        endTime = rs.getString(7);
724
        ticketCount = rs.getInt(8);
725
726
        // if @docid is not owned by @user, only ACL info from that
727 802 bojilova
        // access files to which @user/@groups has "read" permission
728 688 bojilova
        // is extracted
729
        if ( !isOwned ) {
730
          if ( !acfid.equals(acfid_prev) ) {
731
            acfid_prev = acfid;
732 1426 tao
            //hasPermission = this.hasPermission("READ",user,groups,acfid);
733
             PermissionController controller = new PermissionController(acfid);
734
             hasPermission = controller.hasPermission(user,groups,
735
                                            AccessControlInterface.READSTRING);
736 688 bojilova
          }
737
          if ( !hasPermission ) {
738
            rs.next();
739
            continue;
740
          }
741
        }
742
743
        // open <resource> tag
744
        if ( !permOrder.equals(permOrder_prev) ) {
745
          // close </resource> tag if any was opened
746
          output.append(outTemp.toString());
747
          outTemp = new StringBuffer();
748
          if ( !permOrder_prev.equals("") ) {
749
            output.append("  </resource>\n");
750
          }
751
          output.append("  <resource order=\"" + permOrder + "\" public=\"" +
752
                        publicAcc + "\">\n");
753
          output.append("    <resourceIdentifier>" + docurl +
754
                        "</resourceIdentifier>\n");
755
          permOrder_prev = permOrder;
756
        }
757
758
        // close </allow> or </deny> tag then open new one
759
        if ( permission != perm_prev ||
760
             (endTime == null) && (end_prev != null) ||
761
             (beginTime == null) && (begin_prev != null) ||
762
             endTime != null && !endTime.equals(end_prev)  ||
763
             beginTime != null && !beginTime.equals(begin_prev) ||
764
             ticketCount != ticket_prev )  {
765
          output.append(outTemp.toString());
766
          outTemp = new StringBuffer();
767
          principalArr.removeAllElements();
768
          output.append("    <" + permType + ">\n");
769
        }
770
771
        // put all principals here for the same
772
        // permission, duration and ticket_count
773
        if ( !principalArr.contains(principal) ) {
774
          principalArr.addElement(principal);
775
          output.append("      <principal>" + principal + "</principal>\n");
776
        }
777
778
        // prepare <permission> tags, <duration> and <ticketCount>
779
        // if any to put within <allow> (<deny>) by next cicle
780
        if ( permission != perm_prev ||
781
             (endTime == null) && (end_prev != null) ||
782
             (beginTime == null) && (begin_prev != null) ||
783
             endTime != null && !endTime.equals(end_prev)  ||
784
             beginTime != null && !beginTime.equals(begin_prev) ||
785
             ticketCount != ticket_prev )  {
786
          if ( (permission & READ) != 0 ) {
787
            outTemp.append("      <permission>read</permission>\n");
788
          }
789
          if ( (permission & WRITE) != 0 ) {
790
            outTemp.append("      <permission>write</permission>\n");
791
          }
792
          if ( (permission & ALL) != 0 ) {
793
            outTemp.append("      <permission>all</permission>\n");
794
          }
795
          if ( (beginTime != null) || (endTime != null) ) {
796
            outTemp.append("      <duration>" + beginTime + " " + endTime +
797
                          "</duration>\n");
798
          }
799
          if ( ticketCount > 0 ) {
800
            outTemp.append("      <ticketCount>" + ticketCount +
801
                          "</ticketCount>\n");
802
          }
803
          outTemp.append("    </" + permType + ">\n");
804
          perm_prev = permission;
805
          ticket_prev = ticketCount;
806
          begin_prev = beginTime;
807
          end_prev = endTime;
808
        }
809
810
        hasRows = rs.next();
811 652 bojilova
      }
812 688 bojilova
813
      // close <allow> or <deny> if anything left in outTemp var
814
      output.append(outTemp.toString());
815
816
      // If there are no any acl info for @docid accessible by @user/@group,
817
      // extract only the following information
818
      if ( permOrder.equals("") ) {
819
        output.append("  <resource public=\"" + publicAcc + "\">\n");
820
        output.append("    <resourceIdentifier>" + docurl +
821
                      "</resourceIdentifier>\n");
822
      }
823
824
      // always close them
825
      output.append("  </resource>\n");
826
      output.append("</acl>\n");
827
828
      pstmt.close();
829
830
      return output.toString();
831
832
    } catch (SQLException e) {
833
      throw new
834
      SQLException("AccessControlList.getACL(). " + e.getMessage());
835 638 bojilova
    }
836 1214 tao
    finally
837
    {
838
      try
839
      {
840
        pstmt.close();
841
      }
842
      finally
843
      {
844
        DBConnectionPool.returnDBConnection(conn, serialNumber);
845
      }
846
    }
847 688 bojilova
  }
848
849
  /* Check if @user is owner of @docid from db conn. */
850
  private boolean isOwned(String docid, String user) throws SQLException {
851
852 1214 tao
    PreparedStatement pstmt = null;
853
    DBConnection conn = null;
854
    int serialNumber = -1;
855
    try
856
    {
857
      //check out DBConnection
858
      conn=DBConnectionPool.getDBConnection("AccessControlList.isOwned");
859
      serialNumber=conn.getCheckOutSerialNumber();
860
      pstmt = conn.prepareStatement("SELECT 'x' FROM xml_documents " +
861 765 bojilova
                                  "WHERE docid = ? " +
862
                                  "AND user_owner = ?");
863 1214 tao
      pstmt.setString(1, docid);
864
      pstmt.setString(2, user);
865
      pstmt.execute();
866
      ResultSet rs = pstmt.getResultSet();
867
      boolean hasRow = rs.next();
868
      return hasRow;
869
    }
870
    finally
871
    {
872
      try
873
      {
874
        pstmt.close();
875
      }
876
      finally
877
      {
878
        DBConnectionPool.returnDBConnection(conn, serialNumber);
879
      }
880
    }
881 688 bojilova
  }
882 652 bojilova
883 688 bojilova
  /* Get the flag for public "read" access for @docid from db conn. */
884
  private String getPublicAccess(String docid) throws SQLException {
885
886
    int publicAcc = 0;
887 1214 tao
    PreparedStatement pstmt = null;
888
    DBConnection conn = null;
889
    int serialNumber = -1;
890
    try
891
    {
892
      //check out DBConnection
893
      conn=DBConnectionPool.getDBConnection("AccessControlList.getPublicAcces");
894
      serialNumber=conn.getCheckOutSerialNumber();
895
      pstmt = conn.prepareStatement("SELECT public_access FROM xml_documents " +
896 765 bojilova
                                  "WHERE docid = ?");
897 1214 tao
      pstmt.setString(1, docid);
898
      pstmt.execute();
899
      ResultSet rs = pstmt.getResultSet();
900
      boolean hasRow = rs.next();
901
      if ( hasRow ) {
902
        publicAcc = rs.getInt(1);
903
      }
904
905
      return (publicAcc == 1) ? "yes" : "no";
906 1139 tao
    }
907 1214 tao
    finally
908
    {
909
      try
910
      {
911
        pstmt.close();
912
      }
913
      finally
914
      {
915
        DBConnectionPool.returnDBConnection(conn, serialNumber);
916
      }
917
    }
918 688 bojilova
  }
919
920
  /* Get SystemID for @publicID from Metacat DB Catalog. */
921
  private String getSystemID(String publicID) throws SQLException {
922
923
    String systemID = "";
924 1214 tao
    PreparedStatement pstmt = null;
925
    DBConnection conn = null;
926
    int serialNumber = -1;
927
928
    try
929
    {
930
      //check out DBConnection
931
      conn=DBConnectionPool.getDBConnection("AccessControlList.getSystemID");
932
      serialNumber=conn.getCheckOutSerialNumber();
933
934
      pstmt = conn.prepareStatement("SELECT system_id FROM xml_catalog " +
935 688 bojilova
                                  "WHERE entry_type = 'DTD' " +
936 765 bojilova
                                  "AND public_id = ?");
937 1214 tao
      pstmt.setString(1, publicID);
938
      pstmt.execute();
939
      ResultSet rs = pstmt.getResultSet();
940
      boolean hasRow = rs.next();
941
      if ( hasRow ) {
942
        systemID = rs.getString(1);
943
      }
944 688 bojilova
945 1214 tao
      return systemID;
946
    }//try
947
    finally
948
    {
949
950
      try
951
      {
952
        pstmt.close();
953
      }
954
      finally
955
      {
956
        DBConnectionPool.returnDBConnection(conn, serialNumber);
957
      }
958
    }//finally
959 688 bojilova
  }
960
961 555 bojilova
}