Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions core/auth/src/main/java/com/nubeiot/auth/BasicCredential.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,18 @@

public class BasicCredential extends Credential {

@Getter
private final String user;

@Getter
private final String password;

@JsonCreator
public BasicCredential(@JsonProperty(value = "type", required = true) CredentialType type,
@JsonProperty(value = "user", required = true) String user,
@JsonProperty(value = "password", required = true) String password) {
super(type, user);
super(type);
this.user = user;
this.password = password;
}

Expand All @@ -40,7 +44,7 @@ public String computeHeader() {

@Override
public String toString() {
return super.toString() + "::Password:*****";
return super.toString() + " :: User: " + user + " :: Password: *****";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package com.nubeiot.auth;

import java.nio.charset.Charset;
import java.util.Base64;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.nubeiot.core.SecretProperty;

import lombok.Getter;

public class BasicSecretCredential extends Credential {

@Getter
private final SecretProperty user;

@Getter
private final SecretProperty password;

@JsonCreator
public BasicSecretCredential(@JsonProperty(value = "type", required = true) CredentialType type,
@JsonProperty(value = "user", required = true) SecretProperty user,
@JsonProperty(value = "password", required = true) SecretProperty password) {
super(type);
this.user = user;
this.password = password;
}

@Override
public String computeUrl(String defaultUrl) {
return this.computeRemoteUrl(defaultUrl);
}

@Override
public String computeUrlCredential() {
return this.getUser().getValue() + ":" + this.getPassword().getValue() + "@";
}

@Override
public String computeHeader() {
return "Basic " + Base64.getEncoder()
.encodeToString(
(this.getUser().getValue() + ":" + this.getPassword().getValue()).getBytes(
Charset.forName("UTF-8")));
}

@Override
public String toString() {
return super.toString() + " :: User: " + user.getValue() + " :: Password:*****";
}

}
32 changes: 24 additions & 8 deletions core/auth/src/main/java/com/nubeiot/auth/Credential.java
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
package com.nubeiot.auth;

import static com.nubeiot.core.IConfig.recomputeReferences;

import io.vertx.core.json.JsonObject;

import com.fasterxml.jackson.annotation.JsonSubTypes;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.JsonTypeInfo.Id;
import com.nubeiot.core.IConfig;
import com.nubeiot.core.SecretConfig;

import lombok.Getter;
import lombok.RequiredArgsConstructor;
Expand All @@ -11,33 +17,43 @@
@JsonTypeInfo(use = Id.NAME, property = "type", visible = true)
@JsonSubTypes( {
@JsonSubTypes.Type(value = BasicCredential.class, name = "BASIC"),
@JsonSubTypes.Type(value = BasicSecretCredential.class, name = "BASIC_SECRET"),
@JsonSubTypes.Type(value = TokenCredential.class, name = "TOKEN"),
})
public abstract class Credential {

@Getter
private final CredentialType type;

@Getter
private final String user;

public abstract String computeUrl(String defaultUrl);

protected abstract String computeUrlCredential();
abstract String computeUrlCredential();

public abstract String computeHeader();

protected String computeRemoteUrl(String defaultUrl) {
return defaultUrl.replaceFirst("^((https?|wss?)\\:\\/\\/)(.+)", "$1" + this.computeUrlCredential() + "$3");
String computeRemoteUrl(String defaultUrl) {
return defaultUrl.replaceFirst("^((https?|wss?)://)(.+)", "$1" + this.computeUrlCredential() + "$3");
}

@SuppressWarnings("unchecked")
public static <C extends IConfig> C recomputeReferenceCredentials(C config, SecretConfig secretConfig) {
return IConfig.from(recomputeReferences(config.toJson(), (jObject, key, value) -> {
if (key.equals("type") && value.equals("BASIC")) {
jObject.put("type", "BASIC_SECRET");
} else if (value.startsWith("@secret")) {
jObject.put(key,
new JsonObject().put("ref", value).put("value", secretConfig.decode(value).getValue()));
}
}), (Class<C>) config.getClass());
}

@Override
public String toString() {
return "User: " + user + "::Type: " + type;
return "Type: " + type;
}

public enum CredentialType {
BASIC, TOKEN
BASIC, BASIC_SECRET, TOKEN
}

}
8 changes: 6 additions & 2 deletions core/auth/src/main/java/com/nubeiot/auth/TokenCredential.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@

public class TokenCredential extends Credential {

@Getter
private final String user;

@Getter
private final String token;

@JsonCreator
public TokenCredential(@JsonProperty(value = "type", required = true) CredentialType type,
@JsonProperty(value = "user", required = false) String user,
@JsonProperty(value = "token", required = true) String token) {
super(type, user);
super(type);
this.user = user;
this.token = token;
}

Expand All @@ -37,7 +41,7 @@ public String computeHeader() {

@Override
public String toString() {
return super.toString() + "::Token: ******************************";
return super.toString() + " :: User: " + user + " :: Token: ******************************";
}

}
35 changes: 31 additions & 4 deletions core/auth/src/test/java/com/nubeiot/auth/CredentialTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@
import io.vertx.core.json.JsonObject;

import com.nubeiot.auth.Credential.CredentialType;
import com.nubeiot.core.IConfig;
import com.nubeiot.core.NubeConfig;
import com.nubeiot.core.NubeConfig.AppConfig.AppSecretConfig;
import com.nubeiot.core.SecretProperty;
import com.nubeiot.core.dto.JsonData;
import com.nubeiot.core.utils.Configs;

public class CredentialTest {

Expand All @@ -16,10 +21,10 @@ public void test_basic_credential() {
jsonObject.put("type", "BASIC");
jsonObject.put("user", "xx");
jsonObject.put("password", "abc");
Credential credential = JsonData.convert(jsonObject, BasicCredential.class);
BasicCredential credential = JsonData.convert(jsonObject, BasicCredential.class);
Assert.assertEquals(Credential.CredentialType.BASIC, credential.getType());
Assert.assertEquals("xx", credential.getUser());
Assert.assertEquals("abc", ((BasicCredential) credential).getPassword());
Assert.assertEquals("abc", credential.getPassword());
}

@Test
Expand Down Expand Up @@ -47,9 +52,9 @@ public void test_token_credential() {
JsonObject jsonObject = new JsonObject();
jsonObject.put("type", "TOKEN");
jsonObject.put("token", "abcdef");
Credential credential = JsonData.convert(jsonObject, TokenCredential.class);
TokenCredential credential = JsonData.convert(jsonObject, TokenCredential.class);
Assert.assertEquals(CredentialType.TOKEN, credential.getType());
Assert.assertEquals("abcdef", ((TokenCredential) credential).getToken());
Assert.assertEquals("abcdef", credential.getToken());
}

@Test
Expand Down Expand Up @@ -83,4 +88,26 @@ public void test_compute_url() {
Assert.assertEquals("wss://xx:abc@abc.xyz", credential.computeUrl("wss://abc.xyz"));
}

@Test
public void test_basic_secret_credential() {
JsonObject jsonObject = new JsonObject();
jsonObject.put("type", "BASIC_SECRET");
jsonObject.put("user", new SecretProperty("@secret.user", "xx").toJson());
jsonObject.put("password", new SecretProperty("@secret.password", "abc").toJson());
BasicSecretCredential credential = JsonData.convert(jsonObject, BasicSecretCredential.class);
Assert.assertEquals(CredentialType.BASIC_SECRET, credential.getType());
Assert.assertEquals("xx", credential.getUser().getValue());
Assert.assertEquals("abc", credential.getPassword().getValue());
Assert.assertEquals("@secret.user", credential.getUser().getRef());
Assert.assertEquals("@secret.password", credential.getPassword().getRef());
}

@Test
public void test_recompute_reference_credential() {
NubeConfig nubeConfig = IConfig.from(Configs.loadJsonConfig("nube-cfg.json"), NubeConfig.class);
AppSecretConfig secretConfig = IConfig.from(nubeConfig.getAppConfig(), AppSecretConfig.class);
JsonObject output = Credential.recomputeReferenceCredentials(nubeConfig, secretConfig).toJson();
Assert.assertTrue(output.encode().contains("BASIC_SECRET"));
}

}
49 changes: 49 additions & 0 deletions core/auth/src/test/resources/nube-cfg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"__app__": {
"__installer__": {
"auto_install": true,
"repository": {
"remote": {
"urls": {
"JAVA": [
{
"credential": {
"type": "BASIC",
"user": "@secret.user",
"password": "@secret.password"
},
"url": "http://nexus:8081/repository/maven-releases/"
},
{
"credential": {
"type": "BASIC",
"user": "@secret.user",
"password": "@secret.password"
},
"url": "http://nexus:8081/repository/maven-snapshots/"
},
{
"credential": {
"type": "BASIC",
"user": "@secret.user",
"password": "@secret.password"
},
"url": "http://nexus:8081/repository/maven-central/"
},
{
"url": "https://maven.mangoautomation.net/repository/ias-snapshot/"
},
{
"url": "https://maven.mangoautomation.net/repository/ias-release/"
}
]
}
}
}
},
"__secret__": {
"@user": "admin",
"@password": "admin123"
}
}
}
43 changes: 42 additions & 1 deletion core/base/src/main/java/com/nubeiot/core/IConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Supplier;

import io.vertx.core.json.DecodeException;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;

import com.fasterxml.jackson.annotation.JsonIgnore;
Expand All @@ -27,7 +29,9 @@
public interface IConfig extends JsonData {

ObjectMapper MAPPER = JsonData.MAPPER.copy().setSerializationInclusion(Include.NON_NULL);
ObjectMapper MAPPER_IGNORE_UNKNOWN_PROPERTY = MAPPER.copy().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
ObjectMapper MAPPER_IGNORE_UNKNOWN_PROPERTY = MAPPER.copy()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,
false);

static <T extends IConfig> T fromClasspath(String jsonFile, Class<T> clazz) {
return IConfig.from(Configs.loadJsonConfig(jsonFile), clazz);
Expand Down Expand Up @@ -123,6 +127,43 @@ default <T extends IConfig> JsonObject mergeToJson(@NonNull T to) {
return this.toJson().mergeIn(to.toJson(), true);
}

@SuppressWarnings("unchecked")
static <C extends IConfig> C recomputeReferences(C config, SecretConfig secretConfig) {
return IConfig.from(recomputeReferences(config.toJson(), (jObject, key, value) -> {
jObject.put(key, secretConfig.decode(value).getValue());
}), (Class<C>) config.getClass());
}

static Object recomputeReferences(Object config, TriConsumer<JsonObject, String, String> consumer) {
if (config instanceof JsonObject) {
JsonObject jObject = (JsonObject) config;
Set<String> keys = jObject.fieldNames();

for (String key : keys) {
Object value = jObject.getValue(key);
if (value instanceof JsonObject || value instanceof JsonArray) {
recomputeReferences(value, consumer);
} else if (value instanceof String) {
consumer.accept(jObject, key, (String) value);
}
}
} else if (config instanceof JsonArray) {
JsonArray jArray = (JsonArray) config;
for (Object obj : jArray) {
recomputeReferences(obj, consumer);
}
}

return config;
}

static <T extends SecretConfig> T getSecretConfig(JsonObject jObject, Class<T> clazz) {
if (jObject.getJsonObject(SecretConfig.NAME) == null) {
return ReflectionClass.createObject(clazz);
}
return IConfig.from(jObject, clazz);
}

@Override
@SuppressWarnings("unchecked")
default JsonObject toJson() {
Expand Down
Loading