blob: 1a4869d8d3059642014a44be0e866b2934d65ff7 [file] [log] [blame]
/*
* 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.core.client.security.tokens;
import static com.google.common.base.Preconditions.checkArgument;
import static java.util.Objects.requireNonNull;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;
import javax.security.auth.DestroyFailedException;
import org.apache.hadoop.security.UserGroupInformation;
/**
* Authentication token for Kerberos authenticated clients
*
* @since 1.7.0
*/
public class KerberosToken implements AuthenticationToken {
public static final String CLASS_NAME = KerberosToken.class.getName();
private static final int VERSION = 1;
private String principal;
private File keytab;
/**
* Creates a token using the provided principal and the currently logged-in user via {@link UserGroupInformation}.
*
* @param principal
* The user that is logged in
*/
public KerberosToken(String principal) throws IOException {
requireNonNull(principal);
final UserGroupInformation ugi = UserGroupInformation.getCurrentUser();
checkArgument(ugi.hasKerberosCredentials(), "Subject is not logged in via Kerberos");
checkArgument(principal.equals(ugi.getUserName()), "Provided principal does not match currently logged-in user");
this.principal = ugi.getUserName();
}
/**
* Creates a Kerberos token for the specified principal using the provided keytab. The principal and keytab combination are verified by attempting a log in.
* <p>
* This constructor does not have any side effects.
*
* @param principal
* The Kerberos principal
* @param keytab
* A keytab file containing the principal's credentials.
*/
public KerberosToken(String principal, File keytab) throws IOException {
this(principal, keytab, false);
}
/**
* Creates a token and logs in via {@link UserGroupInformation} using the provided principal and keytab. A key for the principal must exist in the keytab,
* otherwise login will fail.
*
* @param principal
* The Kerberos principal
* @param keytab
* A keytab file
* @param replaceCurrentUser
* Should the current Hadoop user be replaced with this user
* @deprecated since 1.8.0, @see #KerberosToken(String, File)
*/
@Deprecated
public KerberosToken(String principal, File keytab, boolean replaceCurrentUser) throws IOException {
requireNonNull(principal, "Principal was null");
requireNonNull(keytab, "Keytab was null");
checkArgument(keytab.exists() && keytab.isFile(), "Keytab was not a normal file");
UserGroupInformation ugi;
if (replaceCurrentUser) {
UserGroupInformation.loginUserFromKeytab(principal, keytab.getAbsolutePath());
ugi = UserGroupInformation.getCurrentUser();
} else {
ugi = UserGroupInformation.loginUserFromKeytabAndReturnUGI(principal, keytab.getAbsolutePath());
}
this.principal = ugi.getUserName();
this.keytab = keytab;
}
/**
* Creates a token using the login user as returned by {@link UserGroupInformation#getCurrentUser()}
*
* @throws IOException
* If the current logged in user cannot be computed.
*/
public KerberosToken() throws IOException {
this(UserGroupInformation.getCurrentUser().getUserName());
}
@Override
public KerberosToken clone() {
try {
KerberosToken clone = (KerberosToken) super.clone();
clone.principal = principal;
clone.keytab = keytab == null ? keytab : keytab.getCanonicalFile();
return clone;
} catch (CloneNotSupportedException | IOException e) {
throw new RuntimeException(e);
}
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof KerberosToken))
return false;
KerberosToken other = (KerberosToken) obj;
return principal.equals(other.principal);
}
/**
* The identity of the user to which this token belongs to according to Kerberos
*
* @return The principal
*/
public String getPrincipal() {
return principal;
}
/**
* The keytab file used to perform Kerberos login. Optional, may be null.
*/
public File getKeytab() {
return keytab;
}
@Override
public void write(DataOutput out) throws IOException {
out.writeInt(VERSION);
}
@Override
public void readFields(DataInput in) throws IOException {
int actualVersion = in.readInt();
if (VERSION != actualVersion) {
throw new IOException("Did not find expected version in serialized KerberosToken");
}
}
@Override
public synchronized void destroy() throws DestroyFailedException {
principal = null;
}
@Override
public boolean isDestroyed() {
return null == principal;
}
@Override
public void init(Properties properties) {
}
@Override
public Set<TokenProperty> getProperties() {
return Collections.emptySet();
}
@Override
public int hashCode() {
return principal.hashCode();
}
}