You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gn...@apache.org on 2017/09/12 18:36:51 UTC

[1/4] karaf git commit: [KARAF-5359] Upgrade to JLine 3.5.0

Repository: karaf
Updated Branches:
  refs/heads/master 62750e306 -> 46503d10e


[KARAF-5359] Upgrade to JLine 3.5.0


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/1590a9ad
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/1590a9ad
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/1590a9ad

Branch: refs/heads/master
Commit: 1590a9ad54ed97358d3d2e7f7181b62265c77263
Parents: c5d3a88
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Mon Sep 11 09:03:06 2017 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Tue Sep 12 19:13:11 2017 +0200

----------------------------------------------------------------------
 pom.xml                                                           | 2 +-
 .../org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java   | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/1590a9ad/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 8fa9035..e6fac94 100644
--- a/pom.xml
+++ b/pom.xml
@@ -258,7 +258,7 @@
         <hibernate.validator.version>5.3.4.Final</hibernate.validator.version>
         <jansi.version>1.16</jansi.version>
         <javassist.version>3.9.0.GA</javassist.version>
-        <jline.version>3.4.0</jline.version>
+        <jline.version>3.5.0</jline.version>
         <jsw.version>3.2.3</jsw.version>
         <log4j.version>1.2.17</log4j.version>
         <maven.version>3.5.0</maven.version>

http://git-wip-us.apache.org/repos/asf/karaf/blob/1590a9ad/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
index 01986e2..7fd3ced 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
@@ -65,6 +65,7 @@ import org.jline.reader.Completer;
 import org.jline.reader.EndOfFileException;
 import org.jline.reader.LineReader;
 import org.jline.reader.LineReaderBuilder;
+import org.jline.reader.MaskingCallback;
 import org.jline.reader.ParsedLine;
 import org.jline.reader.UserInterruptException;
 import org.jline.terminal.Terminal.Signal;
