Repository: mina-sshd
Updated Branches:
  refs/heads/master 7df595887 -> b5bb002f0


[SSHD-689] Allow providing a file as a welcome banner configuration option


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/b5bb002f
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/b5bb002f
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/b5bb002f

Branch: refs/heads/master
Commit: b5bb002f06a7977a2935cdab27be35afd96c7886
Parents: 7df5958
Author: Lyor Goldstein <[email protected]>
Authored: Thu Aug 18 19:08:41 2016 +0300
Committer: Lyor Goldstein <[email protected]>
Committed: Thu Aug 18 19:08:41 2016 +0300

----------------------------------------------------------------------
 .../sshd/common/PropertyResolverUtils.java      | 24 +++++-
 .../server/ServerAuthenticationManager.java     | 32 +++++++-
 .../java/org/apache/sshd/server/SshServer.java  | 23 ++----
 .../server/session/ServerUserAuthService.java   | 84 ++++++++++++++++----
 .../sshd/server/auth/WelcomeBannerTest.java     |  1 -
 5 files changed, 131 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b5bb002f/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java 
b/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java
index 40b2510..d5c767b 100644
--- a/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java
+++ b/sshd-core/src/main/java/org/apache/sshd/common/PropertyResolverUtils.java
@@ -19,6 +19,7 @@
 
 package org.apache.sshd.common;
 
+import java.nio.charset.Charset;
 import java.util.Collection;
 import java.util.Map;
 import java.util.NoSuchElementException;
@@ -311,6 +312,28 @@ public final class PropertyResolverUtils {
         }
     }
 
