blob: 879955414e0aff75428d1c606d89e2b6cc995ddf [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.zookeeper;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import org.apache.zookeeper.client.ZKClientConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Computes the Server Principal for a SASL client.
*/
public class SaslServerPrincipal {
private static final Logger LOG = LoggerFactory.getLogger(SaslServerPrincipal.class);
/**
* Get the name of the server principal for a SASL client.
* @param addr the address of the host.
* @param clientConfig the configuration for the client.
* @return the name of the principal.
*/
static String getServerPrincipal(InetSocketAddress addr, ZKClientConfig clientConfig) {
return getServerPrincipal(new WrapperInetSocketAddress(addr), clientConfig);
}
/**
* Get the name of the server principal for a SASL client. This is visible for testing purposes.
* @param addr the address of the host.
* @param clientConfig the configuration for the client.
* @return the name of the principal.
*/
static String getServerPrincipal(WrapperInetSocketAddress addr, ZKClientConfig clientConfig) {
String configuredServerPrincipal = clientConfig.getProperty(ZKClientConfig.ZOOKEEPER_SERVER_PRINCIPAL);
if (configuredServerPrincipal != null) {
// If server principal is already configured then return it
return configuredServerPrincipal;
}
String principalUserName = clientConfig.getProperty(
ZKClientConfig.ZK_SASL_CLIENT_USERNAME,
ZKClientConfig.ZK_SASL_CLIENT_USERNAME_DEFAULT);
String hostName = addr.getHostName();
boolean canonicalize = true;
String canonicalizeText = clientConfig.getProperty(
ZKClientConfig.ZK_SASL_CLIENT_CANONICALIZE_HOSTNAME,
ZKClientConfig.ZK_SASL_CLIENT_CANONICALIZE_HOSTNAME_DEFAULT);
try {
canonicalize = Boolean.parseBoolean(canonicalizeText);
} catch (IllegalArgumentException ea) {
LOG.warn(
"Could not parse config {} \"{}\" into a boolean using default {}",
ZKClientConfig.ZK_SASL_CLIENT_CANONICALIZE_HOSTNAME,
canonicalizeText,
canonicalize);
}
if (canonicalize) {
WrapperInetAddress ia = addr.getAddress();
if (ia == null) {
throw new IllegalArgumentException("Unable to canonicalize address " + addr + " because it's not resolvable");
}
String canonicalHostName = ia.getCanonicalHostName();
//avoid using literal IP address when security check fails
if (!canonicalHostName.equals(ia.getHostAddress())) {
hostName = canonicalHostName;
}
LOG.debug("Canonicalized address to {}", hostName);
}
String serverPrincipal = principalUserName + "/" + hostName;
return serverPrincipal;
}
/**
* This is here to provide a way to unit test the core logic as the methods for
* InetSocketAddress are marked as final.
*/
static class WrapperInetSocketAddress {
private final InetSocketAddress addr;
WrapperInetSocketAddress(InetSocketAddress addr) {
this.addr = addr;
}
public String getHostName() {
return addr.getHostName();
}
public WrapperInetAddress getAddress() {
InetAddress ia = addr.getAddress();
return ia == null ? null : new WrapperInetAddress(ia);
}
@Override
public String toString() {
return addr.toString();
}
}
/**
* This is here to provide a way to unit test the core logic as the methods for
* InetAddress are marked as final.
*/
static class WrapperInetAddress {
private final InetAddress ia;
WrapperInetAddress(InetAddress ia) {
this.ia = ia;
}
public String getCanonicalHostName() {
return ia.getCanonicalHostName();
}
public String getHostAddress() {
return ia.getHostAddress();
}
@Override
public String toString() {
return ia.toString();
}
}
}