@@ -410,7 +411,7 @@ public class ConsoleSessionImpl implements Session {
         CharSequence command = null;
         reading.set(true);
         try {
-            reader.readLine(getPrompt(), getRPrompt(), null, null);
+            reader.readLine(getPrompt(), getRPrompt(), (MaskingCallback) null, null);
             ParsedLine pl = reader.getParsedLine();
             if (pl instanceof ParsedLineImpl) {
                 command = ((ParsedLineImpl) pl).program();


[3/4] karaf git commit: Merge branch 'KARAF-5359', fixes #350

Posted by gn...@apache.org.
Merge branch 'KARAF-5359', fixes #350


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

Branch: refs/heads/master
Commit: af5ae5114648899ddbcbd5103b231d8b75a6e6ef
Parents: 62750e3 1590a9a
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Tue Sep 12 20:32:42 2017 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Tue Sep 12 20:32:42 2017 +0200

----------------------------------------------------------------------
 pom.xml                                                           | 2 +-
 .../org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java   | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/af5ae511/pom.xml
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/karaf/blob/af5ae511/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
----------------------------------------------------------------------


[2/4] karaf git commit: [KARAF-5287] Provide a way to hide passwords in shell

Posted by gn...@apache.org.
[KARAF-5287] Provide a way to hide passwords in shell


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/5228a23f
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/5228a23f
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/5228a23f

Branch: refs/heads/master
Commit: 5228a23fc4113922cc9936c8d921a97cc2ea434d
Parents: 1590a9a
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Mon Sep 11 09:10:45 2017 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Tue Sep 12 19:15:36 2017 +0200

----------------------------------------------------------------------
 .../karaf/jaas/command/UserAddCommand.java      |   2 +-
 .../apache/karaf/shell/api/action/Argument.java |  15 ++
 .../apache/karaf/shell/api/action/Option.java   |  15 ++
 .../action/command/ActionMaskingCallback.java   | 161 +++++++++++++++++++
 .../action/command/DefaultActionPreparator.java |  10 ++
 .../shell/impl/action/command/HelpOption.java   |   8 +
 .../shell/impl/console/ConsoleSessionImpl.java  |  60 ++++++-
 .../command/ActionMaskingCallbackTest.java      | 113 +++++++++++++
 .../commands/AbstractCommandHelpPrinter.java    |   8 +
 9 files changed, 390 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/5228a23f/jaas/command/src/main/java/org/apache/karaf/jaas/command/UserAddCommand.java
----------------------------------------------------------------------
diff --git a/jaas/command/src/main/java/org/apache/karaf/jaas/command/UserAddCommand.java b/jaas/command/src/main/java/org/apache/karaf/jaas/command/UserAddCommand.java
index 0a0898c..98b0546 100644
--- a/jaas/command/src/main/java/org/apache/karaf/jaas/command/UserAddCommand.java
+++ b/jaas/command/src/main/java/org/apache/karaf/jaas/command/UserAddCommand.java
@@ -27,7 +27,7 @@ public class UserAddCommand extends JaasCommandSupport {
     @Argument(index = 0, name = "username", description = "User Name", required = true, multiValued = false)
     private String username;
 
-    @Argument(index = 1, name = "password", description = "Password", required = true, multiValued = false)
+    @Argument(index = 1, name = "password", description = "Password", required = true, multiValued = false, censor = true, mask = '#')
     private String password;
 
     @Override

http://git-wip-us.apache.org/repos/asf/karaf/blob/5228a23f/shell/core/src/main/java/org/apache/karaf/shell/api/action/Argument.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/action/Argument.java b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Argument.java
index b0268a2..f9dcc1b 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/api/action/Argument.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Argument.java
@@ -82,4 +82,19 @@ public @interface Argument
      * @return the argument help string representation.
      */
     String valueToShowInHelp() default DEFAULT_STRING;
+
+    /**
+     * Censor the argument in the console. Characters will be replaced with {@link Argument#mask()}.
+     * This is useful for hiding sensitive data like passwords.
+     *
+     * @return true if the argument should be censored in the console.
+     */
+    boolean censor() default false;
+
+    /**
+     * Character to use when censoring the argument in the console.
+     *
+     * @return the Character to use when censoring the argument in the console.
+     */
+    char mask() default '*';
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/5228a23f/shell/core/src/main/java/org/apache/karaf/shell/api/action/Option.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/api/action/Option.java b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Option.java
index bd15244..f4214ec 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/api/action/Option.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/api/action/Option.java
@@ -94,4 +94,19 @@ public @interface Option
      * @return the option description as shown in the help.
      */
     String valueToShowInHelp() default DEFAULT_STRING;
+
+    /**
+     * Censor the argument in the console. Characters will be replaced with {@link Argument#mask()}.
+     * This is useful for hiding sensitive data like passwords.
+     *
+     * @return true if the argument should be censored in the console.
+     */
+    boolean censor() default false;
+
+    /**
+     * Character to use when censoring the argument in the console.
+     *
+     * @return the Character to use when censoring the argument in the console.
+     */
+    char mask() default '*';
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/5228a23f/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ActionMaskingCallback.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ActionMaskingCallback.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ActionMaskingCallback.java
new file mode 100644
index 0000000..33c7dbe
--- /dev/null
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/ActionMaskingCallback.java
@@ -0,0 +1,161 @@
+/*
+ * 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.karaf.shell.impl.action.command;
+
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Option;
+import org.jline.reader.ParsedLine;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+public class ActionMaskingCallback {
+
+    private final ActionCommand command;
+    private final Set<String> booleanOptions;
+    private final Map<String, Option> typedOptions;
+    private final List<Argument> arguments;
+
+    public static ActionMaskingCallback build(ActionCommand command) {
+        Set<String> booleanOptions = new HashSet<>();
+        Map<String, Option> typedOptions = new HashMap<>();
+        List<Argument> arguments = new ArrayList<>();
+        boolean censor = false;
+        for (Class<?> type = command.getActionClass(); type != null; type = type.getSuperclass()) {
+            for (Field field : type.getDeclaredFields()) {
+                Option option = field.getAnnotation(Option.class);
+                if (option != null) {
+                    if (field.getType() == boolean.class || field.getType() == Boolean.class) {
+                        booleanOptions.add(option.name());
+                        booleanOptions.addAll(Arrays.asList(option.aliases()));
+                    } else {
+                        typedOptions.put(option.name(), option);
+                        Arrays.asList(option.aliases()).forEach(action -> typedOptions.put(option.name(), option));
+                        censor |= option.censor();
+                    }
+                }
+                Argument argument = field.getAnnotation(Argument.class);
+                if (argument != null) {
+                    arguments.add(argument);
+                    censor |= argument.censor();
+                }
+            }
+        }
+        arguments.sort(Comparator.comparing(Argument::index));
+        return censor ? new ActionMaskingCallback(command, booleanOptions, typedOptions, arguments) : null;
+    }
+
+    private ActionMaskingCallback(ActionCommand command, Set<String> booleanOptions, Map<String, Option> typedOptions, List<Argument> arguments) {
+        this.command = command;
+        this.booleanOptions = booleanOptions;
+        this.typedOptions = typedOptions;
+        this.arguments = arguments;
+    }
+
+    public String filter(String line, ParsedLine parsed) {
+        int prev = 0;
+        StringBuilder sb = new StringBuilder();
+        int cur = line.indexOf(parsed.line());
+        List<String> words = parsed.words();
+        int state = 0;
+        int arg = 0;
+        for (int word = 0; word < words.size(); word++) {
+            String wordStr = words.get(word);
+            switch (state) {
+                // command
+                case 0:
+                    cur = line.indexOf(wordStr, cur) + wordStr.length();
+                    state++;
+                    break;
+                // option
+                case 1:
+                    if (wordStr.startsWith("-")) {
+                        int idxEq = wordStr.indexOf('=');
+                        if (idxEq > 0) {
+                            String name = wordStr.substring(0, idxEq);
+                            if (booleanOptions.contains(name)) {
+                                break;
+                            }
+                            Option option = typedOptions.get(name);
+                            if (option != null && option.censor()) {
+                                cur = line.indexOf(wordStr, cur);
+                                sb.append(line.substring(prev, cur + idxEq + 1));
+                                for (int i = idxEq + 1; i < wordStr.length(); i++) {
+                                    sb.append(option.mask());
+                                }
+                                prev = cur = cur + wordStr.length();
+                            }
+                        } else {
+                            String name = wordStr;
+                            if (booleanOptions.contains(name)) {
+                                break;
+                            }
+                            Option option = typedOptions.get(name);
+                            if (option != null) {
+                                // skip value
+                                word++;
+                                if (option.censor() && word < words.size()) {
+                                    String val = words.get(word);
+                                    cur = line.indexOf(val, cur);
+                                    sb.append(line.substring(prev, cur));
+                                    for (int i = 0; i < val.length(); i++) {
+                                        sb.append(option.mask());
+                                    }
+                                    prev = cur = cur + val.length();
+                                }
+                            }
+                        }
+                        break;
+                    } else {
+                        state = 2;
+                        // fall through
+                    }
+                // argument
+                case 2:
+                    if (arg < arguments.size()) {
+                        Argument argument = arguments.get(arg);
+                        if (argument.censor()) {
+                            cur = line.indexOf(wordStr, cur);
+                            sb.append(line.substring(prev, cur));
+                            for (int i = 0; i < wordStr.length(); i++) {
+                                sb.append(argument.mask());
+                            }
+                            prev = cur = cur + wordStr.length();
+                        }
+                        if (!argument.multiValued()) {
+                            arg++;
+                        }
+                    }
+                    break;
+            }
+        }
+        if (prev < line.length()) {
+            sb.append(line, prev, line.length());
+        }
+        return sb.toString();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/5228a23f/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/DefaultActionPreparator.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/DefaultActionPreparator.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/DefaultActionPreparator.java
index 313e2a2..b4ceb27 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/DefaultActionPreparator.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/DefaultActionPreparator.java
@@ -283,6 +283,16 @@ public class DefaultActionPreparator {
                 public Class<? extends Annotation> annotationType() {
                     return delegate.annotationType();
                 }
+
+                @Override
+                public boolean censor() {
+                    return delegate.censor();
+                }
+
+                @Override
+                public char mask() {
+                    return delegate.mask();
+                }
             };
         }
         return argument;

http://git-wip-us.apache.org/repos/asf/karaf/blob/5228a23f/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/HelpOption.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/HelpOption.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/HelpOption.java
index ec0b1a8..8a409a0 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/HelpOption.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/action/command/HelpOption.java
@@ -50,6 +50,14 @@ public class HelpOption {
             return Option.DEFAULT_STRING;
         }
 
+        public boolean censor() {
+            return false;
+        }
+
+        public char mask() {
+            return 0;
+        }
+
         public Class<? extends Annotation> annotationType() {
             return Option.class;
         }

http://git-wip-us.apache.org/repos/asf/karaf/blob/5228a23f/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
----------------------------------------------------------------------
diff --git a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
index 7fd3ced..34795ed 100644
--- a/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
+++ b/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
@@ -27,6 +27,8 @@ import java.lang.management.ManagementFactory;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -53,6 +55,8 @@ import org.apache.karaf.shell.api.console.Registry;
 import org.apache.karaf.shell.api.console.Session;
 import org.apache.karaf.shell.api.console.SessionFactory;
 import org.apache.karaf.shell.api.console.Terminal;
+import org.apache.karaf.shell.impl.action.command.ActionCommand;
+import org.apache.karaf.shell.impl.action.command.ActionMaskingCallback;
 import org.apache.karaf.shell.impl.console.parsing.CommandLineParser;
 import org.apache.karaf.shell.impl.console.parsing.KarafParser;
 import org.apache.karaf.shell.support.ShellUtil;
@@ -105,6 +109,7 @@ public class ConsoleSessionImpl implements Session {
     final org.jline.terminal.Terminal jlineTerminal;
     final History history;
     final LineReader reader;
+    final AggregateMaskingCallback maskingCallback;
 
     private Thread thread;
     private Properties brandingProps;
@@ -159,6 +164,9 @@ public class ConsoleSessionImpl implements Session {
             commandsCompleter.complete(rdr, line, candidates);
         };
 
+        // Masking
+        maskingCallback = new AggregateMaskingCallback();
+
         // Console reader
         reader = LineReaderBuilder.builder()
                     .terminal(jlineTerminal)
@@ -411,7 +419,7 @@ public class ConsoleSessionImpl implements Session {
         CharSequence command = null;
         reading.set(true);
         try {
-            reader.readLine(getPrompt(), getRPrompt(), (MaskingCallback) null, null);
+            reader.readLine(getPrompt(), getRPrompt(), maskingCallback, null);
             ParsedLine pl = reader.getParsedLine();
             if (pl instanceof ParsedLineImpl) {
                 command = ((ParsedLineImpl) pl).program();
@@ -616,4 +624,54 @@ public class ConsoleSessionImpl implements Session {
         return parts[0];
     }
 
+    private class AggregateMaskingCallback implements MaskingCallback {
+
+        private final List<Command> commands = new ArrayList<>();
+        private final Map<String, ActionMaskingCallback> regexs = new HashMap<>();
+
+        @Override
+        public String display(String line) {
+            return compute(line);
+        }
+
+        @Override
+        public String history(String line) {
+            return compute(line);
+        }
+
+        private String compute(String line) {
+            Collection<Command> commands;
+            boolean update;
+            synchronized (this) {
+                commands = factory.getRegistry().getCommands();
+                update = !commands.equals(this.commands);
+            }
+            if (update) {
+                Map<String, ActionMaskingCallback> regexs = new HashMap<>();
+                for (Command cmd : commands) {
+                    if (cmd instanceof ActionCommand) {
+                        ActionMaskingCallback amc = ActionMaskingCallback.build((ActionCommand) cmd);
+                        if (amc != null) {
+                            regexs.put(cmd.getScope() + ":" + cmd.getName(), amc);
+                        }
+                    }
+                }
+                synchronized (this) {
+                    this.commands.clear();
+                    this.regexs.clear();
+                    this.commands.addAll(commands);
+                    this.regexs.putAll(regexs);
+                }
+            }
+            ParsedLine pl = reader.getParser().parse(line, line.length());
+            String cmd = resolveCommand(pl.words().get(0));
+            ActionMaskingCallback repl = regexs.get(cmd);
+            if (repl != null) {
+                line = repl.filter(line, pl);
+            }
+            return line;
+        }
+
+    }
+
 }

http://git-wip-us.apache.org/repos/asf/karaf/blob/5228a23f/shell/core/src/test/java/org/apache/karaf/shell/impl/action/command/ActionMaskingCallbackTest.java
----------------------------------------------------------------------
diff --git a/shell/core/src/test/java/org/apache/karaf/shell/impl/action/command/ActionMaskingCallbackTest.java b/shell/core/src/test/java/org/apache/karaf/shell/impl/action/command/ActionMaskingCallbackTest.java
new file mode 100644
index 0000000..672afdd
--- /dev/null
+++ b/shell/core/src/test/java/org/apache/karaf/shell/impl/action/command/ActionMaskingCallbackTest.java
@@ -0,0 +1,113 @@
+/*
+ * 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.karaf.shell.impl.action.command;
+
+import org.apache.felix.gogo.runtime.CommandProcessorImpl;
+import org.apache.felix.gogo.runtime.threadio.ThreadIOImpl;
+import org.apache.felix.service.command.CommandProcessor;
+import org.apache.felix.service.threadio.ThreadIO;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Option;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.api.console.SessionFactory;
+import org.apache.karaf.shell.impl.console.HeadlessSessionImpl;
+import org.apache.karaf.shell.impl.console.SessionFactoryImpl;
+import org.apache.karaf.shell.impl.console.parsing.KarafParser;
+import org.jline.reader.ParsedLine;
+import org.jline.reader.Parser;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.PrintStream;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+public class ActionMaskingCallbackTest {
+
+    private Parser parser;
+    private ActionMaskingCallback cb;
+
+    @Before
+    public void setUp() {
+        ThreadIO tio = new ThreadIOImpl();
+        CommandProcessor cp = new CommandProcessorImpl(tio);
+        SessionFactory sf = new SessionFactoryImpl(tio);
+        InputStream is = new ByteArrayInputStream(new byte[0]);
+        PrintStream os = new PrintStream(new ByteArrayOutputStream());
+        Session session = new HeadlessSessionImpl(sf, cp, is, os, os);
+        parser = new KarafParser(session);
+
+        ActionCommand cmd = new ActionCommand(null, UserAddCommand.class);
+        cb = ActionMaskingCallback.build(cmd);
+    }
+
+    @Test
+    public void testJaasUserAdd() throws Exception {
+        check("user-add user password ", "user-add user ######## ");
+        check("user-add --help user password ", "user-add --help user ######## ");
+        check("user-add --help user password foo", "user-add --help user ######## foo");
+        check("user-add --opt1 user password foo", "user-add --opt1 user ######## foo");
+        check("user-add --opt2 valOpt2 user password foo", "user-add --opt2 valOpt2 user ######## foo");
+        check("user-add --opt2=valOpt2 user password foo", "user-add --opt2=valOpt2 user ######## foo");
+        check("user-add --opt1 --opt2 valOpt2 --opt3=valOpt3 user password foo", "user-add --opt1 --opt2 valOpt2 --opt3=@@@@@@@ user ######## foo");
+        check("user-add --opt1 --opt2 valOpt2 --opt3 valOpt3 user password foo", "user-add --opt1 --opt2 valOpt2 --opt3 @@@@@@@ user ######## foo");
+    }
+
+    private void check(String input, String expected) {
+        String output = cb.filter(input, parser.parse(input, input.length()));
+        assertEquals(expected, output);
+    }
+
+
+    @Command(scope = "jaas", name = "user-add", description = "Add a user")
+    @Service
+    public static class UserAddCommand implements Action {
+
+        @Option(name = "--opt1")
+        private boolean opt1;
+
+        @Option(name = "--opt2")
+        private String opt2;
+
+        @Option(name = "--opt3", censor = true, mask = '@')
+        private String opt3;
+
+        @Argument(index = 0, name = "username")
+        private String username;
+
+        @Argument(index = 1, name = "password", censor = true, mask = '#')
+        private String password;
+
+        @Argument(index = 2, name = "foo")
+        private String foo;
+
+        @Override
+        public Object execute() throws Exception {
+            return null;
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/karaf/blob/5228a23f/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/commands/AbstractCommandHelpPrinter.java
----------------------------------------------------------------------
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/commands/AbstractCommandHelpPrinter.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/commands/AbstractCommandHelpPrinter.java
index dee1eb9..eecad47 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/commands/AbstractCommandHelpPrinter.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/commands/AbstractCommandHelpPrinter.java
@@ -58,6 +58,14 @@ public abstract class AbstractCommandHelpPrinter implements CommandHelpPrinter {
                 public Class<? extends Annotation> annotationType() {
                     return delegate.annotationType();
                 }
+
+                public boolean censor() {
+                    return delegate.censor();
+                }
+
+                public char mask() {
+                    return delegate.mask();
+                }
             };
         }
         return argument;


[4/4] karaf git commit: Merge branch 'KARAF-5287', fixes #352

Posted by gn...@apache.org.
Merge branch 'KARAF-5287', fixes #352


Project: http://git-wip-us.apache.org/repos/asf/karaf/repo
Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/46503d10
Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/46503d10
Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/46503d10

Branch: refs/heads/master
Commit: 46503d10ec6c9e5c94ed21a49ff1c88dc949f3e2
Parents: af5ae51 5228a23
Author: Guillaume Nodet <gn...@gmail.com>
Authored: Tue Sep 12 20:34:46 2017 +0200
Committer: Guillaume Nodet <gn...@gmail.com>
Committed: Tue Sep 12 20:34:46 2017 +0200

----------------------------------------------------------------------
 .../karaf/jaas/command/UserAddCommand.java      |   2 +-
 .../apache/karaf/shell/api/action/Argument.java |  15 ++
 .../apache/karaf/shell/api/action/Option.java   |  15 ++
 .../action/command/ActionMaskingCallback.java   | 161 +++++++++++++++++++
 .../action/command/DefaultActionPreparator.java |  10 ++
 .../shell/impl/action/command/HelpOption.java   |   8 +
 .../shell/impl/console/ConsoleSessionImpl.java  |  60 ++++++-
 .../command/ActionMaskingCallbackTest.java      | 113 +++++++++++++
 .../commands/AbstractCommandHelpPrinter.java    |   8 +
 9 files changed, 390 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/karaf/blob/46503d10/shell/core/src/main/java/org/apache/karaf/shell/impl/console/ConsoleSessionImpl.java
----------------------------------------------------------------------