From 96fc669b388cd6c1c4ce63f9135950e0eca2aeb3 Mon Sep 17 00:00:00 2001 From: Stefan Kalscheuer Date: Fri, 12 Aug 2016 17:49:53 +0200 Subject: [PATCH 1/6] Updated dependencies --- pom.xml | 14 +++++++------- .../jvault/connector/HTTPVaultConnector.java | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 6bc1f44..809881e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ de.stklcode.jvault connector - 0.1.1 + 0.1.2-SNAPSHOT @@ -27,33 +27,33 @@ commons-io commons-io - 2.4 + 2.5 org.apache.httpcomponents httpcore - 4.0.1 + 4.4.5 org.apache.httpcomponents httpclient - 4.0.2 + 4.5.2 com.fasterxml.jackson.core jackson-core - 2.7.2 + 2.8.1 com.fasterxml.jackson.core jackson-databind - 2.7.2 + 2.8.1 junit junit - 4.11 + 4.12 test diff --git a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java index 0be52bd..126d49a 100644 --- a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java +++ b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java @@ -293,7 +293,7 @@ public class HTTPVaultConnector implements VaultConnector { StringEntity input; try { input = new StringEntity(jsonMapper.writeValueAsString(payload), HTTP.UTF_8); - } catch (UnsupportedEncodingException | JsonProcessingException e) { + } catch (JsonProcessingException e) { throw new InvalidRequestException("Unable to parse response", e); } input.setContentEncoding("UTF-8"); From 27eb1a1e8a3371c1d0fac26c4de6f7c315a8a14d Mon Sep 17 00:00:00 2001 From: Stefan Kalscheuer Date: Fri, 12 Aug 2016 19:33:19 +0200 Subject: [PATCH 2/6] Javadoc warnings removed --- .../stklcode/jvault/connector/VaultConnector.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java index 7124765..d09ec03 100644 --- a/src/main/java/de/stklcode/jvault/connector/VaultConnector.java +++ b/src/main/java/de/stklcode/jvault/connector/VaultConnector.java @@ -60,6 +60,7 @@ public interface VaultConnector { /** * Get all availale authentication backends. * @return List of backends + * @throws VaultConnectorException on error */ List getAuthBackends() throws VaultConnectorException; @@ -67,6 +68,7 @@ public interface VaultConnector { * Authorize to Vault using token. * @param token The token * @return Token response + * @throws VaultConnectorException on error */ TokenResponse authToken(final String token) throws VaultConnectorException; @@ -75,7 +77,7 @@ public interface VaultConnector { * @param username The username * @param password The password * @return Authorization result - * @throws VaultConnectorException + * @throws VaultConnectorException on error */ AuthResponse authUserPass(final String username, final String password) throws VaultConnectorException; @@ -84,6 +86,7 @@ public interface VaultConnector { * @param appID The App ID * @param userID The User ID * @return TRUE on success + * @throws VaultConnectorException on error */ AuthResponse authAppId(final String appID, final String userID) throws VaultConnectorException; @@ -93,7 +96,7 @@ public interface VaultConnector { * @param policy The policy to associate with * @param displayName Arbitrary name to display * @return TRUE on success - * @throws VaultConnectorException + * @throws VaultConnectorException on error */ boolean registerAppId(final String appID, final String policy, final String displayName) throws VaultConnectorException; @@ -102,7 +105,7 @@ public interface VaultConnector { * @param appID The App-ID * @param userID The User-ID * @return TRUE on success - * @throws VaultConnectorException + * @throws VaultConnectorException on error */ boolean registerUserId(final String appID, final String userID) throws VaultConnectorException; @@ -113,7 +116,7 @@ public interface VaultConnector { * @param displayName Arbitrary name to display * @param userID The User-ID * @return TRUE on success - * @throws VaultConnectorException + * @throws VaultConnectorException on error */ default boolean registerAppUserId(final String appID, final String policy, final String displayName, final String userID) throws VaultConnectorException { return registerAppId(appID, policy, userID) && registerUserId(appID, userID); @@ -129,6 +132,7 @@ public interface VaultConnector { * Retrieve secret form Vault. * @param key Secret identifier * @return Secret response + * @throws VaultConnectorException on error */ SecretResponse readSecret(final String key) throws VaultConnectorException; @@ -136,6 +140,7 @@ public interface VaultConnector { * List available secrets from Vault. * @param path Root path to search * @return List of secret keys + * @throws VaultConnectorException on error */ List listSecrets(final String path) throws VaultConnectorException; @@ -144,6 +149,7 @@ public interface VaultConnector { * @param key Secret path * @param value Secret value * @return TRUE on success + * @throws VaultConnectorException on error */ boolean writeSecret(final String key, final String value) throws VaultConnectorException; } From ee5b112704ada8586fa92a524cafe95c2274a61c Mon Sep 17 00:00:00 2001 From: Stefan Kalscheuer Date: Sat, 13 Aug 2016 18:00:44 +0200 Subject: [PATCH 3/6] LeaseDuration checked for authorization status --- .../jvault/connector/HTTPVaultConnector.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java index 126d49a..ba33e06 100644 --- a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java +++ b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java @@ -50,6 +50,7 @@ public class HTTPVaultConnector implements VaultConnector { private boolean authorized = false; /* authorization status */ private String token; /* current token */ + private long tokenTTL = 0; /* expiration time for current token */ /** * Create connector using hostname and schema. @@ -97,6 +98,7 @@ public class HTTPVaultConnector implements VaultConnector { @Override public void resetAuth() { token = null; + tokenTTL = 0; authorized = false; } @@ -139,7 +141,7 @@ public class HTTPVaultConnector implements VaultConnector { @Override public boolean isAuthorized() { - return authorized; + return authorized && (tokenTTL == 0 || tokenTTL >= System.currentTimeMillis()); } @Override @@ -164,6 +166,7 @@ public class HTTPVaultConnector implements VaultConnector { public TokenResponse authToken(final String token) throws VaultConnectorException { /* set token */ this.token = token; + this.tokenTTL = 0; try { String response = requestPost(PATH_TOKEN_LOOKUP, new HashMap<>()); TokenResponse res = jsonMapper.readValue(response, TokenResponse.class); @@ -185,6 +188,7 @@ public class HTTPVaultConnector implements VaultConnector { AuthResponse upr = jsonMapper.readValue(response, AuthResponse.class); /* verify response */ this.token = upr.getAuth().getClientToken(); + this.tokenTTL = System.currentTimeMillis() + upr.getAuth().getLeaseDuration() * 1000L; this.authorized = true; return upr; } catch (IOException e) { @@ -204,6 +208,7 @@ public class HTTPVaultConnector implements VaultConnector { AuthResponse auth = jsonMapper.readValue(response, AuthResponse.class); /* verify response */ this.token = auth.getAuth().getClientToken(); + this.tokenTTL = System.currentTimeMillis() + auth.getAuth().getLeaseDuration() * 1000L; this.authorized = true; return auth; } catch (IOException e) { @@ -284,7 +289,7 @@ public class HTTPVaultConnector implements VaultConnector { * @param path URL path (relative to base) * @param payload Map of payload values (will be converted to JSON) * @return HTTP response - * @throws VaultConnectorException + * @throws VaultConnectorException on connection error */ private String requestPost(final String path, final Map payload) throws VaultConnectorException { /* Initialize post */ @@ -311,7 +316,7 @@ public class HTTPVaultConnector implements VaultConnector { * @param path URL path (relative to base) * @param payload Map of payload values (will be converted to JSON) * @return HTTP response - * @throws VaultConnectorException + * @throws VaultConnectorException on connection error */ private String requestPut(final String path, final Map payload) throws VaultConnectorException { /* Initialize post */ @@ -337,7 +342,7 @@ public class HTTPVaultConnector implements VaultConnector { * @param path URL path (relative to base) * @param payload Map of payload values (will be converted to JSON) * @return HTTP response - * @throws VaultConnectorException + * @throws VaultConnectorException on connection error */ private String requestGet(final String path, final Map payload) throws VaultConnectorException { /* Initialize post */ @@ -358,7 +363,7 @@ public class HTTPVaultConnector implements VaultConnector { * Execute prepared HTTP request and return result * @param base Prepares Request * @return HTTP response - * @throws VaultConnectorException + * @throws VaultConnectorException on connection error */ private String request(HttpRequestBase base) throws VaultConnectorException { /* Set JSON Header */ From a8afae70cc5dd58749eb60cbc0f0dd8ef10573db Mon Sep 17 00:00:00 2001 From: Stefan Kalscheuer Date: Sat, 13 Aug 2016 18:43:41 +0200 Subject: [PATCH 4/6] Removed Commons IO dependency Replaced deprecated HttpClient methods --- pom.xml | 5 -- .../jvault/connector/HTTPVaultConnector.java | 84 +++++++++++-------- 2 files changed, 49 insertions(+), 40 deletions(-) diff --git a/pom.xml b/pom.xml index 809881e..75df88e 100644 --- a/pom.xml +++ b/pom.xml @@ -24,11 +24,6 @@ jar - - commons-io - commons-io - 2.5 - org.apache.httpcomponents httpcore diff --git a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java index ba33e06..9f06fe0 100644 --- a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java +++ b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java @@ -6,21 +6,23 @@ import de.stklcode.jvault.connector.exception.*; import de.stklcode.jvault.connector.model.AuthBackend; import de.stklcode.jvault.connector.model.response.*; import de.stklcode.jvault.connector.model.response.embedded.AuthMethod; -import org.apache.commons.io.IOUtils; import org.apache.http.HttpResponse; -import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestBase; +import org.apache.http.client.utils.URIBuilder; import org.apache.http.entity.StringEntity; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpParams; -import org.apache.http.protocol.HTTP; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.util.EntityUtils; +import java.io.BufferedReader; import java.io.IOException; +import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; +import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.stream.Collectors; @@ -45,7 +47,6 @@ public class HTTPVaultConnector implements VaultConnector { private final ObjectMapper jsonMapper; - private final HttpClient httpClient; /* HTTP client for connection */ private final String baseURL; /* Base URL of Vault */ private boolean authorized = false; /* authorization status */ @@ -91,7 +92,6 @@ public class HTTPVaultConnector implements VaultConnector { */ public HTTPVaultConnector(String baseURL) { this.baseURL = baseURL; - this.httpClient = new DefaultHttpClient(); this.jsonMapper = new ObjectMapper(); } @@ -110,6 +110,9 @@ public class HTTPVaultConnector implements VaultConnector { } catch (VaultConnectorException | IOException e) { e.printStackTrace(); return null; + } catch (URISyntaxException ignored) { + /* this should never occur and may leak sensible information */ + return null; } } @@ -126,10 +129,10 @@ public class HTTPVaultConnector implements VaultConnector { @Override public SealResponse unseal(final String key, final Boolean reset) { - Map param = new HashMap<>(); + Map param = new HashMap<>(); param.put("key", key); if (reset != null) - param.put("reset", reset); + param.put("reset", reset.toString()); try { String response = requestPut(PATH_UNSEAL, param); return jsonMapper.readValue(response, SealResponse.class); @@ -159,6 +162,9 @@ public class HTTPVaultConnector implements VaultConnector { return amr.getSupportedMethods().stream().map(AuthMethod::getType).collect(Collectors.toList()); } catch (IOException e) { throw new InvalidResponseException("Unable to parse response", e); + } catch (URISyntaxException ignored) { + /* this should never occur and may leak sensible information */ + throw new InvalidRequestException("Invalid URI format."); } } @@ -255,6 +261,9 @@ public class HTTPVaultConnector implements VaultConnector { return jsonMapper.readValue(response, SecretResponse.class); } catch (IOException e) { throw new InvalidResponseException("Unable to parse response", e); + } catch (URISyntaxException ignored) { + /* this should never occur and may leak sensible information */ + throw new InvalidRequestException("Invalid URI format."); } } @@ -263,12 +272,15 @@ public class HTTPVaultConnector implements VaultConnector { if (!isAuthorized()) throw new AuthorizationRequiredException(); - String response = requestGet(PATH_SECRET + "/" + path + "/?list=true", new HashMap<>()); try { + String response = requestGet(PATH_SECRET + "/" + path + "/?list=true", new HashMap<>()); SecretListResponse secrets = jsonMapper.readValue(response, SecretListResponse.class); return secrets.getKeys(); } catch (IOException e) { throw new InvalidResponseException("Unable to parse response", e); + } catch (URISyntaxException ignored) { + /* this should never occur and may leak sensible information */ + throw new InvalidRequestException("Invalid URI format."); } } @@ -297,7 +309,7 @@ public class HTTPVaultConnector implements VaultConnector { /* generate JSON from payload */ StringEntity input; try { - input = new StringEntity(jsonMapper.writeValueAsString(payload), HTTP.UTF_8); + input = new StringEntity(jsonMapper.writeValueAsString(payload), StandardCharsets.UTF_8); } catch (JsonProcessingException e) { throw new InvalidRequestException("Unable to parse response", e); } @@ -318,7 +330,7 @@ public class HTTPVaultConnector implements VaultConnector { * @return HTTP response * @throws VaultConnectorException on connection error */ - private String requestPut(final String path, final Map payload) throws VaultConnectorException { + private String requestPut(final String path, final Map payload) throws VaultConnectorException { /* Initialize post */ HttpPut put = new HttpPut(baseURL + path); /* generate JSON from payload */ @@ -344,13 +356,13 @@ public class HTTPVaultConnector implements VaultConnector { * @return HTTP response * @throws VaultConnectorException on connection error */ - private String requestGet(final String path, final Map payload) throws VaultConnectorException { - /* Initialize post */ - HttpGet get = new HttpGet(baseURL + path); - /* Parse parameters */ - HttpParams params = new BasicHttpParams(); - payload.forEach(params::setParameter); - get.setParams(params); + private String requestGet(final String path, final Map payload) throws VaultConnectorException, URISyntaxException { + /* Add parameters to URI */ + URIBuilder uriBuilder = new URIBuilder(baseURL + path); + payload.forEach(uriBuilder::addParameter); + + /* Initialize request */ + HttpGet get = new HttpGet(uriBuilder.build()); /* Set X-Vault-Token header */ if (token != null) @@ -370,14 +382,17 @@ public class HTTPVaultConnector implements VaultConnector { base.addHeader("accept", "application/json"); HttpResponse response = null; - try { + try (CloseableHttpClient httpClient = HttpClientBuilder.create().build()) { response = httpClient.execute(base); /* Check if response is valid */ if (response == null) throw new InvalidResponseException("Response unavailable"); + switch (response.getStatusLine().getStatusCode()) { case 200: - return IOUtils.toString(response.getEntity().getContent()); + try(BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) { + return br.lines().collect(Collectors.joining("\n")); + } catch (IOException ignored) { } case 204: return ""; case 403: @@ -385,19 +400,18 @@ public class HTTPVaultConnector implements VaultConnector { default: InvalidResponseException ex = new InvalidResponseException("Invalid response code") .withStatusCode(response.getStatusLine().getStatusCode()); - try { - /* Try to parse error response */ - ErrorResponse er = jsonMapper.readValue(IOUtils.toString(response.getEntity().getContent()), - ErrorResponse.class); - /* Check for "permission denied" response */ - if (er.getErrors().size() > 0 && er.getErrors().get(0).equals("permission denied")) - throw new PermissionDeniedException(); - - throw ex.withResponse(er.toString()); - } - catch (IOException e) { - throw ex; + if (response.getEntity() != null) { + try (BufferedReader br = new BufferedReader(new InputStreamReader(response.getEntity().getContent()))) { + String responseString = br.lines().collect(Collectors.joining("\n")); + ErrorResponse er = jsonMapper.readValue(responseString, ErrorResponse.class); + /* Check for "permission denied" response */ + if (er.getErrors().size() > 0 && er.getErrors().get(0).equals("permission denied")) + throw new PermissionDeniedException(); + throw ex.withResponse(er.toString()); + } catch (IOException ignored) { + } } + throw ex; } } catch (IOException e) { throw new InvalidResponseException("Unable to read response", e); @@ -405,7 +419,7 @@ public class HTTPVaultConnector implements VaultConnector { finally { if (response != null && response.getEntity() != null) try { - response.getEntity().consumeContent(); + EntityUtils.consume(response.getEntity()); } catch (IOException ignored) { } } From 4c68e74a385cc3606118227c2ea192f22ab4b707 Mon Sep 17 00:00:00 2001 From: Stefan Kalscheuer Date: Thu, 1 Sep 2016 18:44:28 +0200 Subject: [PATCH 5/6] Minor dependency updates --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 75df88e..e4a6ce8 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ org.apache.maven.plugins maven-compiler-plugin - 3.3 + 3.5.1 1.8 1.8 From 847cce7bfb911c06852b50724d59929b800d20e9 Mon Sep 17 00:00:00 2001 From: Stefan Kalscheuer Date: Thu, 1 Sep 2016 20:26:14 +0200 Subject: [PATCH 6/6] Fixed AuthMethodResponse for Vault 0.6.1 compatibility --- README.md | 4 +-- pom.xml | 2 +- .../jvault/connector/HTTPVaultConnector.java | 2 +- .../model/response/AuthMethodsResponse.java | 35 ++++++++++++------- .../model/response/embedded/AuthMethod.java | 24 ++++++++----- 5 files changed, 41 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 0340035..f0265ce 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Java Vault Connector is a connector library for [Vault](https://www.vaultproject * Write secrets * List secrets * Connector Factory with builder pattern -* Tested against Vault 0.6.0 +* Tested against Vault 0.6.1 **Usage Example** @@ -38,7 +38,7 @@ String secret = vault.readSecret("some/secret/key").getValue(); de.stklcode.jvault connector - 0.1.1 + 0.2.0 ``` diff --git a/pom.xml b/pom.xml index e4a6ce8..48b0560 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ de.stklcode.jvault connector - 0.1.2-SNAPSHOT + 0.2.0-SNAPSHOT diff --git a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java index 9f06fe0..b64659b 100644 --- a/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java +++ b/src/main/java/de/stklcode/jvault/connector/HTTPVaultConnector.java @@ -159,7 +159,7 @@ public class HTTPVaultConnector implements VaultConnector { String response = requestGet(PATH_AUTH, new HashMap<>()); /* Parse response */ AuthMethodsResponse amr = jsonMapper.readValue(response, AuthMethodsResponse.class); - return amr.getSupportedMethods().stream().map(AuthMethod::getType).collect(Collectors.toList()); + return amr.getSupportedMethods().values().stream().map(AuthMethod::getType).collect(Collectors.toList()); } catch (IOException e) { throw new InvalidResponseException("Unable to parse response", e); } catch (URISyntaxException ignored) { diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/AuthMethodsResponse.java b/src/main/java/de/stklcode/jvault/connector/model/response/AuthMethodsResponse.java index 9f7b11a..425e4d2 100644 --- a/src/main/java/de/stklcode/jvault/connector/model/response/AuthMethodsResponse.java +++ b/src/main/java/de/stklcode/jvault/connector/model/response/AuthMethodsResponse.java @@ -1,11 +1,12 @@ package de.stklcode.jvault.connector.model.response; -import com.fasterxml.jackson.annotation.JsonAnySetter; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.databind.ObjectMapper; import de.stklcode.jvault.connector.exception.InvalidResponseException; import de.stklcode.jvault.connector.model.response.embedded.AuthMethod; -import java.util.ArrayList; -import java.util.List; +import java.io.IOException; +import java.util.HashMap; import java.util.Map; /** @@ -14,19 +15,27 @@ import java.util.Map; * @author Stefan Kalscheuer * @since 0.1 */ -public class AuthMethodsResponse implements VaultResponse { +@JsonIgnoreProperties(ignoreUnknown = true) +public class AuthMethodsResponse extends VaultDataResponse { + private Map supportedMethods; - private List supportedMethods; - - @JsonAnySetter - public void setMethod(String path, Map data) throws InvalidResponseException { - if (supportedMethods == null) - supportedMethods = new ArrayList<>(); - - supportedMethods.add(new AuthMethod(path, data.get("description"), data.get("type"))); + public AuthMethodsResponse() { + this.supportedMethods = new HashMap<>(); } - public List getSupportedMethods() { + @Override + public void setData(Map data) throws InvalidResponseException { + ObjectMapper mapper = new ObjectMapper(); + for (String path : data.keySet()) { + try { + this.supportedMethods.put(path, mapper.readValue(mapper.writeValueAsString(data.get(path)), AuthMethod.class)); + } catch (IOException e) { + throw new InvalidResponseException(); + } + } + } + + public Map getSupportedMethods() { return supportedMethods; } } diff --git a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthMethod.java b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthMethod.java index 663dcb1..89bbb37 100644 --- a/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthMethod.java +++ b/src/main/java/de/stklcode/jvault/connector/model/response/embedded/AuthMethod.java @@ -1,8 +1,11 @@ package de.stklcode.jvault.connector.model.response.embedded; - +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonSetter; import de.stklcode.jvault.connector.model.AuthBackend; +import java.util.Map; + /** * Embedded authentication method response. * @@ -12,12 +15,15 @@ import de.stklcode.jvault.connector.model.AuthBackend; public class AuthMethod { private AuthBackend type; private String rawType; - private String path; + + @JsonProperty("description") private String description; - public AuthMethod(String path, String description, String type) { - this.path = path; - this.description = description; + @JsonProperty("config") + private Map config; + + @JsonSetter("type") + public void setType(String type) { this.rawType = type; this.type = AuthBackend.forType(type); } @@ -30,11 +36,11 @@ public class AuthMethod { return rawType; } - public String getPath() { - return path; - } - public String getDescription() { return description; } + + public Map getConfig() { + return config; + } }