aboutsummaryrefslogtreecommitdiffstats
path: root/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java')
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java347
1 files changed, 347 insertions, 0 deletions
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java
new file mode 100644
index 000000000..6798026f3
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java
@@ -0,0 +1,347 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;
+
+import com.fasterxml.jackson.annotation.JsonGetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonSetter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Config {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Config.class);
+ private static final String DEFAULT_CONFIGFILENAME = "etc/oauth-provider.config.json";
+ private static final String ENVVARIABLE = "${";
+ private static final String REGEXENVVARIABLE = "(\\$\\{[A-Z0-9_-]+\\})";
+ private static final Pattern pattern = Pattern.compile(REGEXENVVARIABLE);
+ private static final String DEFAULT_TOKENISSUER = "Opendaylight";
+ private static final String DEFAULT_TOKENSECRET = generateSecret();
+ private static final String DEFAULT_REDIRECTURI = "/odlux/index.html#/oauth?token=";
+ private static final String DEFAULT_SUPPORTODLUSERS = "true";
+ public static final String TOKENALG_HS256 = "HS256";
+ public static final String TOKENALG_RS256 = "RS256";
+ public static final String TOKENALG_RS512 = "RS512";
+ private static final String CLIENTALG_PRE = "Client";
+ public static final String TOKENALG_CLIENT_RS256 = CLIENTALG_PRE + TOKENALG_RS256;
+ public static final String TOKENALG_CLIENT_RS512 = CLIENTALG_PRE + TOKENALG_RS512;
+ private static final String DEFAULT_TOKEN_ALGORITHM = TOKENALG_HS256;
+
+ private static final long DEFAULT_TOKEN_LIFETIME = 30 * 60;
+ private static final List<String> VALID_ALGORITHMS =
+ Arrays.asList(TOKENALG_HS256, TOKENALG_RS256, TOKENALG_RS512, TOKENALG_CLIENT_RS256, TOKENALG_CLIENT_RS512);
+ private static final List<String> VALID_ALGORITHMS_FOR_INTERNAL_LOGIN =
+ Arrays.asList(TOKENALG_HS256, TOKENALG_RS256, TOKENALG_RS512);
+ private static SecureRandom random;
+ private static Config _instance;
+
+ private List<OAuthProviderConfig> providers;
+ private String redirectUri;
+ private String supportOdlUsers;
+ private String tokenSecret;
+ private String tokenPubKey;
+ private String algorithm;
+ private String tokenIssuer;
+ private String publicUrl;
+ private long tokenLifetime;
+
+ @Override
+ public String toString() {
+ return "Config [providers=" + providers + ", redirectUri=" + redirectUri + ", supportOdlUsers="
+ + supportOdlUsers + ", tokenSecret=***, tokenPubKey=" + tokenPubKey + ", algorithm=" + algorithm
+ + ", tokenIssuer=" + tokenIssuer + ", publicUrl=" + publicUrl + ", tokenLifetime=" + tokenLifetime
+ + "]";
+ }
+
+ public List<OAuthProviderConfig> getProviders() {
+ return providers;
+ }
+
+ public void setProviders(List<OAuthProviderConfig> providers) {
+ this.providers = providers;
+ }
+
+ public String getRedirectUri() {
+ return redirectUri;
+ }
+
+ public void setRedirectUri(String redirectUri) {
+ this.redirectUri = redirectUri;
+ }
+
+ public String getSupportOdlUsers() {
+ return supportOdlUsers;
+ }
+
+ public void setSupportOdlUsers(String supportOdlUsers) {
+ this.supportOdlUsers = supportOdlUsers;
+ }
+
+ public String getTokenSecret() {
+ return tokenSecret;
+ }
+
+ public void setTokenSecret(String tokenSecret) {
+ this.tokenSecret = tokenSecret;
+ }
+
+ public String getAlgorithm() {
+ return this.algorithm;
+ }
+
+ public void setAlgorithm(String alg) {
+ this.algorithm = alg;
+ }
+
+ @JsonGetter("tokenPubKey")
+ public String getPublicKey() {
+ return this.tokenPubKey;
+ }
+
+ @JsonSetter("tokenPubKey")
+ public void setPublicKey(String pubKey) {
+ this.tokenPubKey = pubKey;
+ }
+
+ public String getTokenIssuer() {
+ return tokenIssuer;
+ }
+
+ public void setTokenIssuer(String tokenIssuer) {
+ this.tokenIssuer = tokenIssuer;
+ }
+
+ public String getPublicUrl() {
+ return publicUrl;
+ }
+
+ public void setPublicUrl(String publicUrl) {
+ this.publicUrl = publicUrl;
+ }
+
+ public long getTokenLifetime() {
+ return this.tokenLifetime;
+ }
+
+ public void setTokenLifetime(long lifetime) {
+ this.tokenLifetime = lifetime;
+ }
+
+ @JsonIgnore
+ private void handleEnvironmentVars() {
+ if (isEnvExpression(this.tokenIssuer)) {
+ this.tokenIssuer = getProperty(this.tokenIssuer, null);
+ }
+ if (isEnvExpression(this.tokenSecret)) {
+ this.tokenSecret = getProperty(this.tokenSecret, null);
+ }
+ if (isEnvExpression(this.tokenPubKey)) {
+ this.tokenPubKey = getProperty(this.tokenPubKey, null);
+ }
+ if (isEnvExpression(this.algorithm)) {
+ this.algorithm = getProperty(this.algorithm, null);
+ }
+ if (isEnvExpression(this.publicUrl)) {
+ this.publicUrl = getProperty(this.publicUrl, null);
+ }
+ if (isEnvExpression(this.redirectUri)) {
+ this.redirectUri = getProperty(this.redirectUri, null);
+ }
+ if (isEnvExpression(this.supportOdlUsers)) {
+ this.supportOdlUsers = getProperty(this.supportOdlUsers, null);
+ }
+ if (this.providers != null && !this.providers.isEmpty()) {
+ for (OAuthProviderConfig cfg : this.providers) {
+ cfg.handleEnvironmentVars();
+ }
+ }
+ }
+
+ @JsonIgnore
+ private void handleDefaultValues() {
+ if (this.tokenIssuer == null || this.tokenIssuer.isEmpty()) {
+ this.tokenIssuer = DEFAULT_TOKENISSUER;
+ }
+ if (this.algorithm == null || this.algorithm.isEmpty()) {
+ this.algorithm = DEFAULT_TOKEN_ALGORITHM;
+ }
+ if (TOKENALG_HS256.equals(this.algorithm) && (this.tokenSecret == null || this.tokenSecret.isEmpty())) {
+ this.tokenSecret = DEFAULT_TOKENSECRET;
+ }
+ if (this.redirectUri == null || this.redirectUri.isEmpty() || "null".equals(this.redirectUri)) {
+ this.redirectUri = DEFAULT_REDIRECTURI;
+ }
+ if (this.publicUrl != null && (this.publicUrl.isEmpty() || "null".equals(this.publicUrl))) {
+ this.publicUrl = null;
+ }
+ if (this.supportOdlUsers == null || this.supportOdlUsers.isEmpty()) {
+ this.supportOdlUsers = DEFAULT_SUPPORTODLUSERS;
+ }
+ if (this.tokenLifetime <= 0) {
+ this.tokenLifetime = DEFAULT_TOKEN_LIFETIME;
+ }
+ }
+
+ static boolean isEnvExpression(String key) {
+ return key != null && key.contains(ENVVARIABLE);
+ }
+
+ public static String generateSecret() {
+ return generateSecret(30);
+ }
+
+ public static String generateSecret(int targetStringLength) {
+ int leftLimit = 48; // numeral '0'
+ int rightLimit = 122; // letter 'z'
+ if (random == null) {
+ random = new SecureRandom();
+ }
+ String generatedString = random.ints(leftLimit, rightLimit + 1)
+ .filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97)).limit(targetStringLength)
+ .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();
+ return generatedString;
+ }
+
+ /**
+ *
+ * @param key environment var
+ * @param defValue default value if no env var found
+ * @return
+ */
+ public static String getProperty(final String key, final String defValue) {
+ String value = defValue;
+ //try to read env var
+ boolean found = false;
+ if (isEnvExpression(key)) {
+
+ LOG.info("try to find env var(s) for {}", key);
+ final Matcher matcher = pattern.matcher(key);
+ String tmp = new String(key);
+ while (matcher.find() && matcher.groupCount() > 0) {
+ final String mkey = matcher.group(1);
+ if (mkey != null) {
+ try {
+ LOG.info("match found for v={} and env key={}", key, mkey);
+ String envvar = mkey.substring(2, mkey.length() - 1);
+ String env = System.getenv(envvar);
+ tmp = tmp.replace(mkey, env == null ? "" : env);
+ if (env != null && !env.isEmpty()) {
+ found = true;
+ }
+ } catch (SecurityException e) {
+ LOG.warn("unable to read env {}: {}", key, e);
+ }
+ }
+ }
+ if (found) {
+ value = tmp;
+ }
+ }
+ return value;
+ }
+
+ public static boolean getPropertyBoolean(String key, boolean defaultValue) {
+ final String value = getProperty(key, String.valueOf(defaultValue));
+ return value.equals("true");
+ }
+
+ public static Config load(String filename) throws IOException, InvalidConfigurationException {
+ CustomObjectMapper mapper = new CustomObjectMapper();
+ File file = new File(filename);
+ if (!file.exists()) {
+ throw new FileNotFoundException();
+ }
+ String content = String.join("", Files.readAllLines(file.toPath()));
+ Config cfg = mapper.readValue(content, Config.class);
+ cfg.handleEnvironmentVars();
+ cfg.handleDefaultValues();
+ cfg.validate();
+ return cfg;
+ }
+
+
+ @JsonIgnore
+ private void validate() throws InvalidConfigurationException {
+ //verify that algorithm is supported
+ if (!VALID_ALGORITHMS.contains(this.algorithm)) {
+ throw new InvalidConfigurationException(String.format("Algorithm '%s' is not supported ", this.algorithm));
+ }
+ //verify that set values are matching the algorithm
+ //if hs256 check if secret is set
+ if (this.algorithm.startsWith("HS")) {
+ if (this.tokenSecret == null || this.tokenSecret.isBlank()) {
+ throw new InvalidConfigurationException(
+ String.format("There is no secret set for algorithm '%s'", this.algorithm));
+ }
+ }
+ //if rs256 or rs512 check if secret(private key) and pubkey are set
+ if (this.algorithm.startsWith("RS")) {
+ if (this.tokenSecret == null || this.tokenSecret.isBlank()) {
+ throw new InvalidConfigurationException(
+ String.format("There is no secret set for algorithm '%s'", this.algorithm));
+ }
+ if (this.tokenPubKey == null || this.tokenPubKey.isBlank()) {
+ throw new InvalidConfigurationException(
+ String.format("There is no public key for algorithm '%s'", this.algorithm));
+ }
+ }
+ //if client rs256 or client rs512 check if pubkey are set
+ if (this.algorithm.startsWith("Client")) {
+ if (this.tokenPubKey == null || this.tokenPubKey.isBlank()) {
+ throw new InvalidConfigurationException(
+ String.format("There is no public key for algorithm '%s'", this.algorithm));
+ }
+ }
+ }
+
+ @JsonIgnore
+ public boolean doSupportOdlUsers() {
+ return "true".equals(this.supportOdlUsers);
+ }
+
+
+ public static Config getInstance() throws IOException, InvalidConfigurationException {
+ return getInstance(DEFAULT_CONFIGFILENAME);
+ }
+
+ public static Config getInstance(String filename) throws IOException, InvalidConfigurationException {
+ if (_instance == null) {
+ _instance = load(filename);
+ }
+ return _instance;
+ }
+
+ public boolean loginActive() {
+ return VALID_ALGORITHMS_FOR_INTERNAL_LOGIN.contains(this.algorithm);
+ }
+
+
+}