Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ public class CredentialShell extends CommandShell {
" [-help]\n" +
" [" + CreateCommand.USAGE + "]\n" +
" [" + DeleteCommand.USAGE + "]\n" +
" [" + ListCommand.USAGE + "]\n";
" [" + ListCommand.USAGE + "]\n" +
" [" + CheckCommand.USAGE + "]\n";
@VisibleForTesting
public static final String NO_VALID_PROVIDERS =
"There are no valid (non-transient) providers configured.\n" +
Expand All @@ -66,6 +67,7 @@ public class CredentialShell extends CommandShell {
* <pre>
* % hadoop credential create alias [-provider providerPath]
* % hadoop credential list [-provider providerPath]
* % hadoop credential check alias [-provider providerPath]
* % hadoop credential delete alias [-provider providerPath] [-f]
* </pre>
* @param args
Expand All @@ -86,6 +88,11 @@ protected int init(String[] args) throws IOException {
return 1;
}
setSubCommand(new CreateCommand(args[++i]));
} else if (args[i].equals("check")) {
if (i == args.length -1) {
return 1;
}
setSubCommand(new CheckCommand(args[++i]));
} else if (args[i].equals("delete")) {
if (i == args.length - 1) {
return 1;
Expand Down Expand Up @@ -293,6 +300,83 @@ public String getUsage() {
}
}

private class CheckCommand extends Command {
public static final String USAGE = "check <alias> [-value alias-value] " +
"[-provider provider-path] [-strict]";
public static final String DESC =
"The check subcommand check a password for the name\n" +
"specified as the <alias> argument within the provider indicated\n" +
"through the -provider argument. If -strict is supplied, fail\n" +
"immediately if the provider requires a password and none is given.\n" +
"If -value is provided, use that for the value of the credential\n" +
"instead of prompting the user.";

private String alias = null;

public CheckCommand(String alias) {
this.alias = alias;
}

public boolean validate() {
if (alias == null) {
getOut().println("There is no alias specified. Please provide the" +
"mandatory <alias>. See the usage description with -help.");
return false;
}
if (alias.equals("-help")) {
return true;
}
try {
provider = getCredentialProvider();
if (provider == null) {
return false;
} else if (provider.needsPassword()) {
if (strict) {
getOut().println(provider.noPasswordError());
return false;
} else {
getOut().println(provider.noPasswordWarning());
}
}
} catch (IOException e) {
e.printStackTrace(getErr());
}
return true;
}

public void execute() throws IOException, NoSuchAlgorithmException {
if (alias.equals("-help")) {
doHelp();
return;
}
warnIfTransientProvider();
getOut().println("Checking aliases for CredentialProvider: " +
provider.toString());
try {
PasswordReader c = getPasswordReader();
if (c == null) {
throw new IOException("No console available for checking user.");
}

char[] password = c.readPassword("Enter alias password: ");
char[] storePassword = provider.getCredentialEntry(alias).getCredential();
String beMatch = Arrays.equals(storePassword, password) ? "success" : "failed";

getOut().println("Password match " + beMatch + " for " + alias + ".");
} catch (IOException e) {
getOut().println("Cannot check aliases for CredentialProvider: " +
provider.toString()
+ ": " + e.getMessage());
throw e;
}
}

@Override
public String getUsage() {
return USAGE + ":\n\n" + DESC;
}
}

private class CreateCommand extends Command {
public static final String USAGE = "create <alias> [-value alias-value] " +
"[-provider provider-path] [-strict]";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ Usage: `hadoop credential <subcommand> [options]`
| create *alias* [-provider *provider-path*] [-strict] [-value *credential-value*] | Prompts the user for a credential to be stored as the given alias. The *hadoop.security.credential.provider.path* within the core-site.xml file will be used unless a `-provider` is indicated. The `-strict` flag will cause the command to fail if the provider uses a default password. Use `-value` flag to supply the credential value (a.k.a. the alias password) instead of being prompted. |
| delete *alias* [-provider *provider-path*] [-strict] [-f] | Deletes the credential with the provided alias. The *hadoop.security.credential.provider.path* within the core-site.xml file will be used unless a `-provider` is indicated. The `-strict` flag will cause the command to fail if the provider uses a default password. The command asks for confirmation unless `-f` is specified |
| list [-provider *provider-path*] [-strict] | Lists all of the credential aliases The *hadoop.security.credential.provider.path* within the core-site.xml file will be used unless a `-provider` is indicated. The `-strict` flag will cause the command to fail if the provider uses a default password. |
| check *alias* [-provider *provider-path*] [-strict] | Check password for the given alias. The *hadoop.security.credential.provider.path* within the core-site.xml file will be used unless a `-provider` is indicated. The `-strict` flag will cause the command to fail if the provider uses a default password. |

Command to manage credentials, passwords and secrets within credential providers.

Expand Down Expand Up @@ -221,6 +222,8 @@ Usage: `hadoop key <subcommand> [options]`
| roll *keyname* [-provider *provider*] [-strict] [-help] | Creates a new version for the specified key within the provider indicated using the `-provider` argument. The `-strict` flag will cause the command to fail if the provider uses a default password. |
| delete *keyname* [-provider *provider*] [-strict] [-f] [-help] | Deletes all versions of the key specified by the *keyname* argument from within the provider specified by `-provider`. The `-strict` flag will cause the command to fail if the provider uses a default password. The command asks for user confirmation unless `-f` is specified. |
| list [-provider *provider*] [-strict] [-metadata] [-help] | Displays the keynames contained within a particular provider as configured in core-site.xml or specified with the `-provider` argument. The `-strict` flag will cause the command to fail if the provider uses a default password. `-metadata` displays the metadata. |
| check *keyname* [-provider *provider*] [-strict] [-help] | Check password of the *keyname* contained within a particular provider as configured in core-site.xml or specified with the `-provider` argument. The `-strict` flag will cause the command to fail if the provider uses a default password. |

| -help | Prints usage of this command |

Manage keys via the KeyProvider. For details on KeyProviders, see the [Transparent Encryption Guide](../hadoop-hdfs/TransparentEncryption.html).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,11 +174,20 @@ public void testPromptForCredential() throws Exception {
assertEquals(0, rc);
assertTrue(outContent.toString().contains("credential1 has been successfully " +
"created."));

String[] args2 = {"delete", "credential1", "-f", "-provider",
jceksProvider};

String[] args2 = {"check", "credential1", "-provider",
jceksProvider};
ArrayList<String> password = new ArrayList<String>();
password.add("p@ssw0rd");
shell.setPasswordReader(new MockPasswordReader(password));
rc = shell.run(args2);
assertEquals(0, rc);
assertTrue(outContent.toString().contains("Password match success for credential1."));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add an error message here which includes the failing string if the conditions not met. FWIW we are moving to using AssertJ assertions -if you are happy with them, feel free to use them over classic junit asserts

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An error check added.


String[] args3 = {"delete", "credential1", "-f", "-provider",
jceksProvider};
rc = shell.run(args3);
assertEquals(0, rc);
assertTrue(outContent.toString().contains("credential1 has been successfully " +
"deleted."));
}
Expand Down