Skip to content

Commit 1b99c2b

Browse files
committed
ID-24: add lookup function for ANM hashed password generation
1 parent 7b210cc commit 1b99c2b

4 files changed

Lines changed: 204 additions & 0 deletions

File tree

CHANGELOG.adoc

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,39 @@ ifdef::env-github[]
99
:warning-caption: :warning:
1010
endif::[]
1111

12+
== Version 0.7.0
13+
[cols="1,2,<10a", options="header"]
14+
|===
15+
|ID|Type|Description
16+
|https://github.com/Axway-API-Management-Plus/yamles-utils/issues/21[#21]
17+
|Enhancement
18+
|Generate Files.
19+
20+
|https://github.com/Axway-API-Management-Plus/yamles-utils/issues/22[#22]
21+
|Enhancement
22+
|Evaluate Expression.
23+
24+
`eval` command to evaluate expression and print result to `stdout`.
25+
26+
Example:
27+
[source, shell]
28+
----
29+
$ export NAME="World"
30+
$ yamlesutils.sh -q eval "Hello {{ _env('NAME') }}!"
31+
Hello World!
32+
----
33+
|https://github.com/Axway-API-Management-Plus/yamles-utils/issues/24[#24]
34+
|Enhancement
35+
|Lookup function to generate hashed ANM password.
36+
37+
Example:
38+
[source, shell]
39+
----
40+
$ yamlesutils.sh -q eval "{{ _gen_anm_pwd_hash('changeme') }}"
41+
$AAGQAAAAAQAC$oALW5N6CWi0PszIfVK3w5w==$uERZwFPmZ2bEknEfZiyrK7QfqcODTyjFJNrbpEQfEDI=
42+
----
43+
|===
44+
1245
== Version 0.6.0
1346
[cols="1,2,<10a", options="header"]
1447
|===

docs/asciidoc/_plugin_core.adoc

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,44 @@ The lookup function requires a single key parameter which represents the name of
9494
----
9595
<1> Retrieves the value from the system property `my.secret`.
9696

97+
=== Admin Node Manager Password Hash (built-in)
98+
99+
[cols="2,6a"]
100+
|===
101+
|*Name*
102+
|`gen_anm_pwd_hash`
103+
104+
|*Built-In*
105+
|yes
106+
107+
|*Synopsis*
108+
|Generates a hashed password for the Admin Node Manager.
109+
110+
2+|*Configuration Parameters*
111+
2+|not required
112+
113+
2+|*Lookup Function Arguments*
114+
|`pwd`
115+
|Clear text password.
116+
|===
117+
118+
This built-in lookup provider generates a hashed password, which can be used for the Admin Node Manager inside the `adminUsers.json` configuration file.
119+
120+
This provider is used by the built-in lookup function `_gen_anm_pwd_hash`.
121+
Configuration of this lookup provider is not required.
122+
123+
The lookup function requires a single key parameter which represents the clear text password to be hashed.
124+
The password can also be retrived by calling a nested lookup function.
125+
126+
.Example
127+
[source]
128+
----
129+
{{ _gen_anm_pwd_hash("change") }} #<1>
130+
{{ _gen_anm_pwd_hash(_env("ADMIN_PASSWORD")) }} #<2>
131+
----
132+
<1> Generates a hased password from a clear text password.
133+
<2> Generates a hased password from the value of the `ADMIN_PASSWORD` environment variable.
134+
97135
=== JSON from Environment Variables
98136