+    public static Charset getCharset(PropertyResolver resolver, String name, 
Charset defaultValue) {
+        Object value = getObject(resolver, name);
+        return (value == null) ? defaultValue : toCharset(value);
+    }
+
+    public static Charset getCharset(Map<String, ?> props, String name, 
Charset defaultValue) {
+        Object value = getObject(props, name);
+        return (value == null) ? defaultValue : toCharset(value);
+    }
+
+    public static Charset toCharset(Object value) {
+        if (value == null) {
+            return null;
+        } else if (value instanceof Charset) {
+            return (Charset) value;
+        } else if (value instanceof CharSequence) {
+            return Charset.forName(value.toString());
+        } else {
+            throw new IllegalArgumentException("Invalid charset conversion 
value: " + value);
+        }
+    }
+
     public static String getString(PropertyResolver resolver, String name) {
         Object value = getObject(resolver, name);
         return Objects.toString(value, null);
@@ -325,7 +348,6 @@ public final class PropertyResolverUtils {
         return resolvePropertyValue(resolver, name);
     }
 
-
     // for symmetrical reasons...
     public static Object getObject(Map<String, ?> props, String name) {
         return resolvePropertyValue(props, name);

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b5bb002f/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
 
b/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
index b1978e1..188fd3f 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/ServerAuthenticationManager.java
@@ -63,7 +63,30 @@ public interface ServerAuthenticationManager {
     /**
      * Key used to retrieve the value of welcome banner that will be displayed
      * when a user connects to the server. If {@code null}/empty then no banner
-     * will be sent.
+     * will be sent. The value can be one of the following:
+     * <UL>
+     *      <P><LI>
+     *      A {@link java.io.File} or {@link java.nio.file.Path}, in which case
+     *      its contents will be transmitted. <B>Note:</B> if the file is empty
+     *      or does not exits, no banner will be transmitted.
+     *      </LI></P>
+     *
+     *      <P><LI>
+     *      A {@link java.net.URI} or a string starting with 
&quot;file:/&quot;, in
+     *      which case it will be converted to a {@link java.nio.file.Path} and
+     *      handled accordingly.
+     *      </LI></P>
+     *
+     *      <P><LI>
+     *      A string containing a special value indicator - e.g., {@link 
#AUTO_WELCOME_BANNER_VALUE},
+     *      in which case the relevant banner content will be generated.
+     *      </LI></P>
+     *
+     *      <P><LI>
+     *      Any other object whose {@code toString()} value yields a non empty 
string
+     *      will be used as the banner contents.
+     *      </LI></P>
+     * </UL>
      * @see <A HREF="https://www.ietf.org/rfc/rfc4252.txt";>RFC-4252 section 
5.4</A>
      */
     String WELCOME_BANNER = "welcome-banner";
@@ -100,6 +123,13 @@ public interface ServerAuthenticationManager {
     WelcomeBannerPhase DEFAULT_BANNER_PHASE = WelcomeBannerPhase.IMMEDIATE;
 
     /**
+     * The charset to use if the configured welcome banner points
+     * to a file - if not specified (either as a string or a {@link 
java.nio.charset.Charset}
+     * then the local default is used.
+     */
+    String WELCOME_BANNER_CHARSET = "welcome-banner-charset";
+
+    /**
      * This key is used when configuring multi-step authentications.
      * The value needs to be a blank separated list of comma separated list
      * of authentication method names.

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b5bb002f/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java 
b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
index a6e635b..f8fcf39 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/SshServer.java
@@ -45,7 +45,6 @@ import org.apache.sshd.common.NamedFactory;
 import org.apache.sshd.common.PropertyResolverUtils;
 import org.apache.sshd.common.ServiceFactory;
 import org.apache.sshd.common.config.SshConfigFileReader;
-import org.apache.sshd.common.config.keys.KeyRandomArt;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.helpers.AbstractFactoryManager;
 import org.apache.sshd.common.io.IoAcceptor;
@@ -583,7 +582,7 @@ public class SshServer extends AbstractFactoryManager 
implements ServerFactoryMa
 
         KeyPairProvider hostKeyProvider = setupServerKeys(sshd, hostKeyType, 
hostKeySize, keyFiles);
         sshd.setKeyPairProvider(hostKeyProvider);
-        // Should come AFTER key pair provider setup so auto-welcome can be 
generated
+        // Should come AFTER key pair provider setup so auto-welcome can be 
generated if needed
         setupServerBanner(sshd, options);
         sshd.setPort(port);
 
@@ -608,7 +607,7 @@ public class SshServer extends AbstractFactoryManager 
implements ServerFactoryMa
         Thread.sleep(Long.MAX_VALUE);
     }
 
-    public static String setupServerBanner(ServerFactoryManager server, 
Map<String, ?> options) throws Exception {
+    public static Object setupServerBanner(ServerFactoryManager server, 
Map<String, ?> options) throws Exception {
         String bannerOption = GenericUtils.isEmpty(options)
                 ? null
                 : 
Objects.toString(options.remove(SshConfigFileReader.BANNER_CONFIG_PROP), null);
@@ -621,30 +620,22 @@ public class SshServer extends AbstractFactoryManager 
implements ServerFactoryMa
             }
         }
 
-        String banner;
+        Object banner;
         if (GenericUtils.length(bannerOption) > 0) {
             if ("none".equals(bannerOption)) {
                 return null;
             }
 
             if 
(ServerAuthenticationManager.AUTO_WELCOME_BANNER_VALUE.equalsIgnoreCase(bannerOption))
 {
-                banner = KeyRandomArt.combine(' ', 
server.getKeyPairProvider());
+                banner = bannerOption;
             } else {
-                Path path = Paths.get(bannerOption);
-                long fileSize = Files.size(path);
-                ValidateUtils.checkTrue(fileSize > 0L, "No banner contents in 
file=%s", bannerOption);
-
-                List<String> lines = Files.readAllLines(path);
-                banner = GenericUtils.join(lines, '\n');
+                banner = Paths.get(bannerOption);
             }
         } else {
             banner = "Welcome to SSHD\n";
         }
 
-        if (GenericUtils.length(banner) > 0) {
-            PropertyResolverUtils.updateProperty(server, 
ServerAuthenticationManager.WELCOME_BANNER, banner);
-        }
-
-        return PropertyResolverUtils.getString(server, 
ServerAuthenticationManager.WELCOME_BANNER);
+        PropertyResolverUtils.updateProperty(server, 
ServerAuthenticationManager.WELCOME_BANNER, banner);
+        return banner;
     }
 }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b5bb002f/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
 
b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
index b0593f6..8ea3162 100644
--- 
a/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
+++ 
b/sshd-core/src/main/java/org/apache/sshd/server/session/ServerUserAuthService.java
@@ -18,9 +18,17 @@
  */
 package org.apache.sshd.server.session;
 
+import java.io.File;
 import java.io.IOException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
@@ -368,20 +376,7 @@ public class ServerUserAuthService extends 
AbstractCloseable implements Service,
             return null;
         }
 
-        String welcomeBanner = PropertyResolverUtils.getString(session, 
ServerAuthenticationManager.WELCOME_BANNER);
-        if ((GenericUtils.length(welcomeBanner) > 0)
-            && 
ServerAuthenticationManager.AUTO_WELCOME_BANNER_VALUE.equalsIgnoreCase(welcomeBanner))
 {
-            try {
-                welcomeBanner = KeyRandomArt.combine(' ', 
session.getKeyPairProvider());
-            } catch (Exception e) {
-                if (e instanceof IOException) {
-                    throw (IOException) e;
-                }
-
-                throw new IOException(e);
-            }
-        }
-
+        String welcomeBanner = resolveWelcomeBanner(session);
         if (GenericUtils.isEmpty(welcomeBanner)) {
             return null;
         }
@@ -401,6 +396,67 @@ public class ServerUserAuthService extends 
AbstractCloseable implements Service,
         return session.writePacket(buffer);
     }
 
+    protected String resolveWelcomeBanner(ServerSession session) throws 
IOException {
+        Object bannerValue = PropertyResolverUtils.getObject(session, 
ServerAuthenticationManager.WELCOME_BANNER);
+        if (bannerValue == null) {
+            return null;
+        }
+
+        if (bannerValue instanceof CharSequence) {
+            String message = bannerValue.toString();
+            if (GenericUtils.isEmpty(message)) {
+                return null;
+            }
+
+            if 
(ServerAuthenticationManager.AUTO_WELCOME_BANNER_VALUE.equalsIgnoreCase(message))
 {
+                try {
+                    return KeyRandomArt.combine(' ', 
session.getKeyPairProvider());
+                } catch (Exception e) {
+                    if (e instanceof IOException) {
+                        throw (IOException) e;
+                    }
+
+                    throw new IOException(e);
+                }
+            }
+
+            if (!message.startsWith("file:/")) {
+                return message;
+            }
+
+            try {
+                bannerValue = new URI(message);
+            } catch (URISyntaxException e) {
+                log.error("resolveWelcomeBanner({}) bad path URI {}: {}", 
session, message, e.getMessage());
+                throw new IOException(e);
+            }
+        }
+
+        if (bannerValue instanceof URI) {
+            bannerValue = Paths.get((URI) bannerValue);
+        }
+
+        if (bannerValue instanceof File) {
+            bannerValue = ((File) bannerValue).toPath();
+        }
+
+        if (bannerValue instanceof Path) {
+            Path path = (Path) bannerValue;
+            if ((!Files.exists(path)) || (Files.size(path) <= 0L)) {
+                if (log.isDebugEnabled()) {
+                    log.debug("resolveWelcomeBanner({}) file is empty/does not 
exist", session, path);
+                }
+                return null;
+            }
+
+            Charset cs = PropertyResolverUtils.getCharset(session, 
ServerAuthenticationManager.WELCOME_BANNER_CHARSET, Charset.defaultCharset());
+            Collection<String> lines = Files.readAllLines((Path) bannerValue, 
cs);
+            return GenericUtils.join(lines, '\n');
+        }
+
+        return bannerValue.toString();
+    }
+
     public ServerFactoryManager getFactoryManager() {
         return serverSession.getFactoryManager();
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/b5bb002f/sshd-core/src/test/java/org/apache/sshd/server/auth/WelcomeBannerTest.java
----------------------------------------------------------------------
diff --git 
a/sshd-core/src/test/java/org/apache/sshd/server/auth/WelcomeBannerTest.java 
b/sshd-core/src/test/java/org/apache/sshd/server/auth/WelcomeBannerTest.java
index 3126b6b..7f824ad 100644
--- a/sshd-core/src/test/java/org/apache/sshd/server/auth/WelcomeBannerTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/server/auth/WelcomeBannerTest.java
@@ -51,7 +51,6 @@ public class WelcomeBannerTest extends BaseTestSupport {
         super();
     }
 
-
     @BeforeClass
     public static void setupClientAndServer() throws Exception {
         sshd = Utils.setupTestServer(WelcomeBannerPhaseTest.class);

Reply via email to