Commit c51de95c authored by Brian Major's avatar Brian Major
Browse files

s1729 - Tomcat realm tests

parent 52a4b880
Loading
Loading
Loading
Loading
+28 −114
Original line number Diff line number Diff line
@@ -91,133 +91,47 @@

    <property name="jars"               value="${log4j}:${tomcat}" />

    <target name="build" depends="compile,resources">
        <jar jarfile="${build}/lib/${project}.jar"
            basedir="${build}/class" update="no">
                <exclude name="test/**" />
        </jar>
    </target>
    <target name="build" depends="simpleJar" />
    
    <target name="resources">
    <target name="test-resources">
        <copy todir="${build}/class">
            <fileset dir="src/resources">
                <include name="**.xsd" />
                <include name="**.properties" />
            </fileset>
        </copy>
        <jar jarfile="${build}/tmp/test.jar"
                basedir="${build}/class"
                update="no">
            <include name="ca/nrc/cadc/reg/client/**" />
            <include name="**.properties" />
        </jar>
    </target>

    <!-- JAR files needed to run the test suite -->
    <property name="asm"                value="${ext.lib}/asm.jar" />
    <property name="asm-attrs"          value="${ext.lib}/asm-attrs.jar" />
    <property name="cglib"              value="${ext.lib}/cglib.jar" />
    <property name="commons-logging"    value="${ext.lib}/commons-logging.jar" />
    <property name="easyMock"           value="${ext.dev}/easymock.jar" />
    <property name="easyMock"           value="${ext.dev}/easymock.jar" />
    <property name="junit"              value="${ext.dev}/junit.jar" />
    <property name="xerces"             value="${ext.lib}/xerces.jar" />
    <property name="gson"               value="${ext.lib}/gson.jar" />

    <property name="testingJars"        value="${test.jdbc.drivers}:${asm}:${asm-attrs}:${cglib}:${commons-logging}:${easyMock}:${ext.dev}/objenesis.jar:${junit}:${xerces}:${gson}" />
    
    <target name="setup-test">
        <copy file="test/src/resources/foo.xsd" todir="${build}/test/class"/>
        <copy file="test/src/resources/bar.xsd" todir="${build}/test/class"/>
        <copy file="src/resources/UWS-v1.0.xsd" todir="${build}/test/class"/>
        <copy file="src/resources/XLINK.xsd" todir="${build}/test/class"/>
    </target>
    
    <target name="misc-test" depends="compile-test">
        <junit printsummary="yes" haltonfailure="yes" fork="yes">
            <classpath>
                <pathelement path="${build}/class"/>
                <pathelement path="${build}/test/class"/>
                <pathelement path="${build}/test/src"/>
                <pathelement path="${jars}:${testingJars}"/>
            </classpath>

            <test name="ca.nrc.cadc.uws.server.RandomStringGeneratorTest" />
            <test name="ca.nrc.cadc.uws.web.restlet.RestletPrincipalExtractorTest" />
            <test name="ca.nrc.cadc.uws.web.ResourceTestSuite" />

            <formatter type="plain" usefile="false" />
        </junit>

    </target>
    
    <target name="log-test" depends="compile-test">
    <property name="dev.junit" value="${ext.dev}/junit.jar" />
    <property name="servlet" value="${ext.lib}/servlet-api.jar" />
    <property name="log" value="${ext.lib}/commons-logging.jar" />
    <property name="juli" value="${ext.lib}/tomcat-juli.jar" />
    <property name="tomcatUtil" value="${ext.lib}/tomcat-util.jar" />
    <property name="test" value="${build}/tmp/test.jar" />
    <property name="testingJars" value="${dev.junit}:${servlet}:${log}:${juli}:${tomcatUtil}:${test}" />
    
    <!-- Run the test suite -->
    <target name="test" depends="compile-test,test-resources">
        <echo message="Running test" />

        <!-- Run the junit test suite -->
        <echo message="Running test suite..." />
        <junit printsummary="yes" haltonfailure="yes" fork="yes">
            <classpath>
                <pathelement path="${build}/class"/>
                <pathelement path="${build}/test/class" />
                <pathelement path="${build}/test/src"/>
                <pathelement path="${jars}:${testingJars}"/>
            </classpath>

            <test name="ca.nrc.cadc.uws.util.JobLogInfoTest" />
            <test name="ca.nrc.cadc.uws.util.RestletLogInfoTest" />

            <formatter type="plain" usefile="false" />
        </junit>
    </target>

    <target name="xml-test" depends="compile-test">
        <junit printsummary="yes" haltonfailure="yes" fork="yes">
            <classpath>
                <pathelement path="${build}/class" />
                <pathelement path="${build}/test/class"/>
                <pathelement path="${build}/test/src"/>
                <pathelement path="${jars}:${testingJars}" />
            </classpath>

            <test name="ca.nrc.cadc.uws.JobReaderWriterTest" />
            <test name="ca.nrc.cadc.uws.JobListReaderWriterTest" />

            <formatter type="plain" usefile="false" />
        </junit>
    </target>

    <target name="dao-test" depends="build,compile-test">
        <junit printsummary="yes" haltonfailure="yes" fork="yes">
            <classpath>
                <pathelement path="${build}/class"/>
                <pathelement path="${build}/test/class"/>
                <pathelement path="${build}/test/src"/>
                <pathelement path="${jars}:${testingJars}"/>
            </classpath>
            <test name="ca.nrc.cadc.uws.server.SybaseJobDAOTest" />
            <test name="ca.nrc.cadc.uws.server.PostgresJobDAOTest" />
            <formatter type="plain" usefile="false" />
        </junit>
    </target>

    <target name="exec-test" depends="compile-test">
        <junit printsummary="yes" haltonfailure="yes" fork="yes">
          <classpath>
              <pathelement path="."/>
              <pathelement path="src"/>
              <pathelement path="test/src"/>
              <pathelement path="${build}/class"/>
              <pathelement path="${build}/test/class"/>
              <pathelement path="${jars}:${testingJars}"/>
          </classpath>
          <formatter type="plain" usefile="false"/>
          <test name="ca.nrc.cadc.uws.server.ThreadExecutorTest"/>
          <test name="ca.nrc.cadc.uws.server.ThreadPoolExecutorTest"/>
        </junit>
    </target>
    
    <target name="util-test" depends="compile-test">
        <junit printsummary="yes" haltonfailure="yes" fork="yes">
          <classpath>
              <pathelement path="."/>
              <pathelement path="src"/>
              <pathelement path="test/src"/>
              <pathelement path="${build}/class"/>
              <pathelement path="${build}/test/class"/>
              <pathelement path="${jars}:${testingJars}"/>
          </classpath>
            <test name="ca.nrc.cadc.tomcat.CadcBasicAuthenticatorTest"/>
            <test name="ca.nrc.cadc.tomcat.RealmRegistryClientTest"/>
            <formatter type="plain" usefile="false"/>
          <test name="ca.nrc.cadc.uws.util.IterableContentTest"/>
        </junit>
    </target>
    
