PrestoDB支持的认证方式有3种(前提都是要打开https服务):
- Kerberos
- LDAP
- Password file 本篇博客下面主要介绍Password file认证的代码逻辑和配置。
1 开发自定义的password authenticator
参考官网提供的信息 prestodb.io/docs/curren…
我们需要实现PasswordAuthenticatorFactory,用于创建PasswordAuthenticator实例
2 认证代码逻辑
2.1 入口 PluginManager扫描插件
for (File file : listFiles(installedPluginsDir)) {
if (file.isDirectory()) {
loadPlugin(file.getAbsolutePath());
}
}
for (String plugin : plugins) {
loadPlugin(plugin);
}
查看配置文件中的插件路径
sudo vi /etc/presto/conf/node.properties
plugin.dir=/usr/lib/presto/plugin
2.2 在plugin路径下实现PasswordAuthenticatorFactory
技术: ServiceLoader 当外部程序装配该模块时,通过该jar包META-INF/services/里的配置文件找到具体的实现类名,从而完成模块的注入
private void loadPlugin(URLClassLoader pluginClassLoader)
{
ServiceLoader<Plugin> serviceLoader = ServiceLoader.load(Plugin.class, pluginClassLoader);
List<Plugin> plugins = ImmutableList.copyOf(serviceLoader);
if (plugins.isEmpty()) {
log.warn("No service providers of type %s", Plugin.class.getName());
}
for (Plugin plugin : plugins) {
log.info("Installing %s", plugin.getClass().getName());
installPlugin(plugin);
}
}
此处会找到plugin下面所有实现Plugin.class的类
2.3 安装Plugin
public void installPlugin(Plugin plugin)
...
for (PasswordAuthenticatorFactory authenticatorFactory : plugin.getPasswordAuthenticatorFactories()) {
log.info("Registering password authenticator %s", authenticatorFactory.getName());
passwordAuthenticatorManager.addPasswordAuthenticatorFactory(authenticatorFactory);
}
2.4 创建PasswordAuthenticator
PasswordAuthenticatorManager
public void loadPasswordAuthenticator()
throws Exception
{
if (!required.get()) {
return;
}
File configFileLocation = CONFIG_FILE.getAbsoluteFile();
Map<String, String> properties = new HashMap<>(loadProperties(configFileLocation));
String name = properties.remove(NAME_PROPERTY);
checkArgument(!isNullOrEmpty(name),
"Password authenticator configuration %s does not contain %s", configFileLocation, NAME_PROPERTY);
log.info("-- Loading password authenticator --");
PasswordAuthenticatorFactory factory = factories.get(name);
checkState(factory != null, "Password authenticator %s is not registered", name);
PasswordAuthenticator authenticator = factory.create(ImmutableMap.copyOf(properties));
this.authenticator.set(requireNonNull(authenticator, "authenticator is null"));
log.info("-- Loaded password authenticator %s --", name);
}
private static final String NAME_PROPERTY = "password-authenticator.name";
读取etc/password-authenticator.properties里面的配置,并从factories里面找到name与NAME_PROPERTY一致的factory并用于创建PasswordAuthenticator authenticator。
3开发和配置
3.1 开发
public class NbFilePasswordAuthenticatorPlugin implements Plugin {
@Override
public Iterable<PasswordAuthenticatorFactory> getPasswordAuthenticatorFactories()
{
return ImmutableList.<PasswordAuthenticatorFactory>builder()
.add(new NbFilePasswordAuthenticatorFactory())
.build();
}
}
public class NbFilePasswordAuthenticatorFactory implements PasswordAuthenticatorFactory {
@Override
public String getName() {
return "nb-password-authenticator";
}
@Override
public PasswordAuthenticator create(Map<String, String> config) {
return new NbFilePasswordAuthenticator(config);
}
}
public class NbFilePasswordAuthenticator implements PasswordAuthenticator {
private static final Logger log = Logger.getLogger("NbFilePasswordAuthenticator");
private final Supplier<PasswordStore> passwordStoreSupplier;
private Map<String, String> config;
public NbFilePasswordAuthenticator(Map<String, String> config) {
File configFile = null;
if (config.containsKey("file.password-file")) {
String filePath = config.get("file.password-file").trim();
log.log(Level.INFO, "file.password-file=" + filePath);
configFile = new File(filePath);
if (!configFile.exists()) {
log.log(Level.WARNING, "File %s does not exist" + configFile.getAbsolutePath());
throw new RuntimeException("File " + configFile.getAbsolutePath() + " does not exist");
}
} else {
String msg = "must has file.password-file in etc/password-authenticator.properties";
log.log(Level.WARNING, msg);
throw new RuntimeException(msg);
}
// default: 1 day
int period = 86400;
if (config.containsKey("file.refresh-period")) {
period = Integer.parseInt(config.get("file.refresh-period"));
}
int cacheMaxSize = 1000;
File finalConfigFile = configFile;
passwordStoreSupplier = (Supplier<PasswordStore>) memoizeWithExpiration(
() -> new PasswordStore(finalConfigFile, cacheMaxSize, null),
period,
SECONDS);
}
@Override
public Principal createAuthenticatedPrincipal(String user, String password) {
if (password == null || password.equals("")) {
throw new AccessDeniedException("password mustn't be blank!");
}
if (user == null || user.equals("")) {
throw new AccessDeniedException("user mustn't be blank!");
}
String[] authInfo = password.split(Keys.AUTH_PASSWORD_SPLIT);
if (authInfo.length < 2) {
throw new AccessDeniedException("password must has 'nbdata' !");
}
if (!passwordStoreSupplier.get().authenticate(authInfo[0], authInfo[1])) {
throw new AccessDeniedException("Invalid credentials");
}
return new BasicPrincipal(user);
}
}
3.2 配置
3.2.1 创建plugin
cd /usr/lib/presto/plugin/
sudo mkdir nxb-password-authenticators
复制打包好的jar和依赖到nb-password-authenticators目录里面 (coordinator节点上)
3.2.2 配置etc/password-authenticator.properties
sudo vi /usr/lib/presto/etc/password-authenticator.properties
加入以下内容
password-authenticator.name=nb-password-authenticator
file.password-file=/home/hadoop/xxxxx/password-auth.properties
3.2.3 配置config.properties
sudo vi /etc/presto/conf/config.properties
http-server.authentication.type=PASSWORD
http-server.https.enabled=true
http-server.https.port=8447
http-server.https.keystore.path=/home/hadoop/xxxxx/my_htpasswd/presto_keystore.jks
http-server.https.keystore.key=xxxxxxx
最后重启服务