blob: ce7bfad5f6d8161576167315fc1c6e3b0e62ec14 [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.server;
import static com.google.common.base.Preconditions.checkArgument;
import java.io.IOException;
import org.apache.accumulo.core.client.AccumuloException;
import org.apache.accumulo.core.client.AccumuloSecurityException;
import org.apache.accumulo.core.client.Connector;
import org.apache.accumulo.core.client.Instance;
import org.apache.accumulo.core.client.ZooKeeperInstance;
import org.apache.accumulo.core.client.impl.ClientContext;
import org.apache.accumulo.core.client.impl.ConnectorImpl;
import org.apache.accumulo.core.client.impl.Credentials;
import org.apache.accumulo.core.client.security.tokens.PasswordToken;
import org.apache.accumulo.core.conf.AccumuloConfiguration;
import org.apache.accumulo.core.conf.Property;
import org.apache.accumulo.core.rpc.SslConnectionParams;
import org.apache.accumulo.core.util.DeprecationUtil;
import org.apache.accumulo.server.client.HdfsZooInstance;
import org.apache.accumulo.server.conf.ServerConfigurationFactory;
import org.apache.accumulo.server.rpc.SaslServerConnectionParams;
import org.apache.accumulo.server.rpc.ThriftServerType;
import org.apache.accumulo.server.security.SecurityUtil;
import org.apache.accumulo.server.security.SystemCredentials;
import org.apache.accumulo.server.security.delegation.AuthenticationTokenSecretManager;
import org.apache.hadoop.security.UserGroupInformation;
/**
* Provides a server context for Accumulo server components that operate with the system credentials and have access to the system files and configuration.
*/
public class AccumuloServerContext extends ClientContext {
private final ServerConfigurationFactory confFactory;
private AuthenticationTokenSecretManager secretManager;
/**
* Construct a server context from the server's configuration
*/
public AccumuloServerContext(ServerConfigurationFactory confFactory) {
this(confFactory, null);
}
/**
* Construct a server context from the server's configuration
*/
public AccumuloServerContext(ServerConfigurationFactory confFactory, AuthenticationTokenSecretManager secretManager) {
super(confFactory.getInstance(), getCredentials(confFactory.getInstance()), confFactory.getConfiguration());
this.confFactory = confFactory;
this.secretManager = secretManager;
if (null != getSaslParams()) {
// Server-side "client" check to make sure we're logged in as a user we expect to be
enforceKerberosLogin();
}
}
/**
* A "client-side" assertion for servers to validate that they are logged in as the expected user, per the configuration, before performing any RPC
*/
// Should be private, but package-protected so EasyMock will work
void enforceKerberosLogin() {
final AccumuloConfiguration conf = confFactory.getSiteConfiguration();
// Unwrap _HOST into the FQDN to make the kerberos principal we'll compare against
final String kerberosPrincipal = SecurityUtil.getServerPrincipal(conf.get(Property.GENERAL_KERBEROS_PRINCIPAL));
UserGroupInformation loginUser;
try {
// The system user should be logged in via keytab when the process is started, not the currentUser() like KerberosToken
loginUser = UserGroupInformation.getLoginUser();
} catch (IOException e) {
throw new RuntimeException("Could not get login user", e);
}
checkArgument(loginUser.hasKerberosCredentials(), "Server does not have Kerberos credentials");
checkArgument(kerberosPrincipal.equals(loginUser.getUserName()), "Expected login user to be " + kerberosPrincipal + " but was " + loginUser.getUserName());
}
/**
* Get the credentials to use for this instance so it can be passed to the superclass during construction.
*/
private static Credentials getCredentials(Instance instance) {
if (DeprecationUtil.isMockInstance(instance)) {
return new Credentials("mockSystemUser", new PasswordToken("mockSystemPassword"));
}
return SystemCredentials.get(instance);
}
/**
* Retrieve the configuration factory used to construct this context
*/
public ServerConfigurationFactory getServerConfigurationFactory() {
return confFactory;
}
/**
* Retrieve the SSL/TLS configuration for starting up a listening service
*/
public SslConnectionParams getServerSslParams() {
return SslConnectionParams.forServer(getConfiguration());
}
@Override
public SaslServerConnectionParams getSaslParams() {
AccumuloConfiguration conf = getServerConfigurationFactory().getSiteConfiguration();
if (!conf.getBoolean(Property.INSTANCE_RPC_SASL_ENABLED)) {
return null;
}
return new SaslServerConnectionParams(conf, getCredentials().getToken(), secretManager);
}
/**
* Determine the type of Thrift server to instantiate given the server's configuration.
*
* @return A {@link ThriftServerType} value to denote the type of Thrift server to construct
*/
public ThriftServerType getThriftServerType() {
AccumuloConfiguration conf = getConfiguration();
if (conf.getBoolean(Property.INSTANCE_RPC_SSL_ENABLED)) {
if (conf.getBoolean(Property.INSTANCE_RPC_SASL_ENABLED)) {
throw new IllegalStateException("Cannot create a Thrift server capable of both SASL and SSL");
}
return ThriftServerType.SSL;
} else if (conf.getBoolean(Property.INSTANCE_RPC_SASL_ENABLED)) {
if (conf.getBoolean(Property.INSTANCE_RPC_SSL_ENABLED)) {
throw new IllegalStateException("Cannot create a Thrift server capable of both SASL and SSL");
}
return ThriftServerType.SASL;
} else {
// Lets us control the type of Thrift server created, primarily for benchmarking purposes
String serverTypeName = conf.get(Property.GENERAL_RPC_SERVER_TYPE);
return ThriftServerType.get(serverTypeName);
}
}
public void setSecretManager(AuthenticationTokenSecretManager secretManager) {
this.secretManager = secretManager;
}
public AuthenticationTokenSecretManager getSecretManager() {
return secretManager;
}
// Need to override this from ClientContext to ensure that HdfsZooInstance doesn't "downcast"
// the AccumuloServerContext into a ClientContext (via the copy-constructor on ClientContext)
@Override
public Connector getConnector() throws AccumuloException, AccumuloSecurityException {
// avoid making more connectors than necessary
if (conn == null) {
if (inst instanceof ZooKeeperInstance || inst instanceof HdfsZooInstance) {
// reuse existing context
conn = new ConnectorImpl(this);
} else {
Credentials c = getCredentials();
conn = getInstance().getConnector(c.getPrincipal(), c.getToken());
}
}
return conn;
}
}