+47 −87
Original line number Diff line number Diff line
@@ -69,8 +69,11 @@

package ca.nrc.cadc.tomcat;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.Principal;
import java.util.Arrays;
@@ -78,12 +81,8 @@ import java.util.List;

import org.apache.catalina.realm.GenericPrincipal;
import org.apache.catalina.realm.RealmBase;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.varia.LevelRangeFilter;

/**
 * Custom class for Tomcat realm authentication.
@@ -101,18 +100,9 @@ public class CadcBasicAuthenticator extends RealmBase
    private static Logger log = Logger.getLogger(CadcBasicAuthenticator.class);
    private static final String AC_URI = "ivo://cadc.nrc.ca/canfargms";

    private static final String ISO_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";

    // SHORT_FORMAT applies to DEBUG and TRACE logging levels
    private static final String SHORT_FORMAT = "%-4r [%t] %-5p %c{1} %x - %m\n";

    // LONG_FORMAT applies to INFO, WARN, ERROR and FATAL logging levels
    private static final String LONG_FORMAT = "%d{" + ISO_DATE_FORMAT
                                              + "} [%t] %-5p %c{1} %x - %m\n";

    static
    {
        initLogging();
        RealmUtil.initLogging();
        Logger.getLogger("ca.nrc.cadc.tomcat").setLevel(Level.INFO);
    }

@@ -145,50 +135,23 @@ public class CadcBasicAuthenticator extends RealmBase

        try
        {
            RealmRegistryClient registryClient = new RealmRegistryClient();
            URL loginURL = registryClient.getServiceURL(
                new URI(AC_URI), "http", "/login");

            String post = "userid=" + username + "&password=" + credentials;

            HttpURLConnection conn = (HttpURLConnection) loginURL.openConnection();
            conn.setRequestMethod("POST");
            conn.setDoOutput(true);

            byte[] postData = post.getBytes("UTF-8");
            conn.getOutputStream().write(postData);

            int responseCode = conn.getResponseCode();
            boolean valid = login(username, credentials);

            log.debug("Http POST to /ac/login returned " +
                    responseCode + " for user " + username);

            if (responseCode != 200)
            if (valid)
            {
                // authentication not ok
                if (responseCode != 401)
                {
                    // not an unauthorized, so log the
                    // possible server side error
                    String errorMessage = "Error calling /ac/login, error code: " + responseCode;
                    success = false;
                    throw new IllegalStateException(errorMessage);
                }

                // authentication simply failed
                return null;
            }

                // authentication ok, add public role
                List<String> roles = Arrays.asList("public");

                // Don't want to return the password here in the principal
                // in case it makes it into the servlet somehow
            return new GenericPrincipal(username, "", roles);
                return new GenericPrincipal(username, null, roles);
            }

            return null;
        }
        catch (Throwable t)
        {
            success = false;
            String message = "Could not do http basic authentication: " + t.getMessage();
            log.error(message, t);
            throw new IllegalStateException(message, t);
@@ -209,48 +172,45 @@ public class CadcBasicAuthenticator extends RealmBase
        }
    }

    private static void initLogging()
    boolean login(String username, String credentials)
            throws URISyntaxException, IOException
    {
        // Clear all existing appenders, if there's any.
        BasicConfigurator.resetConfiguration();
        Logger.getRootLogger().setLevel(Level.ERROR); // must redo after reset
        RealmRegistryClient registryClient = new RealmRegistryClient();
        URL loginURL = registryClient.getServiceURL(
            new URI(AC_URI), "http", "/login");

        String post = "userid=" + username + "&password=" + credentials;

        HttpURLConnection conn = (HttpURLConnection) loginURL.openConnection();
        conn.setRequestMethod("POST");
        conn.setDoOutput(true);

        byte[] postData = post.getBytes("UTF-8");
        conn.getOutputStream().write(postData);

        int responseCode = conn.getResponseCode();

        String errorLogFormat = LONG_FORMAT;
        String infoLogFormat = LONG_FORMAT;
        String debugLogFormat = SHORT_FORMAT;
        log.debug("Http POST to /ac/login returned " +
                responseCode + " for user " + username);

        // Appender for WARN, ERROR and FATAL with LONG_FORMAT message prefix
        ConsoleAppender conAppenderHigh =
                new ConsoleAppender(new PatternLayout(errorLogFormat));
        LevelRangeFilter errorFilter = new LevelRangeFilter();
        errorFilter.setLevelMax(Level.FATAL);
        errorFilter.setLevelMin(Level.WARN);
        errorFilter.setAcceptOnMatch(true);
        conAppenderHigh.clearFilters();
        conAppenderHigh.addFilter(errorFilter);
        BasicConfigurator.configure(conAppenderHigh);
        if (responseCode != 200)
        {
            // authentication not ok
            if (responseCode != 401)
            {
                // not an unauthorized, so log the
                // possible server side error
                String errorMessage = "Error calling /ac/login, error code: " + responseCode;
                throw new IllegalStateException(errorMessage);
            }

        // Appender for INFO with LONG_FORMAT message prefix
        ConsoleAppender conAppenderInfo =
                new ConsoleAppender(new PatternLayout(infoLogFormat));
        LevelRangeFilter infoFilter = new LevelRangeFilter();
        infoFilter.setLevelMax(Level.INFO);
        infoFilter.setLevelMin(Level.INFO);
        infoFilter.setAcceptOnMatch(true);
        conAppenderInfo.clearFilters();
        conAppenderInfo.addFilter(infoFilter);
        BasicConfigurator.configure(conAppenderInfo);
            // authentication simply failed
            return false;
        }

        // Appender for DEBUG and TRACE with LONG_FORMAT message prefix
        ConsoleAppender conAppenderDebug =
                new ConsoleAppender(new PatternLayout(debugLogFormat));
        LevelRangeFilter debugFilter = new LevelRangeFilter();
        debugFilter.setLevelMax(Level.DEBUG);
        debugFilter.setLevelMin(Level.TRACE);
        debugFilter.setAcceptOnMatch(true);
        conAppenderDebug.clearFilters();
        conAppenderDebug.addFilter(debugFilter);
        BasicConfigurator.configure(conAppenderDebug);
        return true;
    }



}
 No newline at end of file
+135 −0
Original line number Diff line number Diff line
/*
************************************************************************
*******************  CANADIAN ASTRONOMY DATA CENTRE  *******************
**************  CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES  **************
*
*  (c) 2015.                            (c) 2015.
*  Government of Canada                 Gouvernement du Canada
*  National Research Council            Conseil national de recherches
*  Ottawa, Canada, K1A 0R6              Ottawa, Canada, K1A 0R6
*  All rights reserved                  Tous droits réservés
*
*  NRC disclaims any warranties,        Le CNRC dénie toute garantie
*  expressed, implied, or               énoncée, implicite ou légale,
*  statutory, of any kind with          de quelque nature que ce
*  respect to the software,             soit, concernant le logiciel,
*  including without limitation         y compris sans restriction
*  any warranty of merchantability      toute garantie de valeur
*  or fitness for a particular          marchande ou de pertinence
*  purpose. NRC shall not be            pour un usage particulier.
*  liable in any event for any          Le CNRC ne pourra en aucun cas
*  damages, whether direct or           être tenu responsable de tout
*  indirect, special or general,        dommage, direct ou indirect,
*  consequential or incidental,         particulier ou général,
*  arising from the use of the          accessoire ou fortuit, résultant
*  software.  Neither the name          de l'utilisation du logiciel. Ni
*  of the National Research             le nom du Conseil National de
*  Council of Canada nor the            Recherches du Canada ni les noms
*  names of its contributors may        de ses  participants ne peuvent
*  be used to endorse or promote        être utilisés pour approuver ou
*  products derived from this           promouvoir les produits dérivés
*  software without specific prior      de ce logiciel sans autorisation
*  written permission.                  préalable et particulière
*                                       par écrit.
*
*  This file is part of the             Ce fichier fait partie du projet
*  OpenCADC project.                    OpenCADC.
*
*  OpenCADC is free software:           OpenCADC est un logiciel libre ;
*  you can redistribute it and/or       vous pouvez le redistribuer ou le
*  modify it under the terms of         modifier suivant les termes de
*  the GNU Affero General Public        la “GNU Affero General Public
*  License as published by the          License” telle que publiée
*  Free Software Foundation,            par la Free Software Foundation
*  either version 3 of the              : soit la version 3 de cette
*  License, or (at your option)         licence, soit (à votre gré)
*  any later version.                   toute version ultérieure.
*
*  OpenCADC is distributed in the       OpenCADC est distribué
*  hope that it will be useful,         dans l’espoir qu’il vous
*  but WITHOUT ANY WARRANTY;            sera utile, mais SANS AUCUNE
*  without even the implied             GARANTIE : sans même la garantie
*  warranty of MERCHANTABILITY          implicite de COMMERCIALISABILITÉ
*  or FITNESS FOR A PARTICULAR          ni d’ADÉQUATION À UN OBJECTIF
*  PURPOSE.  See the GNU Affero         PARTICULIER. Consultez la Licence
*  General Public License for           Générale Publique GNU Affero
*  more details.                        pour plus de détails.
*
*  You should have received             Vous devriez avoir reçu une
*  a copy of the GNU Affero             copie de la Licence Générale
*  General Public License along         Publique GNU Affero avec
*  with OpenCADC.  If not, see          OpenCADC ; si ce n’est
*  <http://www.gnu.org/licenses/>.      pas le cas, consultez :
*                                       <http://www.gnu.org/licenses/>.
*
*  $Revision: 5 $
*
************************************************************************
*/

