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