From 2c17fb02400393f74ecaf96d357d61bbb8d291d9 Mon Sep 17 00:00:00 2001 From: Jonathan Creasy Date: Wed, 16 Mar 2016 01:20:07 -0500 Subject: [PATCH] Initial Attempt at Authentication Plugin Not actually authenticating, will just log some debug messages so far. Fixes #501 Fixes #667 --- Makefile.am | 3 + src/auth/AuthenticationChannelHandler.java | 35 +++++++++++ src/auth/AuthenticationPlugin.java | 71 ++++++++++++++++++++++ src/auth/EmbeddedAuthenticationPlugin.java | 71 ++++++++++++++++++++++ src/core/TSDB.java | 35 ++++++++++- src/tsd/PipelineFactory.java | 4 ++ src/utils/Config.java | 5 +- 7 files changed, 221 insertions(+), 3 deletions(-) create mode 100644 src/auth/AuthenticationChannelHandler.java create mode 100644 src/auth/AuthenticationPlugin.java create mode 100644 src/auth/EmbeddedAuthenticationPlugin.java diff --git a/Makefile.am b/Makefile.am index db49f0589e..d914c7d2b1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -69,6 +69,9 @@ tsdb_SRC := \ src/core/TSSubQuery.java \ src/core/WritableDataPoints.java \ src/graph/Plot.java \ + src/auth/AuthenticationChannelHandler.java \ + src/auth/AuthenticationPlugin.java \ + src/auth/EmbeddedAuthenticationPlugin.java \ src/meta/Annotation.java \ src/meta/MetaDataCache.java \ src/meta/TSMeta.java \ diff --git a/src/auth/AuthenticationChannelHandler.java b/src/auth/AuthenticationChannelHandler.java new file mode 100644 index 0000000000..67e0d08f14 --- /dev/null +++ b/src/auth/AuthenticationChannelHandler.java @@ -0,0 +1,35 @@ +package net.opentsdb.auth; +// This file is part of OpenTSDB. +// Copyright (C) 2010-2012 The OpenTSDB Authors. +// +// This program is free software: you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 2.1 of the License, or (at your +// option) any later version. This program is distributed in the hope that it +// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. You should have received a copy +// of the GNU Lesser General Public License along with this program. If not, +// see . + +import net.opentsdb.core.TSDB; +import org.jboss.netty.channel.ChannelHandlerContext; +import org.jboss.netty.channel.MessageEvent; +import org.jboss.netty.channel.SimpleChannelUpstreamHandler; + + +/** + * @since 2.3 + */ +public class AuthenticationChannelHandler extends SimpleChannelUpstreamHandler { + private AuthenticationPlugin authentication = null; + public AuthenticationChannelHandler(String type, TSDB tsdb) { + this.authentication = tsdb.getAuth(); + } + @Override + public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { + if (authentication.authenticate(e)) { + ctx.getPipeline().remove(this); + } + } +} diff --git a/src/auth/AuthenticationPlugin.java b/src/auth/AuthenticationPlugin.java new file mode 100644 index 0000000000..9c9c45560d --- /dev/null +++ b/src/auth/AuthenticationPlugin.java @@ -0,0 +1,71 @@ +// This file is part of OpenTSDB. +// Copyright (C) 2013 The OpenTSDB Authors. +// +// This program is free software: you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 2.1 of the License, or (at your +// option) any later version. This program is distributed in the hope that it +// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. You should have received a copy +// of the GNU Lesser General Public License along with this program. If not, +// see . +package net.opentsdb.auth; + +import net.opentsdb.core.TSDB; +import net.opentsdb.meta.Annotation; +import net.opentsdb.meta.TSMeta; +import net.opentsdb.meta.UIDMeta; +import net.opentsdb.stats.StatsCollector; + +import com.stumbleupon.async.Deferred; +import org.jboss.netty.channel.MessageEvent; + +/** + * @since 2.3 + */ +public abstract class AuthenticationPlugin { + + /** + * Called by TSDB to initialize the plugin + * Implementations are responsible for setting up any IO they need as well + * as starting any required background threads. + * Note: Implementations should throw exceptions if they can't start + * up properly. The TSD will then shutdown so the operator can fix the + * problem. Please use IllegalArgumentException for configuration issues. + * @param tsdb The parent TSDB object + * @throws IllegalArgumentException if required configuration parameters are + * missing + * @throws Exception if something else goes wrong + */ + public abstract void initialize(final TSDB tsdb); + + /** + * Called to gracefully shutdown the plugin. Implementations should close + * any IO they have open + * @return A deferred object that indicates the completion of the request. + * The {@link Object} has not special meaning and can be {@code null} + * (think of it as {@code Deferred}). + */ + public abstract Deferred shutdown(); + + /** + * Should return the version of this plugin in the format: + * MAJOR.MINOR.MAINT, e.g. 2.0.1. The MAJOR version should match the major + * version of OpenTSDB the plugin is meant to work with. + * @return A version string used to log the loaded version + */ + public abstract String version(); + + /** + * Called by the TSD when a request for statistics collection has come in. The + * implementation may provide one or more statistics. If no statistics are + * available for the implementation, simply stub the method. + * @param collector The collector used for emitting statistics + */ + public abstract void collectStats(final StatsCollector collector); + + public abstract Boolean authenticate(MessageEvent e); + public abstract Boolean authenticate(String digest); + public abstract Boolean authenticate(String username, String password); +} diff --git a/src/auth/EmbeddedAuthenticationPlugin.java b/src/auth/EmbeddedAuthenticationPlugin.java new file mode 100644 index 0000000000..03c1063f37 --- /dev/null +++ b/src/auth/EmbeddedAuthenticationPlugin.java @@ -0,0 +1,71 @@ +package net.opentsdb.auth; +// This file is part of OpenTSDB. +// Copyright (C) 2010-2012 The OpenTSDB Authors. +// +// This program is free software: you can redistribute it and/or modify it +// under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 2.1 of the License, or (at your +// option) any later version. This program is distributed in the hope that it +// will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty +// of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser +// General Public License for more details. You should have received a copy +// of the GNU Lesser General Public License along with this program. If not, +// see . + + +import com.stumbleupon.async.Deferred; +import net.opentsdb.core.TSDB; +import net.opentsdb.stats.StatsCollector; +import org.jboss.netty.channel.MessageEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @since 2.3 + */ +public class EmbeddedAuthenticationPlugin extends AuthenticationPlugin { + private static final Logger LOG = LoggerFactory.getLogger(EmbeddedAuthenticationPlugin.class); + private TSDB tsdb = null; + + @Override + public void initialize(TSDB tsdb) { + LOG.debug("initialized authentication plugin"); + this.tsdb = tsdb; + } + + @Override + public Deferred shutdown() { + return null; + } + + @Override + public String version() { + return "2.3.0"; + } + + @Override + public void collectStats(StatsCollector collector) { + + } + + @Override + public Boolean authenticate(MessageEvent e) { + String username = tsdb.getConfig().getString("tsd.authentication.username"); + String secret = tsdb.getConfig().getString("tsd.authentication.secret"); + LOG.debug(e.getMessage().toString()); + LOG.debug(username + ":" + secret); + return authenticate(username, secret); + } + + @Override + public Boolean authenticate(String digest) { + return true; + } + + @Override + public Boolean authenticate(String providedUsername, String providedSecret) { + String correctUsername = tsdb.getConfig().getString("tsd.authentication.username"); + String correctSecret = tsdb.getConfig().getString("tsd.authentication.secret"); + return (correctUsername == providedUsername && correctSecret == providedSecret); + } +} diff --git a/src/core/TSDB.java b/src/core/TSDB.java index 72930603d1..8499f501f1 100644 --- a/src/core/TSDB.java +++ b/src/core/TSDB.java @@ -41,6 +41,8 @@ import org.jboss.netty.util.Timeout; import org.jboss.netty.util.Timer; +import net.opentsdb.auth.AuthenticationPlugin; +import net.opentsdb.auth.EmbeddedAuthenticationPlugin; import net.opentsdb.tree.TreeBuilder; import net.opentsdb.tsd.RTPublisher; import net.opentsdb.tsd.StorageExceptionHandler; @@ -116,7 +118,10 @@ public final class TSDB { */ private final CompactionQueue compactionq; - /** Search indexer to use if configure */ + /** Authentication Plugin to use if configured */ + private AuthenticationPlugin authentication = null; + + /** Search indexer to use if configured */ private SearchPlugin search = null; /** Optional real time pulblisher plugin to use if configured */ @@ -275,6 +280,23 @@ public void initializePlugins(final boolean init_rpcs) { throw new RuntimeException("Failed to instantiate filters", e); } + // load the authentication plugin if enabled + if (config.getBoolean("tsd.authentication.enable")) { + if ("net.opentsdb.auth.EmbeddedAuthenticationPlugin".trim().toUpperCase().equals(config.getString("tsd.authentication.plugin").trim().toUpperCase())) { + authentication = new EmbeddedAuthenticationPlugin(); + } else { + authentication = PluginLoader.loadSpecificPlugin(config.getString("tsd.authentication.plugin"), AuthenticationPlugin.class); + } + if (authentication == null) { + throw new IllegalArgumentException("Unable to locate authentication plugin: "+ config.getString("tsd.authentication.plugin")); + } + try { + authentication.initialize(this); + } catch (Exception e) { + throw new RuntimeException("Failed to initialize authentication plugin", e); + } + } + // load the search plugin if enabled if (config.getBoolean("tsd.search.enable")) { search = PluginLoader.loadSpecificPlugin( @@ -358,7 +380,16 @@ public void initializePlugins(final boolean init_rpcs) { + storage_exception_handler.version()); } } - + + /** + * Returns the configured Authentication Plugin + * @return The Authentication Plugin + * @since 2.3 + */ + public final AuthenticationPlugin getAuth() { + return this.authentication; + } + /** * Returns the configured HBase client * @return The HBase client diff --git a/src/tsd/PipelineFactory.java b/src/tsd/PipelineFactory.java index 85f66a7fbd..43d615edfe 100644 --- a/src/tsd/PipelineFactory.java +++ b/src/tsd/PipelineFactory.java @@ -16,6 +16,7 @@ import java.util.concurrent.ThreadFactory; +import net.opentsdb.auth.AuthenticationChannelHandler; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.ChannelHandler; @@ -140,6 +141,9 @@ protected Object decode(final ChannelHandlerContext ctx, pipeline.addLast("framer", new LineBasedFrameDecoder(1024)); pipeline.addLast("encoder", ENCODER); pipeline.addLast("decoder", DECODER); + if (tsdb.getAuth() != null) { + pipeline.addLast("authentication", new AuthenticationChannelHandler("telnet", tsdb)); + } } pipeline.addLast("timeout", timeoutHandler); diff --git a/src/utils/Config.java b/src/utils/Config.java index 3191b1602a..d06ce400e1 100644 --- a/src/utils/Config.java +++ b/src/utils/Config.java @@ -25,7 +25,6 @@ import org.slf4j.LoggerFactory; import com.google.common.collect.ImmutableMap; - /** * OpenTSDB Configuration Class * @@ -484,6 +483,10 @@ protected void setDefaults() { default_map.put("tsd.network.tcp_no_delay", "true"); default_map.put("tsd.network.keep_alive", "true"); default_map.put("tsd.network.reuse_address", "true"); + default_map.put("tsd.authentication.enable", "false"); + default_map.put("tsd.authentication.plugin", "net.opentsdb.auth.EmbeddedAuthenticationPlugin"); + default_map.put("tsd.authentication.username", "admin"); + default_map.put("tsd.authentication.secret", "admin"); default_map.put("tsd.core.auto_create_metrics", "false"); default_map.put("tsd.core.auto_create_tagks", "true"); default_map.put("tsd.core.auto_create_tagvs", "true");