Return-Path: X-Original-To: apmail-accumulo-commits-archive@www.apache.org Delivered-To: apmail-accumulo-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 9307C18F92 for ; Thu, 3 Dec 2015 21:16:12 +0000 (UTC) Received: (qmail 37300 invoked by uid 500); 3 Dec 2015 21:16:12 -0000 Delivered-To: apmail-accumulo-commits-archive@accumulo.apache.org Received: (qmail 37256 invoked by uid 500); 3 Dec 2015 21:16:12 -0000 Mailing-List: contact commits-help@accumulo.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@accumulo.apache.org Delivered-To: mailing list commits@accumulo.apache.org Received: (qmail 37126 invoked by uid 99); 3 Dec 2015 21:16:12 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 03 Dec 2015 21:16:12 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id 4ED03E683A; Thu, 3 Dec 2015 21:16:12 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: elserj@apache.org To: commits@accumulo.apache.org Date: Thu, 03 Dec 2015 21:16:14 -0000 Message-Id: <2ea45f7a04da4660bbb7c7081dfcdcd9@git.apache.org> In-Reply-To: <543f2049492a44678e029abc105d0b0e@git.apache.org> References: <543f2049492a44678e029abc105d0b0e@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [3/3] accumulo git commit: Merge branch '1.7' Merge branch '1.7' Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/6e5fa1c6 Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/6e5fa1c6 Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/6e5fa1c6 Branch: refs/heads/master Commit: 6e5fa1c6bf8e6193439c81d57aa36159d5197ad9 Parents: 46e5d5c 3aa9d30 Author: Josh Elser Authored: Thu Dec 3 16:15:54 2015 -0500 Committer: Josh Elser Committed: Thu Dec 3 16:15:54 2015 -0500 ---------------------------------------------------------------------- .../org/apache/accumulo/core/conf/Property.java | 2 + .../apache/accumulo/core/rpc/ThriftUtil.java | 60 ++++++ .../accumulo/server/security/SecurityUtil.java | 47 ++++- .../org/apache/accumulo/harness/TestingKdc.java | 13 +- .../test/functional/KerberosRenewalIT.java | 188 +++++++++++++++++++ 5 files changed, 303 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/6e5fa1c6/core/src/main/java/org/apache/accumulo/core/conf/Property.java ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/6e5fa1c6/test/src/main/java/org/apache/accumulo/harness/TestingKdc.java ---------------------------------------------------------------------- diff --cc test/src/main/java/org/apache/accumulo/harness/TestingKdc.java index 1f84fc8,0000000..653139a mode 100644,000000..100644 --- a/test/src/main/java/org/apache/accumulo/harness/TestingKdc.java +++ b/test/src/main/java/org/apache/accumulo/harness/TestingKdc.java @@@ -1,212 -1,0 +1,219 @@@ +/* + * 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.accumulo.harness; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.apache.accumulo.cluster.ClusterUser; +import org.apache.hadoop.minikdc.MiniKdc; +import org.junit.Assert; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Creates a {@link MiniKdc} for tests to use to exercise secure Accumulo + */ +public class TestingKdc { + private static final Logger log = LoggerFactory.getLogger(TestingKdc.class); + + public static final int NUM_USERS = 10; ++ public static final long MAX_TICKET_LIFETIME_MILLIS = 86400000; // one day + + protected MiniKdc kdc = null; + protected ClusterUser accumuloServerUser = null, accumuloAdmin = null; + protected List clientPrincipals = null; + + public final String ORG_NAME = "EXAMPLE", ORG_DOMAIN = "COM"; + + private String hostname; + private File keytabDir; + private boolean started = false; + + public TestingKdc() throws Exception { - this(computeKdcDir(), computeKeytabDir()); ++ this(computeKdcDir(), computeKeytabDir(), MAX_TICKET_LIFETIME_MILLIS); + } + - private static File computeKdcDir() { ++ public static File computeKdcDir() { + File targetDir = new File(System.getProperty("user.dir"), "target"); + if (!targetDir.exists()) + Assert.assertTrue(targetDir.mkdirs()); + Assert.assertTrue("Could not find Maven target directory: " + targetDir, targetDir.exists() && targetDir.isDirectory()); + + // Create the directories: target/kerberos/minikdc + File kdcDir = new File(new File(targetDir, "kerberos"), "minikdc"); + + assertTrue(kdcDir.mkdirs() || kdcDir.isDirectory()); + + return kdcDir; + } + - private static File computeKeytabDir() { ++ public static File computeKeytabDir() { + File targetDir = new File(System.getProperty("user.dir"), "target"); + Assert.assertTrue("Could not find Maven target directory: " + targetDir, targetDir.exists() && targetDir.isDirectory()); + + // Create the directories: target/kerberos/keytabs + File keytabDir = new File(new File(targetDir, "kerberos"), "keytabs"); + + assertTrue(keytabDir.mkdirs() || keytabDir.isDirectory()); + + return keytabDir; + } + + public TestingKdc(File kdcDir, File keytabDir) throws Exception { ++ this(kdcDir, keytabDir, MAX_TICKET_LIFETIME_MILLIS); ++ } ++ ++ public TestingKdc(File kdcDir, File keytabDir, long maxTicketLifetime) throws Exception { + checkNotNull(kdcDir, "KDC directory was null"); + checkNotNull(keytabDir, "Keytab directory was null"); ++ checkArgument(maxTicketLifetime > 0, "Ticket lifetime must be positive"); + + this.keytabDir = keytabDir; + this.hostname = InetAddress.getLocalHost().getCanonicalHostName(); + + log.debug("Starting MiniKdc in {} with keytabs in {}", kdcDir, keytabDir); + + Properties kdcConf = MiniKdc.createConf(); + kdcConf.setProperty(MiniKdc.ORG_NAME, ORG_NAME); + kdcConf.setProperty(MiniKdc.ORG_DOMAIN, ORG_DOMAIN); ++ kdcConf.setProperty(MiniKdc.MAX_TICKET_LIFETIME, Long.toString(maxTicketLifetime)); + // kdcConf.setProperty(MiniKdc.DEBUG, "true"); + kdc = new MiniKdc(kdcConf, kdcDir); + } + + /** + * Starts the KDC and creates the principals and their keytabs + */ + public synchronized void start() throws Exception { + checkArgument(!started, "KDC was already started"); + kdc.start(); + Thread.sleep(1000); + + // Create the identity for accumulo servers + File accumuloKeytab = new File(keytabDir, "accumulo.keytab"); + String accumuloPrincipal = String.format("accumulo/%s", hostname); + + log.info("Creating Kerberos principal {} with keytab {}", accumuloPrincipal, accumuloKeytab); + kdc.createPrincipal(accumuloKeytab, accumuloPrincipal); + + accumuloServerUser = new ClusterUser(qualifyUser(accumuloPrincipal), accumuloKeytab); + + // Create the identity for the "root" user + String rootPrincipal = "root"; + File rootKeytab = new File(keytabDir, rootPrincipal + ".keytab"); + + log.info("Creating Kerberos principal {} with keytab {}", rootPrincipal, rootKeytab); + kdc.createPrincipal(rootKeytab, rootPrincipal); + + accumuloAdmin = new ClusterUser(qualifyUser(rootPrincipal), rootKeytab); + + clientPrincipals = new ArrayList<>(NUM_USERS); + // Create a number of unprivileged users for tests to use + for (int i = 1; i <= NUM_USERS; i++) { + String clientPrincipal = "client" + i; + File clientKeytab = new File(keytabDir, clientPrincipal + ".keytab"); + + log.info("Creating Kerberos principal {} with keytab {}", clientPrincipal, clientKeytab); + kdc.createPrincipal(clientKeytab, clientPrincipal); + + clientPrincipals.add(new ClusterUser(qualifyUser(clientPrincipal), clientKeytab)); + } + + started = true; + } + + public synchronized void stop() throws Exception { + checkArgument(started, "KDC is not started"); + kdc.stop(); + started = false; + } + + /** + * A directory where the automatically-created keytab files are written + */ + public File getKeytabDir() { + return keytabDir; + } + + /** + * A {@link ClusterUser} for Accumulo server processes to use + */ + public ClusterUser getAccumuloServerUser() { + checkArgument(started, "The KDC is not started"); + return accumuloServerUser; + } + + /** + * A {@link ClusterUser} which is the Accumulo "root" user + */ + public ClusterUser getRootUser() { + checkArgument(started, "The KDC is not started"); + return accumuloAdmin; + } + + /** + * The {@link ClusterUser} corresponding to the given offset. Represents an unprivileged user. + * + * @param offset + * The offset to fetch credentials for, valid through {@link #NUM_USERS} + */ + public ClusterUser getClientPrincipal(int offset) { + checkArgument(started, "Client principal is not initialized, is the KDC started?"); + checkArgument(offset >= 0 && offset < NUM_USERS, "Offset is invalid, must be non-negative and less than " + NUM_USERS); + return clientPrincipals.get(offset); + } + + /** + * @see MiniKdc#createPrincipal(File, String...) + */ + public void createPrincipal(File keytabFile, String... principals) throws Exception { + checkArgument(started, "KDC is not started"); + kdc.createPrincipal(keytabFile, principals); + } + + /** + * @return the name for the realm + */ + public String getOrgName() { + return ORG_NAME; + } + + /** + * @return the domain for the realm + */ + public String getOrgDomain() { + return ORG_DOMAIN; + } + + /** + * Qualify a username (only the primary from the kerberos principal) with the proper realm + * + * @param primary + * The primary or primary and instance + */ + public String qualifyUser(String primary) { + return String.format("%s@%s.%s", primary, getOrgName(), getOrgDomain()); + } +}