/** * '$RCSfile$' * Copyright: 2008 Regents of the University of California and the * National Center for Ecological Analysis and Synthesis * Purpose: To test the Access Controls in metacat by JUnit * * '$Author$' * '$Date$' * '$Revision$' * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package edu.ucsb.nceas; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.Reader; import java.io.StringReader; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.HashMap; import java.util.Hashtable; import java.util.Vector; import junit.framework.TestCase; import org.apache.http.client.HttpClient; import org.apache.http.impl.client.DefaultHttpClient; import edu.ucsb.nceas.metacat.authentication.AuthFile; import edu.ucsb.nceas.metacat.client.InsufficientKarmaException; import edu.ucsb.nceas.metacat.client.Metacat; import edu.ucsb.nceas.metacat.client.MetacatException; import edu.ucsb.nceas.metacat.client.MetacatFactory; import edu.ucsb.nceas.metacat.client.MetacatInaccessibleException; import edu.ucsb.nceas.metacat.database.DBConnection; import edu.ucsb.nceas.metacat.database.DBConnectionPool; import edu.ucsb.nceas.metacat.properties.PropertyService; import edu.ucsb.nceas.metacat.shared.ServiceException; import edu.ucsb.nceas.metacat.util.DocumentUtil; import edu.ucsb.nceas.metacat.util.RequestUtil; import edu.ucsb.nceas.metacat.util.SystemUtil; import edu.ucsb.nceas.utilities.IOUtil; import edu.ucsb.nceas.utilities.PropertyNotFoundException; import edu.ucsb.nceas.utilities.SortedProperties; /** * A base JUnit class for Metacat tests */ public class MCTestCase extends TestCase { private static boolean printDebug = false; protected static String EML2_0_0 = "EML2_0_0"; protected static String EML2_0_1 = "EML2_0_1"; protected static String EML2_1_0 = "EML2_1_0"; protected static String EML2_1_1 = "EML2_1_1"; protected static final String AUTHFILECLASSNAME = "edu.ucsb.nceas.metacat.authentication.AuthFile"; private static final String KNBUSERGOURP = "cn=knb-usr,o=NCEAS,dc=ecoinformatics,dc=org"; protected boolean SUCCESS = true; protected boolean FAILURE = false; protected static final String ALLOWFIRST = "allowFirst"; protected static final String DENYFIRST = "denyFirst"; protected String testdatadir = "test/clienttestfiles/"; protected String prefix = "test"; protected String testdocument = ""; protected static HttpClient httpClient = null; protected static boolean metacatConnectionNeeded = false; protected Metacat m; protected static String metacatUrl; protected static String username; protected static String password; protected static String anotheruser; protected static String anotherpassword; private static String lteruser; private static String lterpassword; protected static String referraluser; protected static String referralpassword; protected static String piscouser; protected static String piscopassword; protected static String metacatContextDir; static { try { SortedProperties testProperties = new SortedProperties("build/tests/test.properties"); testProperties.load(); metacatContextDir = testProperties.getProperty("metacat.contextDir"); PropertyService.getInstance(metacatContextDir + "/WEB-INF"); // PropertyService.getInstance(); String printDebugString = PropertyService.getProperty("test.printdebug"); printDebug = Boolean.parseBoolean(printDebugString); metacatUrl = SystemUtil.getServletURL(); //System.out.println("The metacat url (servlet) is ==================== "+metacatUrl); username = PropertyService.getProperty("test.mcUser"); password = PropertyService.getProperty("test.mcPassword"); anotheruser = PropertyService.getProperty("test.mcAnotherUser"); anotherpassword = PropertyService.getProperty("test.mcAnotherPassword"); lteruser = PropertyService.getProperty("test.lterUser"); lterpassword = PropertyService.getProperty("test.lterPassword"); referraluser = PropertyService.getProperty("test.referralUser"); referralpassword = PropertyService.getProperty("test.referralPassword"); piscouser = PropertyService.getProperty("test.piscoUser"); piscopassword = PropertyService.getProperty("test.piscoPassword"); String authenClass = PropertyService.getProperty("auth.class"); if(authenClass != null && authenClass.equals(AUTHFILECLASSNAME)) { //add those test users to the authentication file AuthFile authFile = new AuthFile(); try { String description = null; authFile.addGroup(KNBUSERGOURP, description); } catch (Exception e) { System.out.println("Couldn't add the group "+KNBUSERGOURP+" to the password file since "+e.getMessage()); } String[] groups = null; try { authFile.addUser(username, groups, password, null, null, null, null, null); } catch (Exception e) { System.out.println("Couldn't add the user "+username+" to the password file since "+e.getMessage()); } try { String[] anotherGroup = {KNBUSERGOURP}; authFile.addUser(anotheruser, anotherGroup, anotherpassword, null, null, null, null, null); } catch (Exception e) { System.out.println("Couldn't add the user "+anotheruser+" to the password file since "+e.getMessage()); } try { authFile.addUser(lteruser, groups, lterpassword, null, null, null, null, null); } catch (Exception e) { System.out.println("Couldn't add the user "+lteruser+" to the password file since "+e.getMessage()); } try { authFile.addUser(referraluser, groups, referralpassword, null, null, null, null, null); } catch (Exception e) { System.out.println("Couldn't add the user "+referraluser+" to the password file since "+e.getMessage()); } try { authFile.addUser(piscouser, groups, piscopassword, null, null, null, null, null); } catch (Exception e) { System.out.println("Couldn't add the user "+piscouser+" to the password file since "+e.getMessage()); } } } catch (IOException ioe) { System.err.println("Could not read property file in static block: " + ioe.getMessage()); } catch (PropertyNotFoundException pnfe) { System.err.println("Could not get property in static block: " + pnfe.getMessage()); } catch (ServiceException se) { System.err.println("Could not get PropertyService instance in static block: " + se.getMessage()); } } // header blocks protected String testEml_200_Header = ""; protected String testEml_201_Header = ""; protected String testEml_210_Header = ""; protected String testEml_211_Header = ""; protected String testEmlCreatorBlock = " " + " " + " Smith " + " " + " "; protected String testEmlContactBlock = " " + " " + " Jackson " + " " + " "; protected String testEmlInlineBlock1 = " " + " " + " " + " Operator " + " PSI " + " " + " " + " "; protected String testEmlInlineBlock2 = " " + " " + " LCQ " + " " + " " + " " + " "; /** * Returns an xml squery that searches for the doc id in the * title of documents. This function is for eml-2.0.1+ only. For * other eml versions, this function might have to modified. */ protected String getTestEmlQuery(String titlePart, String emlVersion) { String docType; if (emlVersion.equals(EML2_0_1)) { docType = "eml://ecoinformatics.org/eml-2.0.1"; } else if (emlVersion.equals(EML2_1_0)) { docType = "eml://ecoinformatics.org/eml-2.1.0"; } else { //if (emlVersion.equals(EML2_1_1)) { docType = "eml://ecoinformatics.org/eml-2.1.1"; } String sQuery = ""; sQuery = "" + "unspecified" + "unspecified" + "dataset/title" + "" + docType + "" + "" + "" + "" + titlePart + "" + "dataset/title" + "" + "" + ""; return sQuery; } /** * Query a document by looking for a part of the title in the title element. * Then check if the testTitle exists in the doc. * @param titlePart the part of the title of the doc to look for * @param testTitle the title containing special characters * @param result are we expecting SUCCESS or FAILURE * @param expextedKarmaFailure */ protected void queryDocWhichHasTitle(String titlePart, String testTitle, String emlVersion, boolean result) { try { String sQuery = getTestEmlQuery(titlePart, emlVersion); Reader queryReader = new StringReader(sQuery); Reader resultReader = m.query(queryReader); String queryResult = IOUtil.getAsString(resultReader, true); if (result) { if (!queryResult.contains(testTitle)) { debug("queryResult: " + queryResult); debug("does not contain title: " + testTitle); } assertTrue(queryResult.contains(testTitle)); } else { assertTrue(queryResult.indexOf("") != -1); } } catch (MetacatInaccessibleException mie) { fail("Metacat Inaccessible:\n" + mie.getMessage()); } catch (Exception e) { fail("General exception:\n" + e.getMessage()); } } /* * Retrus an access block base on params passed and the defaul perm order - * allow first */ protected String getAccessBlock(String principal, boolean grantAccess, boolean read, boolean write, boolean changePermission, boolean all) { return getAccessBlock(principal, grantAccess, read, write, changePermission, all, ALLOWFIRST); } /** * This function returns an access block based on the params passed */ protected String getAccessBlock(String principal, boolean grantAccess, boolean read, boolean write, boolean changePermission, boolean all, String permOrder) { String accessBlock = ""; accessBlock += generateOneAccessRule(principal, grantAccess, read, write, changePermission, all); accessBlock += ""; return accessBlock; } /* * Gets eml access block base on given acccess rules and perm order */ protected String getAccessBlock(Vector accessRules, String permOrder) { String accessBlock = ""; // adding rules if (accessRules != null && !accessRules.isEmpty()) { for (int i = 0; i < accessRules.size(); i++) { String rule = (String) accessRules.elementAt(i); accessBlock += rule; } } accessBlock += ""; return accessBlock; } /* * Generates a access rule for given parameter. Note this xml portion * doesn't include */ protected String generateOneAccessRule(String principal, boolean grantAccess, boolean read, boolean write, boolean changePermission, boolean all) { String accessBlock = ""; if (grantAccess) { accessBlock = ""; } else { accessBlock = ""; } accessBlock = accessBlock + "" + principal + ""; if (all) { accessBlock += "all"; } else { if (read) { accessBlock += "read"; } if (write) { accessBlock += "write"; } if (changePermission) { accessBlock += "changePermission"; } } if (grantAccess) { accessBlock += ""; } else { accessBlock += ""; } return accessBlock; } /** * This function returns a valid eml document with public read access */ protected String getTestEmlDoc(String title, String emlVersion) { String testDocument = ""; String header; if (emlVersion == EML2_0_1) { header = testEml_201_Header; } else if (emlVersion == EML2_1_0) { header = testEml_210_Header; } else { // if (emlVersion == EML2_1_1) { header = testEml_211_Header; } testDocument += header; // if this is an EML 2.1.0 or later document, the document level access is // before the dataset element. if (emlVersion == EML2_1_0 || emlVersion == EML2_1_1) { testDocument += getAccessBlock("public", true, true, false, false, false); } testDocument += "" + title + "" + testEmlCreatorBlock; testDocument += testEmlContactBlock; // if this is an EML 2.0.1 or earlier document, the document level access is // inside the dataset element. if (emlVersion != EML2_1_0 && emlVersion != EML2_1_1) { testDocument += getAccessBlock("public", true, true, false, false, false); } testDocument += ""; testDocument += ""; return testDocument; } /** * This function returns a valid eml document with no access rules */ protected String getTestEmlDoc(String title, String emlVersion, String inlineData1, String inlineData2, String onlineUrl1, String onlineUrl2, String docAccessBlock, String inlineAccessBlock1, String inlineAccessBlock2, String onlineAccessBlock1, String onlineAccessBlock2) { debug("getTestEmlDoc(): title=" + title + " inlineData1=" + inlineData1 + " inlineData2=" + inlineData2 + " onlineUrl1=" + onlineUrl1 + " onlineUrl2=" + onlineUrl2 + " docAccessBlock=" + docAccessBlock + " inlineAccessBlock1=" + inlineAccessBlock1 + " inlineAccessBlock2=" + inlineAccessBlock2 + " onlineAccessBlock1=" + onlineAccessBlock1 + " onlineAccessBlock2=" + onlineAccessBlock2); String testDocument = ""; String header; if (emlVersion == EML2_0_0) { header = testEml_200_Header; } else if (emlVersion == EML2_0_1) { header = testEml_201_Header; } else if (emlVersion == EML2_1_0) { header = testEml_210_Header; } else { // if (emlVersion == EML2_1_1) { header = testEml_211_Header; } testDocument += header; // if this is a 2.1.0+ document, the document level access block sits // at the same level and before the dataset element. if (docAccessBlock != null && (emlVersion.equals(EML2_1_0) || emlVersion.equals(EML2_1_1))) { testDocument += docAccessBlock; } testDocument += "" + title + "" + testEmlCreatorBlock; if (inlineData1 != null) { testDocument = testDocument + "" + inlineData1 + ""; } if (inlineData2 != null) { testDocument = testDocument + "" + inlineData2 + ""; } if (onlineUrl1 != null) { testDocument = testDocument + "" + "" + onlineUrl1 + ""; } if (onlineUrl2 != null) { testDocument = testDocument + "" + "" + onlineUrl2 + ""; } testDocument += testEmlContactBlock; // if this is a 2.0.X document, the document level access block sits // inside the dataset element. if (docAccessBlock != null && (emlVersion.equals(EML2_0_0) || emlVersion.equals(EML2_0_1))) { testDocument += docAccessBlock; } testDocument += ""; if (inlineAccessBlock1 != null) { testDocument += ""; testDocument += "inlineEntity1"; testDocument += inlineAccessBlock1; testDocument += ""; } if (inlineAccessBlock2 != null) { testDocument += ""; testDocument += "inlineEntity2"; testDocument += inlineAccessBlock2; testDocument += ""; } if (onlineAccessBlock1 != null) { testDocument += ""; testDocument += "onlineEntity1"; testDocument += onlineAccessBlock1; testDocument += ""; } if (onlineAccessBlock2 != null) { testDocument += ""; testDocument += "onlineEntity2"; testDocument += onlineAccessBlock2; testDocument += ""; } testDocument += ""; // System.out.println("Returning following document" + testDocument); return testDocument; } /** * */ protected String getTestDocFromFile(String filePath) throws IOException{ StringBuffer output = new StringBuffer(); FileReader fileReader = new FileReader(new File(filePath)); BufferedReader bufferedReader = new BufferedReader(fileReader); String readLine = null; while ((readLine = bufferedReader.readLine()) != null) { output.append(readLine); } return output.toString(); } /** * Constructor to build the test */ public MCTestCase() { super(); } /** * Constructor to build the test * * @param name the name of the test method */ public MCTestCase(String name) { super(name); } /** * Establish a testing framework by initializing appropriate objects */ protected void setUp() throws Exception { try { if (metacatConnectionNeeded) { debug("setUp() - Testing Metacat Url: " + metacatUrl); m = MetacatFactory.createMetacatConnection(metacatUrl); } } catch (MetacatInaccessibleException mie) { System.err.println("Metacat is: " + metacatUrl); fail("Metacat connection failed." + mie.getMessage()); } } protected static void debug(String debugMessage) { if (printDebug) { System.err.println(debugMessage); } } protected static Vector> dbSelect(String sqlStatement, String methodName) throws SQLException { Vector> resultVector = new Vector>(); DBConnectionPool connPool = DBConnectionPool.getInstance(); DBConnection dbconn = DBConnectionPool.getDBConnection(methodName); int serialNumber = dbconn.getCheckOutSerialNumber(); PreparedStatement pstmt = null; debug("Selecting from db: " + sqlStatement); pstmt = dbconn.prepareStatement(sqlStatement); pstmt.execute(); ResultSet resultSet = pstmt.getResultSet(); ResultSetMetaData rsMetaData = resultSet.getMetaData(); int numColumns = rsMetaData.getColumnCount(); debug("Number of data columns: " + numColumns); while (resultSet.next()) { Hashtable hashTable = new Hashtable(); for (int i = 1; i <= numColumns; i++) { if (resultSet.getObject(i) != null) { hashTable.put(rsMetaData.getColumnName(i), resultSet.getObject(i)); } } debug("adding data row to result vector"); resultVector.add(hashTable); } resultSet.close(); pstmt.close(); DBConnectionPool.returnDBConnection(dbconn, serialNumber); return resultVector; } protected static void dbQuery(String sqlStatement, String methodName) throws SQLException { DBConnection dbconn = DBConnectionPool.getDBConnection(methodName); int serialNumber = dbconn.getCheckOutSerialNumber(); PreparedStatement statement = dbconn.prepareStatement(sqlStatement); debug("Executing against db: " + sqlStatement); statement.executeQuery(); statement.close(); DBConnectionPool.returnDBConnection(dbconn, serialNumber); } protected static void dbUpdate(String sqlStatement, String methodName) throws SQLException { DBConnection dbconn = DBConnectionPool.getDBConnection(methodName); int serialNumber = dbconn.getCheckOutSerialNumber(); PreparedStatement statement = dbconn.prepareStatement(sqlStatement); debug("Executing against db: " + sqlStatement); statement.executeUpdate(); statement.close(); DBConnectionPool.returnDBConnection(dbconn, serialNumber); } protected static void httpPost(String url, HashMap paramMap) throws Exception { debug("Posting to: " + url); if (httpClient == null) { httpClient = new DefaultHttpClient(); } String postResponse = RequestUtil.post(httpClient, url, paramMap); debug("Post response: " + postResponse); if (postResponse.contains("")) { fail("Error posting to metacat: " + postResponse); } } protected static void resetHttpClient() { httpClient = null; } /** * Create a unique docid for testing insert and update. Does not * include the 'revision' part of the id. * * @return a String docid based on the current date and time */ protected String generateDocumentId() { try { Thread.sleep(1010); } catch (InterruptedException ie) { debug("Could not sleep: " + ie.getMessage()); } return DocumentUtil.generateDocumentId(prefix, 0); } /** * Insert a document into metacat. The expected result is passed as result */ protected String insertDocumentId(String docid, String docText, boolean result, boolean expectKarmaException) { debug("insertDocumentId() - docid=" + docid + " expectedResult=" + result + " expectKarmaException=" + expectKarmaException); String response = null; try { response = m.insert(docid, new StringReader(docText), null); if (result) { assertTrue(response, (response.indexOf("") != -1)); assertTrue(response, response.indexOf(docid) != -1); } else { assertTrue(response, (response.indexOf("") == -1)); } debug("insertDocid(): response=" + response); } catch (MetacatInaccessibleException mie) { fail("Metacat Inaccessible:\n" + mie.getMessage()); } catch (InsufficientKarmaException ike) { if (!expectKarmaException) { fail("Insufficient karma:\n" + ike.getMessage()); } } catch (MetacatException me) { fail("Metacat Error:\n" + me.getMessage()); } catch (Exception e) { fail("General exception:\n" + e.getMessage()); } return response; } /** * Insert a document into metacat. The expected result is passed as result */ protected String uploadDocumentId(String docid, String filePath, boolean result, boolean expectedKarmaException) { debug("uploadDocumentId() - docid=" + docid + " filePath=" + filePath + " expectedResult=" + result + " expectedKarmaException=" + expectedKarmaException); String response = null; try { response = m.upload(docid, new File(filePath)); if (result) { assertTrue(response, (response.indexOf("") != -1)); assertTrue(response, response.indexOf(docid) != -1); } else { assertTrue(response, (response.indexOf("") == -1)); } debug("uploadDocid(): response=" + response); } catch (MetacatInaccessibleException mie) { fail("Metacat Inaccessible:\n" + mie.getMessage()); } catch (InsufficientKarmaException ike) { if (!expectedKarmaException) { fail("Insufficient karma:\n" + ike.getMessage()); } } catch (MetacatException me) { if (result) { fail("Metacat Error:\n" + me.getMessage()); } else { debug("Metacat Error:\n" + me.getMessage()); } } catch (Exception e) { fail("General exception:\n" + e.getMessage()); } return response; } /** * Update a document in metacat. The expected result is passed as result */ protected String updateDocumentId(String docid, String docText, boolean result, boolean expectedKarmaFailure) { debug("updateDocumentId() - docid=" + docid + " expectedResult=" + result + " expectedKarmaFailure=" + expectedKarmaFailure); String response = null; try { response = m.update(docid, new StringReader(testdocument), null); debug("updateDocumentId() - response=" + response); if (result) { assertTrue(response, (response.indexOf("") != -1)); assertTrue(response, response.indexOf(docid) != -1); } else { assertTrue(response, (response.indexOf("") == -1)); } } catch (MetacatInaccessibleException mie) { fail("Metacat Inaccessible:\n" + mie.getMessage()); } catch (InsufficientKarmaException ike) { if (!expectedKarmaFailure) { fail("Insufficient karma:\n" + ike.getMessage()); } } catch (MetacatException me) { if (result) { fail("Metacat Error:\n" + me.getMessage()); } else { debug("Metacat Error:\n" + me.getMessage()); } } catch (Exception e) { fail("General exception:\n" + e.getMessage()); } return response; } /** * Delete a document into metacat. The expected result is passed as result */ protected void deleteDocumentId(String docid, boolean result, boolean expectedKarmaFailure) { debug("deleteDocumentId() - docid=" + docid + " expectedResult=" + result + " expectedKarmaFailure=" + expectedKarmaFailure); try { Thread.sleep(5000); String response = m.delete(docid); debug("deleteDocumentId() - response=" + response); if (result) { assertTrue(response, response.indexOf("") != -1); } else { assertTrue(response, response.indexOf("") == -1); } } catch (MetacatInaccessibleException mie) { fail("Metacat Inaccessible:\n" + mie.getMessage()); } catch (InsufficientKarmaException ike) { if (!expectedKarmaFailure) { fail("Insufficient karma:\n" + ike.getMessage()); } } catch (MetacatException me) { if (result) { fail("Metacat Error:\n" + me.getMessage()); } else { debug("Metacat Error:\n" + me.getMessage()); } } catch (Exception e) { fail("General exception:\n" + e.getMessage()); } } /** * Read a document from metacat and check if it is equal to a given string. * The expected result is passed as result */ protected void readDocumentIdWhichEqualsDoc(String docid, String testDoc, boolean result, boolean expectedKarmaFailure) { debug("readDocumentIdWhichEqualsDoc() - docid=" + docid + " expectedResult=" + result + " expectedKarmaFailure=" + expectedKarmaFailure); try { Reader r = new InputStreamReader(m.read(docid)); String doc = IOUtil.getAsString(r, true); debug("readDocumentIdWhichEqualsDoc() - doc=" + doc); if (result) { if (!testDoc.equals(doc)) { System.out.println("doc ***********************"); System.out.println(doc); System.out.println("end doc ***********************"); System.out.println("testDoc ***********************"); System.out.println(testDoc); System.out.println("end testDoc ***********************"); } assertTrue(testDoc.equals(doc)); } else { assertTrue(doc.indexOf("") != -1); } } catch (MetacatInaccessibleException mie) { fail("Metacat Inaccessible:\n" + mie.getMessage()); } catch (InsufficientKarmaException ike) { if (!expectedKarmaFailure) { fail("Insufficient karma:\n" + ike.getMessage()); } } catch (MetacatException me) { fail("Metacat Error:\n" + me.getMessage()); } catch (Exception e) { fail("General exception:\n" + e.getMessage()); } } }