Package org.apache.oozie.test

Source Code of org.apache.oozie.test.ZKXTestCaseWithSecurity

/**
* 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.oozie.test;

import java.io.File;
import javax.security.auth.login.Configuration;

import org.apache.curator.test.TestingServer;
import org.apache.hadoop.minikdc.MiniKdc;
import org.apache.oozie.service.HadoopAccessorService;
import org.apache.oozie.service.Services;
import org.apache.oozie.util.JaasConfiguration;
import org.apache.zookeeper.server.ZooKeeperSaslServer;

/**
* Provides a version of {@link ZKXTestCase} with security.  A MiniKdc will be started (so no special outside setup is needed) and
* the embedded ZooKeeper provided by this class will support connecting to it with SASL/Kerberos authentication.  However,
* currently, the client returned by {@link #getClient()) and the client used by DummyZKOozie do not authenticate, so they won't
* have full access to any znodes with "sasl" ACLs (this is not always true, see {@link #setupZKServer()).
* <p>
* Anything using {@link ZKUtils} can connect using authentication by simply setting "oozie.zookeeper.secure" to "true" before
* creating the first thing that uses ZKUtils.  Make sure to set it back to false when done.
*/
public abstract class ZKXTestCaseWithSecurity extends ZKXTestCase {
    private MiniKdc kdc = null;
    private File keytabFile;
    private String originalKeytabLoc;
    private String originalPrincipal;

    /**
     * The primary part of the principal name for the Kerberos user
     */
    protected static final String PRIMARY_PRINCIPAL = "oozie";

    @Override
    protected void setUp() throws Exception {
        super.setUp();
        // Set the keytab location and principal to the miniKDC values
        originalKeytabLoc = Services.get().getConf().get(HadoopAccessorService.KERBEROS_KEYTAB);
        originalPrincipal = Services.get().getConf().get(HadoopAccessorService.KERBEROS_PRINCIPAL);
        Services.get().getConf().set(HadoopAccessorService.KERBEROS_KEYTAB, keytabFile.getAbsolutePath());
        Services.get().getConf().set(HadoopAccessorService.KERBEROS_PRINCIPAL, getPrincipal());
    }

    @Override
    protected void tearDown() throws Exception {
        // Restore these values
        Services.get().getConf().set(HadoopAccessorService.KERBEROS_KEYTAB, originalKeytabLoc);
        Services.get().getConf().set(HadoopAccessorService.KERBEROS_PRINCIPAL, originalPrincipal);
        // Just in case the test forgets to set this back
        Services.get().getConf().set("oozie.zookeeper.secure", "false");
        super.tearDown();
        if (kdc != null) {
            kdc.stop();
        }
    }

    /**
     * Creates and sets up the embedded ZooKeeper server.  Test subclasses should have no reason to override this method.
     * <p>
     * Here we override it to start the MiniKdc, set the jaas configuration, configure ZooKeeper for SASL/Kerberos authentication
     * and ACLs, and to start the ZooKeeper server.
     * <p>
     * Unfortunately, ZooKeeper security requires setting the security for the entire JVM.  And for the tests, we're running the
     * ZK server and one or more clients from the same JVM, so things get messy.  There are two ways to tell ZooKeeper to
     * authenticate: (1) set the system property, "java.security.auth.login.config", to a jaas.conf file and (2) create a
     * javax.security.auth.login.Configuration object with the same info as the jaas.conf and set it.  In either case, once set and
     * something has authenticated, it seems that it can't be unset or changed, and there's no way to log out.  By setting the
     * system property, "javax.security.auth.useSubjectCredsOnly", to "false" we can sort-of change the jaas Configuration, but its
     * kind of funny about it.  Another effect of this is that we have to add jaas entries for the "Server" and "Client" here
     * instead of just the "Server" here and the "Client" in the normal place ({@link ZKUtils}) or it will be unable to find the
     * "Client" info.  Also, because there is no way to logout, once any client has authenticated once, all subsequent clients will
     * automatically connect using the same authentication; trying to stop this is futile and either results in an error or has no
     * effect.  This means that there's no way to do any tests with an unauthenticated client.  Also, if any tests using secure
     * ZooKeeper get run before tests not using secure ZooKeeper, they will likely fail because it will try to use authentication:
     * so they should be run separately.  For this reason, the secure tests should be run in a separate module where they will get
     * their own JVM.
     *
     * @return the embedded ZooKeeper server
     * @throws Exception
     */
    @Override
    protected TestingServer setupZKServer() throws Exception {
        // Not entirely sure exactly what "javax.security.auth.useSubjectCredsOnly=false" does, but it has something to do with
        // re-authenticating in cases where it otherwise wouldn't.  One of the sections on this page briefly mentions it:
        // http://docs.oracle.com/javase/7/docs/technotes/guides/security/jgss/tutorials/Troubleshooting.html
        setSystemProperty("javax.security.auth.useSubjectCredsOnly", "false");

        // Setup KDC and principal
        kdc = new MiniKdc(MiniKdc.createConf(), new File(getTestCaseDir()));
        kdc.start();
        keytabFile = new File(getTestCaseDir(), "test.keytab");
        String serverPrincipal = "zookeeper/127.0.0.1";
        kdc.createPrincipal(keytabFile, getPrincipal(), serverPrincipal);

        setSystemProperty("zookeeper.authProvider.1", "org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
        setSystemProperty("zookeeper.kerberos.removeHostFromPrincipal", "true");
        setSystemProperty("zookeeper.kerberos.removeRealmFromPrincipal", "true");

        JaasConfiguration.addEntry("Server", serverPrincipal, keytabFile.getAbsolutePath());
        // Here's where we add the "Client" to the jaas configuration, even though we'd like not to
        JaasConfiguration.addEntry("Client", getPrincipal(), keytabFile.getAbsolutePath());
        Configuration.setConfiguration(JaasConfiguration.getInstance());

        setSystemProperty(ZooKeeperSaslServer.LOGIN_CONTEXT_NAME_KEY, "Server");

        return new TestingServer();
    }

    /**
     * Returns the principal of the Kerberos user.  This would be {@link #PRIMARY_PRINCIPAL}/_host_
     *
     * @return the principal of the Kerberos user
     */
    protected String getPrincipal() {
        return PRIMARY_PRINCIPAL + "/" + kdc.getHost();
    }
}
TOP

Related Classes of org.apache.oozie.test.ZKXTestCaseWithSecurity

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.