Package org.apache.qpid.server.security.acl

Source Code of org.apache.qpid.server.security.acl.AbstractACLTestCase

/*
*  Licensed to the Apache Software Foundation (ASF) under one
*  or more contributor license agreements.  See the NOTICE file
*  distributed with this work for additional information
*  regarding copyright ownership.  The ASF licenses this file
*  to you under the Apache License, Version 2.0 (the
*  "License"); you may not use this file except in compliance
*  with the License.  You may obtain a copy of the License at
*
*    http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing,
*  software distributed under the License is distributed on an
*  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
*  KIND, either express or implied.  See the License for the
*  specific language governing permissions and limitations
*  under the License.
*/
package org.apache.qpid.server.security.acl;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.lang.StringUtils;

import org.apache.qpid.AMQException;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQConnectionURL;
import org.apache.qpid.jms.ConnectionListener;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.test.utils.QpidBrokerTestCase;
import org.apache.qpid.url.URLSyntaxException;

import javax.jms.Connection;
import javax.jms.ExceptionListener;
import javax.jms.JMSException;
import javax.naming.NamingException;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
* Abstract test case for ACLs.
*
* This base class contains convenience methods to mange ACL files and implements a mechanism that allows each
* test method to run its own setup code before the broker starts.
*
* TODO move the pre broker-startup setup method invocation code to {@link QpidBrokerTestCase}
*
* @see ExternalACLTest
* @see ExternalACLJMXTest
* @see ExhaustiveACLTest
*/
public abstract class AbstractACLTestCase extends QpidBrokerTestCase implements ConnectionListener
{
    /** Used to synchronise {@link #tearDown()} when exceptions are thrown */
    protected CountDownLatch _exceptionReceived;
   
    /** Override this to return the name of the configuration XML file. */
    public String getConfig()
    {
        return "config-systests.xml";
    }

    /**
     * This setup method checks {@link #getConfig()} and {@link #getHostList()} to initialise the broker with specific
     * ACL configurations and then runs an optional per-test setup method, which is simply a method with the same name
     * as the test, but starting with {@code setUp} rather than {@code test}.
     *
     * @see org.apache.qpid.test.utils.QpidBrokerTestCase#setUp()
     */
    @Override
    public void setUp() throws Exception
    {
        // Initialise ACLs.
        _configFile = new File("build" + File.separator + "etc" + File.separator + getConfig());

        // run test specific setup
        String testSetup = StringUtils.replace(getName(), "test", "setUp");
        try
        {
            Method setup = getClass().getDeclaredMethod(testSetup);
            setup.invoke(this);
        }
        catch (NoSuchMethodException e)
        {
            // Ignore
        }
        catch (InvocationTargetException e)
        {
            throw (Exception) e.getTargetException();
        }
       
        super.setUp();
    }

    @Override
    public void tearDown() throws Exception
    {
        try
        {
            super.tearDown();
        }
        catch (JMSException e)
        {
            //we're throwing this away as it can happen in this test as the state manager remembers exceptions
            //that we provoked with authentication failures, where the test passes - we can ignore on con close
        }
    }
   
    public void writeACLFile(final String vhost, final String...rules) throws ConfigurationException, IOException
    {
        writeACLFileUtil(this, vhost, rules);
    }

    public static void writeACLFileUtil(QpidBrokerTestCase testcase, String vhost, String...rules) throws ConfigurationException, IOException
    {
        File aclFile = File.createTempFile(testcase.getClass().getSimpleName(), testcase.getName());
        aclFile.deleteOnExit();

        if (vhost == null)
        {
            testcase.setConfigurationProperty("security.acl", aclFile.getAbsolutePath());
        }
        else
        {
            testcase.setConfigurationProperty("virtualhosts.virtualhost." + vhost + ".security.acl", aclFile.getAbsolutePath());
        }

        PrintWriter out = new PrintWriter(new FileWriter(aclFile));
        out.println(String.format("# %s", testcase.getName()));
        for (String line : rules)
        {
            out.println(line);
        }
        out.close();
    }

    /**
     * Creates a connection to the broker, and sets a connection listener to prevent failover and an exception listener
     * with a {@link CountDownLatch} to synchronise in the {@link #check403Exception(Throwable)} method and allow the
     * {@link #tearDown()} method to complete properly.
     */
    public Connection getConnection(String vhost, String username, String password) throws NamingException, JMSException, URLSyntaxException
    {
        AMQConnection connection = (AMQConnection) getConnection(createConnectionURL(vhost, username, password));

        //Prevent Failover
        connection.setConnectionListener(this);
       
        //QPID-2081: use a latch to sync on exception causing connection close, to work
        //around the connection close race during tearDown() causing sporadic failures
        _exceptionReceived = new CountDownLatch(1);

        connection.setExceptionListener(new ExceptionListener()
        {
            public void onException(JMSException e)
            {
                _exceptionReceived.countDown();
            }
        });

        return (Connection) connection;
    }

    // Connection Listener Interface - Used here to block failover

    public void bytesSent(long count)
    {
    }

    public void bytesReceived(long count)
    {
    }

    public boolean preFailover(boolean redirect)
    {
        //Prevent failover.
        return false;
    }

    public boolean preResubscribe()
    {
        return false;
    }

    public void failoverComplete()
    {
    }

    /**
     * Convenience method to build an {@link AMQConnectionURL} with the right parameters.
     */
    public AMQConnectionURL createConnectionURL(String vhost, String username, String password) throws URLSyntaxException
    {
        String url = "amqp://" + username + ":" + password + "@clientid/" + vhost + "?brokerlist='" + getBroker() + "?retries='0''";
        return new AMQConnectionURL(url);
    }

    /**
     * Convenience method to validate a JMS exception with a linked {@link AMQConstant#ACCESS_REFUSED} 403 error code exception.
     */
    public void check403Exception(Throwable t) throws Exception
    {
        assertNotNull("There was no linked exception", t);
        assertTrue("Wrong linked exception type : " + t.getClass(), t instanceof AMQException);
        assertEquals("Incorrect error code received", 403, ((AMQException) t).getErrorCode().getCode());
   
        //use the latch to ensure the control thread waits long enough for the exception thread
        //to have done enough to mark the connection closed before teardown commences
        assertTrue("Timed out waiting for conneciton to report close", _exceptionReceived.await(2, TimeUnit.SECONDS));
    }
}
TOP

Related Classes of org.apache.qpid.server.security.acl.AbstractACLTestCase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.