99137
[cols="2,6a"]
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package com.axway.yamles.utils.plugins.core;
2+
3+
import java.security.SecureRandom;
4+
import java.util.Base64;
5+
import java.util.Map;
6+
import java.util.Optional;
7+
8+
import javax.crypto.SecretKeyFactory;
9+
import javax.crypto.spec.PBEKeySpec;
10+
11+
import org.pf4j.Extension;
12+
13+
import com.axway.yamles.utils.plugins.AbstractBuiltinLookupProvider;
14+
import com.axway.yamles.utils.plugins.FunctionArgument;
15+
import com.axway.yamles.utils.plugins.LookupFunction;
16+
import com.axway.yamles.utils.plugins.LookupFunctionException;
17+
import com.axway.yamles.utils.plugins.LookupProviderException;
18+
19+
@Extension
20+
public class AnmPasswordHashLookupProvider extends AbstractBuiltinLookupProvider {
21+
public static class PasswordHashGenerator {
22+
public static final String VERSION = "AAGQAAAAAQAC";
23+
24+
private PasswordHashGenerator() {
25+
};
26+
27+
public static String generate(String password) throws Exception {
28+
byte[] salt = generateSalt();
29+
byte[] hash = generateHashedPassord(password, salt);
30+
31+
String value = new StringBuilder() //
32+
.append('$').append(VERSION) //
33+
.append('$').append(Base64.getEncoder().encodeToString(salt)) //
34+
.append('$').append(Base64.getEncoder().encodeToString(hash)) //
35+
.toString();
36+
return value;
37+
}
38+
39+
private static byte[] generateSalt() {
40+
SecureRandom random = new SecureRandom();
41+
byte[] salt = new byte[16];
42+
random.nextBytes(salt);
43+
44+
return salt;
45+
}
46+
47+
private static byte[] generateHashedPassord(String password, byte[] salt) throws Exception {
48+
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 102400, 256);
49+
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
50+
return factory.generateSecret(spec).getEncoded();
51+
}
52+
}
53+
54+
protected static class LF extends LookupFunction {
55+
56+
public LF(String alias, AnmPasswordHashLookupProvider provider) {
57+
super(alias, provider, AbstractBuiltinLookupProvider.SOURCE);
58+
}
59+
60+
@Override
61+
public Optional<String> lookup(Map<String, Object> args) throws LookupFunctionException {
62+
String password = getArg(ARG_PWD, args, "");
63+
if (password == null || password.isEmpty()) {
64+
return Optional.empty();
65+
}
66+
try {
67+
return Optional.of(PasswordHashGenerator.generate(password));
68+
} catch (Exception e) {
69+
throw new LookupFunctionException(this, "ANM password hash generation failed", e);
70+
}
71+
}
72+
}
73+
74+
protected static FunctionArgument ARG_PWD = new FunctionArgument("pwd", true, "Password");
75+
76+
public AnmPasswordHashLookupProvider() {
77+
super();
78+
add(ARG_PWD);
79+
}
80+
81+
@Override
82+
public String getName() {
83+
return "gen_anm_pwd_hash";
84+
}
85+
86+
@Override
87+
public String getSummary() {
88+
return "Generate hashed password for Admin Node Manager user.";
89+
}
90+
91+
@Override
92+
public String getDescription() {
93+
return "Use a clear text password to generate a hashed password to be used for ANM users in 'adminUsers.json' file.";
94+
}
95+
96+
@Override
97+
protected LookupFunction buildFunction() throws LookupProviderException {
98+
return new LF(getName(), this);
99+
}
100+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package com.axway.yamles.utils.plugins.core;
2+
3+
import static org.junit.jupiter.api.Assertions.assertTrue;
4+
5+
import java.util.HashMap;
6+
import java.util.Map;
7+
8+
import org.junit.jupiter.api.Test;
9+
10+
import com.axway.yamles.utils.plugins.LookupFunction;
11+
import com.axway.yamles.utils.plugins.core.AnmPasswordHashLookupProvider.PasswordHashGenerator;
12+
13+
public class AnmPasswordHashLookupProviderTest {
14+
15+
@Test
16+
void testGenerator() throws Exception {
17+
String passwordHash = PasswordHashGenerator.generate("changeme");
18+
assertTrue(passwordHash.startsWith("$" + AnmPasswordHashLookupProvider.PasswordHashGenerator.VERSION + "$"));
19+
}
20+
21+
@Test
22+
void testGeneratePasswordHash() throws Exception {
23+
AnmPasswordHashLookupProvider lp = new AnmPasswordHashLookupProvider();
24+
LookupFunction lf = lp.buildFunction();
25+
26+
Map<String, Object> args = new HashMap<>();
27+
args.put(AnmPasswordHashLookupProvider.ARG_PWD.getName(), "changeme");
28+
29+
String passwordHash = lf.lookup(args).get();
30+
31+
assertTrue(passwordHash.startsWith("$" + AnmPasswordHashLookupProvider.PasswordHashGenerator.VERSION + "$"));
32+
}
33+
}

0 commit comments

Comments
 (0)