package ca.nrc.cadc.tomcat;

import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.varia.LevelRangeFilter;

public class RealmUtil
{

    private static final String ISO_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS";

    // SHORT_FORMAT applies to DEBUG and TRACE logging levels
    private static final String SHORT_FORMAT = "%-4r [%t] %-5p %c{1} %x - %m\n";

    // LONG_FORMAT applies to INFO, WARN, ERROR and FATAL logging levels
    private static final String LONG_FORMAT = "%d{" + ISO_DATE_FORMAT
                                              + "} [%t] %-5p %c{1} %x - %m\n";

    public static void initLogging()
    {
        // Clear all existing appenders, if there's any.
        BasicConfigurator.resetConfiguration();
        Logger.getRootLogger().setLevel(Level.ERROR); // must redo after reset

        String errorLogFormat = LONG_FORMAT;
        String infoLogFormat = LONG_FORMAT;
        String debugLogFormat = SHORT_FORMAT;

        // Appender for WARN, ERROR and FATAL with LONG_FORMAT message prefix
        ConsoleAppender conAppenderHigh =
                new ConsoleAppender(new PatternLayout(errorLogFormat));
        LevelRangeFilter errorFilter = new LevelRangeFilter();
        errorFilter.setLevelMax(Level.FATAL);
        errorFilter.setLevelMin(Level.WARN);
        errorFilter.setAcceptOnMatch(true);
        conAppenderHigh.clearFilters();
        conAppenderHigh.addFilter(errorFilter);
        BasicConfigurator.configure(conAppenderHigh);

        // Appender for INFO with LONG_FORMAT message prefix
        ConsoleAppender conAppenderInfo =
                new ConsoleAppender(new PatternLayout(infoLogFormat));
        LevelRangeFilter infoFilter = new LevelRangeFilter();
        infoFilter.setLevelMax(Level.INFO);
        infoFilter.setLevelMin(Level.INFO);
        infoFilter.setAcceptOnMatch(true);
        conAppenderInfo.clearFilters();
        conAppenderInfo.addFilter(infoFilter);
        BasicConfigurator.configure(conAppenderInfo);

        // Appender for DEBUG and TRACE with LONG_FORMAT message prefix
        ConsoleAppender conAppenderDebug =
                new ConsoleAppender(new PatternLayout(debugLogFormat));
        LevelRangeFilter debugFilter = new LevelRangeFilter();
        debugFilter.setLevelMax(Level.DEBUG);
        debugFilter.setLevelMin(Level.TRACE);
        debugFilter.setAcceptOnMatch(true);
        conAppenderDebug.clearFilters();
        conAppenderDebug.addFilter(debugFilter);
        BasicConfigurator.configure(conAppenderDebug);
    }

}
+4 −0
Original line number Diff line number Diff line
# example record
ivo://example.com/srv = http://www.example.com/current/path/to/my/service anon,cookie,token
ivo://example.com/srv = http://www.example.com/current/path/to/my/auth-service password
ivo://example.com/srv = https://www.example.com/current/path/to/my/service cert
 No newline at end of file
+3 −0
Original line number Diff line number Diff line

## test record for RegistryClientTest.testFoundViaConfigFile 
ivo://example.com/srv = http://alt.example.com/current/path/to/my/service anon,cookie,token
Loading