add async auth method support 63/126863/2
authorMichael DÜrre <michael.duerre@highstreet-technologies.com>
Mon, 31 Jan 2022 12:42:48 +0000 (13:42 +0100)
committerKAPIL SINGAL <ks220y@att.com>
Tue, 1 Feb 2022 03:42:46 +0000 (03:42 +0000)
support async keys for oauth verification

Issue-ID: CCSDK-3577
Signed-off-by: Michael DÜrre <michael.duerre@highstreet-technologies.com>
Change-Id: I7d84bc04462fc9c2edd3390267a7dcc21bc7355b
Signed-off-by: Michael DÜrre <michael.duerre@highstreet-technologies.com>
31 files changed:
sdnr/wt/oauth-provider/provider-jar/pom.xml
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/OAuth2Realm.java
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/InvalidConfigurationException.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthToken.java
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/UserTokenPayload.java
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/filters/AnyRoleHttpAuthenticationFilter.java
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/AuthHttpServlet.java
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/AuthService.java
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/GitlabProviderService.java
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/KeycloakProviderService.java
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/MdSalAuthorizationStore.java
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/NextcloudProviderService.java
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/PemUtils.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/RSAKeyReader.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/TokenCreator.java
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestAuthHttpServlet.java
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestConfig.java
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestDeserializer.java
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestGitlabAuthService.java
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestKeycloakAuthService.java
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRSAAlgorithms.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRealm.java
sdnr/wt/oauth-provider/provider-jar/src/test/resources/jwtRS256.key [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/jwtRS256.key.pub [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/jwtRS512.key [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/jwtRS512.key.pub [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/test.config.json
sdnr/wt/oauth-provider/provider-jar/src/test/resources/test.configRS256-invalid.json [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/test.configRS256.json [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/test.configRS512.json [new file with mode: 0644]

index d4e3113..24b07bb 100644 (file)
             <groupId>com.auth0</groupId>
             <artifactId>java-jwt</artifactId>
         </dependency>
+        <dependency>
+           <groupId>org.bouncycastle</groupId>
+           <artifactId>bcprov-jdk15on</artifactId>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.aaa</groupId>
             <artifactId>aaa-shiro</artifactId>
             <exclusions>
-<!--                 <exclusion> -->
-<!--                     <groupId>org.opendaylight.aaa</groupId> -->
-<!--                     <artifactId>aaa-shiro-api</artifactId> -->
-<!--                 </exclusion> -->
                 <exclusion>
                     <groupId>org.opendaylight.aaa</groupId>
                     <artifactId>aaa-cert</artifactId>
                     <groupId>ehcache-root</groupId>
                     <artifactId>ehcache</artifactId>
                 </exclusion>
-<!--                 <exclusion> -->
-<!--                     <groupId>org.jolokia</groupId> -->
-<!--                     <artifactId>jolokia-osgi</artifactId> -->
-<!--                 </exclusion> -->
             </exclusions>
         </dependency>
         <dependency>
index 6dbed1f..908b91d 100644 (file)
@@ -26,15 +26,16 @@ import java.io.IOException;
 import org.apache.shiro.authc.AuthenticationException;
 import org.apache.shiro.authc.AuthenticationInfo;
 import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.BearerToken;
 import org.apache.shiro.authc.SimpleAuthenticationInfo;
 import org.apache.shiro.authc.UsernamePasswordToken;
 import org.apache.shiro.authz.AuthorizationInfo;
 import org.apache.shiro.authz.SimpleAuthorizationInfo;
 import org.apache.shiro.subject.PrincipalCollection;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.InvalidConfigurationException;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
 import org.opendaylight.aaa.api.shiro.principal.ODLPrincipal;
-import org.apache.shiro.authc.BearerToken;
 import org.opendaylight.aaa.shiro.realm.TokenAuthRealm;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -46,7 +47,7 @@ public class OAuth2Realm extends TokenAuthRealm {
     private final TokenCreator tokenCreator;
     private final Config config;
 
-    public OAuth2Realm() throws IOException {
+    public OAuth2Realm() throws IllegalArgumentException, IOException, InvalidConfigurationException {
         super();
         super.setName(REALM_NAME);
         this.config = Config.getInstance();
index 3ebc144..6798026 100644 (file)
  */
 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.Random;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.slf4j.Logger;
@@ -44,25 +47,40 @@ public class Config {
     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";
-    private static Random random;
+    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=" + tokenSecret + ", tokenIssuer=" + tokenIssuer + "]";
+                + supportOdlUsers + ", tokenSecret=***, tokenPubKey=" + tokenPubKey + ", algorithm=" + algorithm
+                + ", tokenIssuer=" + tokenIssuer + ", publicUrl=" + publicUrl + ", tokenLifetime=" + tokenLifetime
+                + "]";
     }
 
-
-
     public List<OAuthProviderConfig> getProviders() {
         return providers;
     }
@@ -95,6 +113,24 @@ public class Config {
         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;
     }
@@ -103,7 +139,6 @@ public class Config {
         this.tokenIssuer = tokenIssuer;
     }
 
-
     public String getPublicUrl() {
         return publicUrl;
     }
@@ -112,25 +147,39 @@ public class Config {
         this.publicUrl = publicUrl;
     }
 
+    public long getTokenLifetime() {
+        return this.tokenLifetime;
+    }
+
+    public void setTokenLifetime(long lifetime) {
+        this.tokenLifetime = lifetime;
+    }
+
     @JsonIgnore
     private void handleEnvironmentVars() {
-        if (isEnvExpression(tokenIssuer)) {
-            this.tokenIssuer = getProperty(tokenIssuer, null);
+        if (isEnvExpression(this.tokenIssuer)) {
+            this.tokenIssuer = getProperty(this.tokenIssuer, null);
+        }
+        if (isEnvExpression(this.tokenSecret)) {
+            this.tokenSecret = getProperty(this.tokenSecret, null);
         }
-        if (isEnvExpression(tokenSecret)) {
-            this.tokenSecret = getProperty(tokenSecret, null);
+        if (isEnvExpression(this.tokenPubKey)) {
+            this.tokenPubKey = getProperty(this.tokenPubKey, null);
         }
-        if (isEnvExpression(publicUrl)) {
-            this.publicUrl = getProperty(publicUrl, null);
+        if (isEnvExpression(this.algorithm)) {
+            this.algorithm = getProperty(this.algorithm, null);
         }
-        if (isEnvExpression(redirectUri)) {
-            this.redirectUri = getProperty(redirectUri, null);
+        if (isEnvExpression(this.publicUrl)) {
+            this.publicUrl = getProperty(this.publicUrl, null);
         }
-        if (isEnvExpression(supportOdlUsers)) {
-            this.supportOdlUsers = getProperty(supportOdlUsers, 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) {
+            for (OAuthProviderConfig cfg : this.providers) {
                 cfg.handleEnvironmentVars();
             }
         }
@@ -138,21 +187,27 @@ public class Config {
 
     @JsonIgnore
     private void handleDefaultValues() {
-        if (tokenIssuer == null || tokenIssuer.isEmpty()) {
+        if (this.tokenIssuer == null || this.tokenIssuer.isEmpty()) {
             this.tokenIssuer = DEFAULT_TOKENISSUER;
         }
-        if (tokenSecret == null || tokenSecret.isEmpty()) {
+        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 (redirectUri == null || redirectUri.isEmpty() || "null".equals(redirectUri)) {
+        if (this.redirectUri == null || this.redirectUri.isEmpty() || "null".equals(this.redirectUri)) {
             this.redirectUri = DEFAULT_REDIRECTURI;
         }
-        if (publicUrl != null && (publicUrl.isEmpty() || "null".equals(publicUrl))) {
+        if (this.publicUrl != null && (this.publicUrl.isEmpty() || "null".equals(this.publicUrl))) {
             this.publicUrl = null;
         }
-        if (supportOdlUsers == null || supportOdlUsers.isEmpty()) {
+        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) {
@@ -166,8 +221,8 @@ public class Config {
     public static String generateSecret(int targetStringLength) {
         int leftLimit = 48; // numeral '0'
         int rightLimit = 122; // letter 'z'
-        if(random==null) {
-            random = new Random();
+        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)
@@ -198,7 +253,7 @@ public class Config {
                         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()) {
+                        if (env != null && !env.isEmpty()) {
                             found = true;
                         }
                     } catch (SecurityException e) {
@@ -218,7 +273,7 @@ public class Config {
         return value.equals("true");
     }
 
-    public static Config load(String filename) throws IOException {
+    public static Config load(String filename) throws IOException, InvalidConfigurationException {
         CustomObjectMapper mapper = new CustomObjectMapper();
         File file = new File(filename);
         if (!file.exists()) {
@@ -228,26 +283,65 @@ public class Config {
         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 {
+    public static Config getInstance() throws IOException, InvalidConfigurationException {
         return getInstance(DEFAULT_CONFIGFILENAME);
     }
 
-    public static Config getInstance(String filename) throws IOException {
+    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);
+    }
+
 
 }
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/InvalidConfigurationException.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/InvalidConfigurationException.java
new file mode 100644 (file)
index 0000000..a0e97de
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * ============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;
+
+public class InvalidConfigurationException extends Exception {
+
+    public InvalidConfigurationException(String str) {
+        super(str);
+    }
+
+    private static final long serialVersionUID = 1L;
+
+}
index b05d394..825286d 100644 (file)
@@ -25,16 +25,19 @@ import com.auth0.jwt.JWT;
 import com.auth0.jwt.interfaces.DecodedJWT;
 import org.apache.shiro.authc.BearerToken;
 
+
 public class OAuthToken {
     private final String access_token;
     private final String token_type;
     private final long expires_at;
+    private final long issued_at;
 
     public OAuthToken(BearerToken btoken) {
         this.access_token = btoken.getToken();
         this.token_type = "Bearer";
         DecodedJWT token = JWT.decode(this.access_token);
         this.expires_at = token.getExpiresAt().getTime() / 1000L;
+        this.issued_at = token.getIssuedAt().getTime() / 1000L;
     }
 
     public String getAccess_token() {
@@ -48,5 +51,8 @@ public class OAuthToken {
     public long getExpires_at() {
         return expires_at;
     }
+    public long getIssued_at() {
+        return issued_at;
+    }
 
 }
index 229cdbf..a983dd6 100644 (file)
@@ -30,11 +30,17 @@ public class UserTokenPayload {
     private String givenName;
     private String familyName;
     private long exp;
+    private long iat;
+
 
     public long getExp() {
         return exp;
     }
 
+    public long getIat() {
+        return this.iat;
+    }
+
     public void setPreferredUsername(String preferredUsername) {
         this.preferredUsername = preferredUsername;
     }
@@ -51,6 +57,10 @@ public class UserTokenPayload {
         this.exp = exp;
     }
 
+    public void setIat(long iat) {
+        this.iat = iat;
+    }
+
     public String getPreferredUsername() {
         return preferredUsername;
     }
index 686684f..96faccb 100644 (file)
@@ -39,12 +39,14 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.apache.shiro.SecurityUtils;
 import org.apache.shiro.ShiroException;
+import org.apache.shiro.authc.BearerToken;
 import org.apache.shiro.codec.Base64;
 import org.apache.shiro.session.Session;
 import org.apache.shiro.subject.Subject;
 import org.jolokia.osgi.security.Authenticator;
 import org.onap.ccsdk.features.sdnr.wt.common.http.BaseHTTPClient;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.InvalidConfigurationException;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.NoDefinitionFoundException;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthProviderConfig;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthToken;
@@ -56,7 +58,6 @@ import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.MdSalAuthorizatio
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.OAuthProviderFactory;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
 import org.opendaylight.aaa.api.IdMService;
-import org.apache.shiro.authc.BearerToken;
 import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfiguration;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.shiro.configuration.Main;
@@ -101,7 +102,7 @@ public class AuthHttpServlet extends HttpServlet {
     private static ShiroConfiguration shiroConfiguration;
     private static MdSalAuthorizationStore mdsalAuthStore;
 
-    public AuthHttpServlet() throws IOException {
+    public AuthHttpServlet() throws IllegalArgumentException, IOException, InvalidConfigurationException {
         this.config = Config.getInstance();
         this.tokenCreator = TokenCreator.getInstance(this.config);
         this.mapper = new ObjectMapper();
@@ -300,7 +301,7 @@ public class AuthHttpServlet extends HttpServlet {
 
     private UserTokenPayload getUserInfo(HttpServletRequest req) {
         if (isBearer(req)) {
-            UserTokenPayload data = TokenCreator.getInstance(this.config).decode(req);
+            UserTokenPayload data = this.tokenCreator.decode(req);
             if (data != null) {
                 return data;
             }
@@ -414,7 +415,7 @@ public class AuthHttpServlet extends HttpServlet {
     protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
 
         LOG.debug("POST request for {}", req.getRequestURI());
-        if (this.config.doSupportOdlUsers() && LOGINURI.equals(req.getRequestURI())) {
+        if (this.config.loginActive() &&  this.config.doSupportOdlUsers() && LOGINURI.equals(req.getRequestURI())) {
             final String username = req.getParameter("username");
             final String domain = req.getParameter("domain");
             BearerToken token =
@@ -443,6 +444,7 @@ public class AuthHttpServlet extends HttpServlet {
             data.setPreferredUsername(username);
             data.setFamilyName("");
             data.setGivenName(username);
+            data.setIat(this.tokenCreator.getDefaultIat());
             data.setExp(this.tokenCreator.getDefaultExp());
             data.setRoles(roles);
             return this.tokenCreator.createNewJWT(data);
index f16975f..bb0857a 100644 (file)
@@ -41,13 +41,13 @@ import java.util.stream.Collectors;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import org.apache.shiro.authc.BearerToken;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthProviderConfig;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthResponseData;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.AuthHttpServlet;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.client.MappedBaseHttpResponse;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.client.MappingBaseHttpClient;
-import org.apache.shiro.authc.BearerToken;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -74,7 +74,7 @@ public abstract class AuthService {
 
     protected abstract String getLoginUrl(String callbackUrl);
 
-    protected abstract UserTokenPayload requestUserRoles(String access_token, long expires_at);
+    protected abstract UserTokenPayload requestUserRoles(String access_token, long issued_at, long expires_at);
 
     protected abstract boolean verifyState(String state);
 
@@ -128,7 +128,8 @@ public abstract class AuthService {
             if (this.doSeperateRolesRequest()) {
                 //long expiresAt = this.tokenCreator.getDefaultExp(Math.round(response.getExpires_in()));
                 long expiresAt = this.tokenCreator.getDefaultExp();
-                UserTokenPayload data = this.requestUserRoles(response.getAccess_token(), expiresAt);
+                long issuedAt = this.tokenCreator.getDefaultIat();
+                UserTokenPayload data = this.requestUserRoles(response.getAccess_token(), issuedAt, expiresAt);
                 if (data != null) {
                     this.handleUserInfoToken(data, resp, host);
                 } else {
index 4a8bdfa..1111603 100644 (file)
@@ -95,7 +95,7 @@ public class GitlabProviderService extends AuthService {
     }
 
     @Override
-    protected UserTokenPayload requestUserRoles(String access_token, long expires_at) {
+    protected UserTokenPayload requestUserRoles(String access_token, long issued_at, long expires_at) {
         LOG.info("reqesting user roles with token={}", access_token);
         Map<String, String> authHeaders = new HashMap<>();
         authHeaders.put("Authorization", String.format("Bearer %s", access_token));
@@ -116,6 +116,7 @@ public class GitlabProviderService extends AuthService {
         data.setPreferredUsername(uInfo.getUsername());
         data.setGivenName(uInfo.getName());
         data.setFamilyName(uInfo.getName());
+        data.setIat(issued_at);
         data.setExp(expires_at);
         List<String> roles = new ArrayList<>();
         GitlabGroupInfo[] uRoles = groupInfos.get().body;
index c226a14..dbc5776 100644 (file)
@@ -84,6 +84,7 @@ public class KeycloakProviderService extends AuthService {
     protected UserTokenPayload mapAccessToken(String spayload) throws JsonMappingException, JsonProcessingException {
         KeycloakUserTokenPayload payload = mapper.readValue(spayload, KeycloakUserTokenPayload.class);
         UserTokenPayload data = new UserTokenPayload();
+        data.setIat(payload.getIat() * 1000L);
         data.setExp(payload.getExp() * 1000L);
         data.setFamilyName(payload.getFamilyName());
         data.setGivenName(payload.getGivenName());
@@ -93,7 +94,7 @@ public class KeycloakProviderService extends AuthService {
     }
 
     @Override
-    protected UserTokenPayload requestUserRoles(String access_token, long expires_at) {
+    protected UserTokenPayload requestUserRoles(String access_token, long issued_at, long expires_at) {
         return null;
     }
 
index 293fe33..ca7f471 100644 (file)
@@ -50,7 +50,9 @@ public class MdSalAuthorizationStore {
     public Optional<OdlPolicy> getPolicy(String path, List<String> userRoles) {
         InstanceIdentifier<Policies> iif = InstanceIdentifier.create(HttpAuthorization.class).child(Policies.class);
         Optional<Policies> odata = Optional.empty();
-        try (ReadTransaction transaction = this.dataBroker.newReadOnlyTransaction()) {
+        // The implicite close is not handled correctly by underlaying opendaylight netconf service
+        ReadTransaction transaction = this.dataBroker.newReadOnlyTransaction();
+        try {
             odata = transaction.read(LogicalDatastoreType.CONFIGURATION, iif).get();
         } catch (ExecutionException e) {
             LOG.warn("unable to read policies from mdsal: ", e);
index 03b0f4f..b6f045c 100644 (file)
@@ -71,7 +71,7 @@ public class NextcloudProviderService extends AuthService {
     }
 
     @Override
-    protected UserTokenPayload requestUserRoles(String access_token, long expires_at) {
+    protected UserTokenPayload requestUserRoles(String access_token, long issued_at, long expires_at) {
         // TODO Auto-generated method stub
         return null;
     }
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/PemUtils.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/PemUtils.java
new file mode 100644 (file)
index 0000000..fac46f6
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * ============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.providers;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import org.bouncycastle.util.io.pem.PemObject;
+import org.bouncycastle.util.io.pem.PemReader;
+
+public class PemUtils {
+
+    private static byte[] parsePEMFile(File pemFile) throws IOException {
+        if (!pemFile.isFile() || !pemFile.exists()) {
+            throw new FileNotFoundException(String.format("The file '%s' doesn't exist.", pemFile.getAbsolutePath()));
+        }
+        return parsePEMFile(new FileReader(pemFile));
+    }
+    private static byte[] parsePEMFile(Reader inputReader) throws IOException {
+        PemReader reader = new PemReader(inputReader);
+        PemObject pemObject = reader.readPemObject();
+        byte[] content = pemObject.getContent();
+        reader.close();
+        return content;
+    }
+    private static PublicKey getPublicKey(byte[] keyBytes, String algorithm) {
+        PublicKey publicKey = null;
+        try {
+            KeyFactory kf = KeyFactory.getInstance(algorithm);
+            EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
+            publicKey = kf.generatePublic(keySpec);
+        } catch (NoSuchAlgorithmException e) {
+            System.out.println("Could not reconstruct the public key, the given algorithm could not be found.");
+        } catch (InvalidKeySpecException e) {
+            System.out.println("Could not reconstruct the public key");
+        }
+
+        return publicKey;
+    }
+
+    private static PrivateKey getPrivateKey(byte[] keyBytes, String algorithm) {
+        PrivateKey privateKey = null;
+        try {
+            KeyFactory kf = KeyFactory.getInstance(algorithm);
+            EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
+            privateKey = kf.generatePrivate(keySpec);
+        } catch (NoSuchAlgorithmException e) {
+            System.out.println("Could not reconstruct the private key, the given algorithm could not be found.");
+        } catch (InvalidKeySpecException e) {
+            System.out.println("Could not reconstruct the private key");
+        }
+
+        return privateKey;
+    }
+
+    public static PublicKey readPublicKeyFromFile(String filepath, String algorithm) throws IOException {
+        byte[] bytes = PemUtils.parsePEMFile(new File(filepath));
+        return PemUtils.getPublicKey(bytes, algorithm);
+    }
+
+    public static PublicKey readPublicKey(String filecontent, String algorithm) throws IOException {
+        byte[] bytes = PemUtils.parsePEMFile(new StringReader(filecontent));
+        return PemUtils.getPublicKey(bytes, algorithm);
+    }
+
+    public static PrivateKey readPrivateKeyFromFile(String filepath, String algorithm) throws IOException {
+        byte[] bytes = PemUtils.parsePEMFile(new File(filepath));
+        return PemUtils.getPrivateKey(bytes, algorithm);
+    }
+
+    public static PrivateKey readPrivateKey(String filecontent, String algorithm) throws IOException {
+        byte[] bytes = PemUtils.parsePEMFile(new StringReader(filecontent));
+        return PemUtils.getPrivateKey(bytes, algorithm);
+    }
+
+}
\ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/RSAKeyReader.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/RSAKeyReader.java
new file mode 100644 (file)
index 0000000..028dff9
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * ============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.providers;
+
+import java.io.IOException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+public class RSAKeyReader {
+
+    private static final String PREFIX_FILEURL = "file://";
+
+    public static RSAPrivateKey getPrivateKey(String filenameOrContent) throws IOException {
+        if (filenameOrContent.startsWith(PREFIX_FILEURL)) {
+            return (RSAPrivateKey) PemUtils.readPrivateKeyFromFile(filenameOrContent.substring(PREFIX_FILEURL.length()),
+                    "RSA");
+        }
+        return (RSAPrivateKey) PemUtils.readPrivateKey(filenameOrContent, "RSA");
+    }
+
+    public static RSAPublicKey getPublicKey(String filenameOrContent) throws IOException {
+        if (filenameOrContent.startsWith(PREFIX_FILEURL)) {
+            return (RSAPublicKey) PemUtils.readPublicKeyFromFile(filenameOrContent.substring(PREFIX_FILEURL.length()),
+                    "RSA");
+        }
+        return (RSAPublicKey) PemUtils.readPublicKey(filenameOrContent, "RSA");
+    }
+}
index c2515e2..238f888 100644 (file)
@@ -27,56 +27,96 @@ import com.auth0.jwt.exceptions.JWTDecodeException;
 import com.auth0.jwt.exceptions.JWTVerificationException;
 import com.auth0.jwt.interfaces.DecodedJWT;
 import com.auth0.jwt.interfaces.JWTVerifier;
+import java.io.IOException;
+import java.security.Security;
 import java.util.Arrays;
 import java.util.Date;
 import javax.servlet.http.HttpServletRequest;
+import org.apache.shiro.authc.BearerToken;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.AuthHttpServlet;
-import org.apache.shiro.authc.BearerToken;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 public class TokenCreator {
 
     private static final Logger LOG = LoggerFactory.getLogger(AuthHttpServlet.class.getName());
-    private static final long DEFAULT_TOKEN_LIFETIME_MS = 30 * 60 * 1000L;
     private final String issuer;
     private static TokenCreator _instance;
-    private final String secret;
+    private final long tokenLifetimeSeconds;
+    private final Algorithm algorithm;
 
     private static final String ROLES_CLAIM = "roles";
     private static final String FAMILYNAME_CLAIM = "family_name";
     private static final String NAME_CLAIM = "name";
 
-    public static TokenCreator getInstance(Config config) {
+    static {
+        Security.addProvider(
+                new BouncyCastleProvider()
+       );
+    }
+    public static TokenCreator getInstance(Config config) throws IllegalArgumentException, IOException {
         if (_instance == null) {
             _instance = new TokenCreator(config);
         }
         return _instance;
     }
-    public static TokenCreator getInstance(String secret, String issuer) {
+
+    public static TokenCreator getInstance(String alg, String secret, String issuer, long tokenLifetime)
+            throws IllegalArgumentException, IOException {
+        return getInstance(alg, secret, null, issuer, tokenLifetime);
+    }
+
+    public static TokenCreator getInstance(String alg, String secret, String pubkey, String issuer, long tokenLifetime)
+            throws IllegalArgumentException, IOException {
         if (_instance == null) {
-            _instance = new TokenCreator(secret, issuer);
+            _instance = new TokenCreator(alg, secret, pubkey, issuer, tokenLifetime);
         }
         return _instance;
     }
 
-    private TokenCreator(Config config) {
-        this(config.getTokenSecret(),config.getTokenIssuer());
+    private TokenCreator(Config config) throws IllegalArgumentException, IOException {
+        this(config.getAlgorithm(), config.getTokenSecret(), config.getPublicKey(), config.getTokenIssuer(),
+                config.getTokenLifetime());
     }
-    private TokenCreator(String secret, String issuer) {
-        this.secret = secret;
+
+    private TokenCreator(String alg, String secret, String pubkey, String issuer, long tokenLifetime)
+            throws IllegalArgumentException, IOException {
         this.issuer = issuer;
+        this.tokenLifetimeSeconds = tokenLifetime;
+        this.algorithm = this.createAlgorithm(alg, secret, pubkey);
+    }
+
+    private Algorithm createAlgorithm(String alg, String secret, String pubkey)
+            throws IllegalArgumentException, IOException {
+        if(alg==null) {
+            alg = Config.TOKENALG_HS256;
+        }
+        switch (alg) {
+            case Config.TOKENALG_HS256:
+                return Algorithm.HMAC256(secret);
+            case Config.TOKENALG_RS256:
+                return Algorithm.RSA256(RSAKeyReader.getPublicKey(pubkey), RSAKeyReader.getPrivateKey(secret));
+            case Config.TOKENALG_RS512:
+                return Algorithm.RSA512(RSAKeyReader.getPublicKey(pubkey), RSAKeyReader.getPrivateKey(secret));
+            case Config.TOKENALG_CLIENT_RS256:
+                return Algorithm.RSA256(RSAKeyReader.getPublicKey(pubkey), null);
+            case Config.TOKENALG_CLIENT_RS512:
+                return Algorithm.RSA512(RSAKeyReader.getPublicKey(pubkey), null);
+        }
+        throw new IllegalArgumentException(String.format("unable to find algorithm for %s", alg));
+
     }
 
     public BearerToken createNewJWT(UserTokenPayload data) {
-        Algorithm algorithm = Algorithm.HMAC256(secret);
         final String token = JWT.create().withIssuer(issuer).withExpiresAt(new Date(data.getExp()))
-                .withSubject(data.getPreferredUsername()).withClaim(NAME_CLAIM, data.getGivenName())
-                .withClaim(FAMILYNAME_CLAIM, data.getFamilyName())
+                .withIssuedAt(new Date(data.getIat())).withSubject(data.getPreferredUsername())
+                .withClaim(NAME_CLAIM, data.getGivenName()).withClaim(FAMILYNAME_CLAIM, data.getFamilyName())
                 .withArrayClaim(ROLES_CLAIM, data.getRoles().toArray(new String[data.getRoles().size()]))
-                .sign(algorithm);
+                .sign(this.algorithm);
+        LOG.trace("token created: {}", token);
         return new BearerToken(token);
     }
 
@@ -84,8 +124,7 @@ public class TokenCreator {
         DecodedJWT jwt = null;
         LOG.debug("try to verify token {}", token);
         try {
-            Algorithm algorithm = Algorithm.HMAC256(secret);
-            JWTVerifier verifier = JWT.require(algorithm).withIssuer(issuer).build();
+            JWTVerifier verifier = JWT.require(this.algorithm).withIssuer(issuer).build();
             jwt = verifier.verify(token);
 
         } catch (JWTVerificationException e) {
@@ -95,13 +134,17 @@ public class TokenCreator {
     }
 
     public long getDefaultExp() {
-        return new Date().getTime() + DEFAULT_TOKEN_LIFETIME_MS;
+        return new Date().getTime() + (this.tokenLifetimeSeconds * 1000);
     }
 
     public long getDefaultExp(long expIn) {
         return new Date().getTime() + expIn;
     }
 
+    public long getDefaultIat() {
+        return new Date().getTime();
+    }
+
     public UserTokenPayload decode(HttpServletRequest req) throws JWTDecodeException {
         final String authHeader = req.getHeader("Authorization");
         if (authHeader == null || !authHeader.startsWith("Bearer")) {
@@ -117,4 +160,5 @@ public class TokenCreator {
 
         return data;
     }
+
 }
index 1fbe43a..ab6dc4e 100644 (file)
@@ -41,6 +41,7 @@ import java.util.Optional;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import org.apache.shiro.authc.BearerToken;
 import org.jolokia.osgi.security.Authenticator;
 import org.json.JSONArray;
 import org.junit.BeforeClass;
@@ -49,6 +50,7 @@ import org.onap.ccsdk.features.sdnr.wt.common.http.BaseHTTPClient;
 import org.onap.ccsdk.features.sdnr.wt.common.test.ServletOutputStreamToByteArrayOutputStream;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.CustomObjectMapper;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.InvalidConfigurationException;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlPolicy;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.AuthHttpServlet;
@@ -57,7 +59,6 @@ import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.test.helper.OdlJsonMapper;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.test.helper.OdlXmlMapper;
 import org.opendaylight.aaa.api.IdMService;
-import org.apache.shiro.authc.BearerToken;
 import org.opendaylight.mdsal.binding.api.DataBroker;
 import org.opendaylight.mdsal.binding.api.ReadTransaction;
 import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
@@ -84,14 +85,15 @@ public class TestAuthHttpServlet {
 //            Map.of("Authorization", BaseHTTPClient.getAuthorizationHeaderValue("admin@sdn", "admin")));
 
     @BeforeClass
-    public static void init() {
+    public static void init() throws IllegalArgumentException, Exception {
 
         try {
             Config config = createConfigFile();
             tokenCreator = TokenCreator.getInstance(config);
             servlet = new TestServlet();
             shiroConfiguration = loadShiroConfig(TESTSHIROCONFIGFILE);
-        } catch (IOException e) {
+        } catch (IOException | InvalidConfigurationException e) {
+            e.printStackTrace();
             fail(e.getMessage());
         }
         servlet.setDataBroker(dataBroker);
@@ -124,7 +126,7 @@ public class TestAuthHttpServlet {
         return mapper.readValue(new File(filename), ShiroConfigurationBuilder.class).build();
     }
 
-    private static Config createConfigFile() throws IOException {
+    private static Config createConfigFile() throws IOException, InvalidConfigurationException {
         return Config.getInstance(TESTCONFIGFILE);
 
     }
@@ -351,7 +353,7 @@ public class TestAuthHttpServlet {
 
         private static final long serialVersionUID = 1L;
 
-        public TestServlet() throws IOException {
+        public TestServlet() throws IllegalArgumentException, Exception {
             super();
         }
 
index d07950d..80ae8cf 100644 (file)
  */
 package org.onap.ccsdk.features.sdnr.wt.oauthprovider.test;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import java.io.IOException;
 import org.junit.Test;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.InvalidConfigurationException;
 
 public class TestConfig {
 
     public static String TEST_CONFIG_FILENAME = "src/test/resources/test.config.json";
     public static String TEST_OOMCONFIG_FILENAME = "src/test/resources/oom.test.config.json";
+    public static String TEST_RS256_FILENAME = "src/test/resources/test.configRS256.json";
+    public static String TEST_RS256INVALID_FILENAME = "src/test/resources/test.configRS256-invalid.json";
+    public static String TEST_RS512_FILENAME = "src/test/resources/test.configRS512.json";
+
+
     @Test
-    public void test() throws IOException {
+    public void test() throws IOException, InvalidConfigurationException {
 
         Config config = Config.load(TEST_CONFIG_FILENAME);
         System.out.println("config="+config);
+        assertEquals(60*60,config.getTokenLifetime());
+        assertNotNull(config.getAlgorithm());
+        assertNotNull(config.getTokenSecret());
+        //assertNotNull(config.getPublicKey());
+        assertEquals(Config.TOKENALG_HS256, config.getAlgorithm());
     }
     @Test
-    public void testOom() throws IOException {
+    public void testOom() throws IOException, InvalidConfigurationException {
 
         Config config = Config.load(TEST_OOMCONFIG_FILENAME);
         System.out.println("config="+config);
+        assertEquals(30*60,config.getTokenLifetime());
+
+    }
+    @Test
+    public void testRS256() throws IOException, InvalidConfigurationException {
+
+        Config config = Config.load(TEST_RS256_FILENAME);
+        System.out.println("config="+config);
+        assertEquals(60*60,config.getTokenLifetime());
+
+    }
+    @Test
+    public void testRS512() throws IOException, InvalidConfigurationException {
+
+        Config config = Config.load(TEST_RS512_FILENAME);
+        System.out.println("config="+config);
+        assertEquals(60*60,config.getTokenLifetime());
+
+    }
+    @Test(expected = InvalidConfigurationException.class)
+    public void testRS256Invalid() throws IOException, InvalidConfigurationException {
 
+        Config.load(TEST_RS256INVALID_FILENAME);
     }
 }
index 65ef2cb..421b619 100644 (file)
@@ -40,8 +40,6 @@ public class TestDeserializer {
         final String token = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ1OHNXaTF4QWxjT1pyelY4X0l2VjliMlJTaFdZUWV4aXZYUXNYLTFTME"
                 + "RNIn0.eyJleHAiOjE2MTAzNjE2OTQsImlhdCI6MTYxMDM2MTM5NCwianRpIjoiOWRhOThmMTYtOTEyOS00N2NmLTgzOGQtNWQzYmVkYzYyZTJjIiwiaXNzIjoiaHR0cDovLzEwLjIwLjExLjE2MDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjE4MzhjNGYyLTVmZTMtNGYwYy1iMmQyLWQzNjRiMjdhNDk5NyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLWNsaSIsInNlc3Npb25fc3RhdGUiOiJjYzcxZmMxZi1hZGQ0LTRhODYtYWU1ZS1jMzRkZjQwM2M3NzIiLCJhY3IiOiIxIiwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiJ9.PUT4NzCM1ej3sNMMCkQa1NuQQwDgn19G-OnWL4NgLvZ3ocJUZ1Yfr9KAPkrJHaiK_HXQqwTA-Ma6Qn7BBMoXNdFjwu0k_HpqyUbBDilGN4wpkGiUeS1p5SW4T_hnWJtwCJ5BYkEvF6WaEbi7MFCbEVO9LVcUvsa-7St1WZ8V8RVfbWgjAu7ejlxe6RYUDMYzIKDj5F5y1-qCyoKzGIjt5ajcA9FWrexHifLJECKO8ZG08Wp7xQld1sYPOdde6XHMwiyNelTwd_EzCBgUw_8664rETGDVtyfuYchowo5Z6fmn4U87L6EGjEuxiAE8f3USy_jh6UF0LnvyTyq_9I"
                 + "M1VA";
-        final String token2 = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ1OHNXaTF4QWxjT1pyelY4X0l2VjliMlJTaFdZUWV4aXZYUXNYLTFTMERNIn0."
-                + "eyJleHAiOjE2MTAzNzA3MDcsImlhdCI6MTYxMDM3MDQwNywianRpIjoiMTczMmI0YzQtNDJlYS00ZWM4LTlhNjMtMTY2YTg4ZTk5ZjQ0IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjE4MzhjNGYyLTVmZTMtNGYwYy1iMmQyLWQzNjRiMjdhNDk5NyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLWNsaSIsInNlc3Npb25fc3RhdGUiOiJhZjVkYTk2NS1jYmIzLTQzOTYtYmNjNi1kZTBkMDUyOWMyNDgiLCJhY3IiOiIxIiwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiJ9.G_1ByqQlPuJ6_5nuIECfY1VqGufzWQpnFKuOy8YPOOug_jJsIwhVo-JQJiKAxYbHbmDNLrpRJTFlSub0K-1AFyxMw0k_W_YLV0dOTqIakVMTKk9obHFAYtthvhdbt5zb9-33OdCRMMKjA-arj8UeOLEAeFkaeYYBARCD4mEnMFG0vzEiovCCD-jXsfISiS-lOYnCd3hWK8e0brk_bvauxS9W4Z6nptE2564wshe9N_j9-3bQRRAHiAt6f755PhbYgJAu87GdA0bLh_TDe6fie-03goIFMssHoq4n67i-8501UoIG_LccijnfexCS-YwxkfTLbz5d8PvsNadqvFlvig";
         final String response =
                 "{\"access_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ1OHNXaTF4QWxjT1pyelY4X0l2VjliMlJTaFdZUWV4aXZYUXNYLTFTME"
                         + "RNIn0.eyJleHAiOjE2MTAzNjE2OTQsImlhdCI6MTYxMDM2MTM5NCwianRpIjoiOWRhOThmMTYtOTEyOS00N2NmLTgzOGQtNWQzYmVkYzYyZTJjIiwiaXNzIjoiaHR0cDovLzEwLjIwLjExLjE2MDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjE4MzhjNGYyLTVmZTMtNGYwYy1iMmQyLWQzNjRiMjdhNDk5NyIsInR5cCI6IkJlYXJlciIsImF6cCI6I"
index 6c46ed2..dda3ba1 100644 (file)
@@ -41,6 +41,7 @@ import javax.servlet.http.HttpServletResponse;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthProviderConfig;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.GitlabProviderService;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
@@ -57,9 +58,9 @@ public class TestGitlabAuthService {
     private static final String REDIRECT_URI = "/odlux/token?";
 
     @BeforeClass
-    public static void init() {
+    public static void init() throws IllegalArgumentException, Exception {
 
-        TokenCreator tokenCreator = TokenCreator.getInstance(TOKENCREATOR_SECRET, "issuer");
+        TokenCreator tokenCreator = TokenCreator.getInstance(Config.TOKENALG_HS256, TOKENCREATOR_SECRET, "issuer", 30*60);
         OAuthProviderConfig config = new OAuthProviderConfig("git", GITURL, null, "odlux.app", OAUTH_SECRET, "openid",
                 "gitlab test", "", false);
         oauthService = new GitlabProviderServiceToTest(config, REDIRECT_URI, tokenCreator);
@@ -160,7 +161,6 @@ public class TestGitlabAuthService {
             final String uri = t.getRequestURI().toString();
             System.out.println(String.format("req received: %s %s", method, t.getRequestURI()));
             OutputStream os = null;
-            String response = "";
             try {
                 if (method.equals("GET")) {
                     if (uri.equals(GITLAB_USER_ENDPOINT)) {
index 30b24af..e4c5e4d 100644 (file)
@@ -41,6 +41,7 @@ import javax.servlet.http.HttpServletResponse;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthProviderConfig;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.KeycloakProviderService;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
@@ -57,9 +58,9 @@ public class TestKeycloakAuthService {
     private static final String REDIRECT_URI = "/odlux/token?";
 
     @BeforeClass
-    public static void init() {
+    public static void init() throws IllegalArgumentException, Exception {
 
-        TokenCreator tokenCreator = TokenCreator.getInstance(TOKENCREATOR_SECRET, "issuer");
+        TokenCreator tokenCreator = TokenCreator.getInstance(Config.TOKENALG_HS256, TOKENCREATOR_SECRET, "issuer", 30*60);
         OAuthProviderConfig config = new OAuthProviderConfig("kc", KEYCLOAKURL, null, "odlux.app", OAUTH_SECRET,
                 "openid", "keycloak test", "onap", false);
         oauthService = new KeycloakProviderServiceToTest(config, REDIRECT_URI, tokenCreator);
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRSAAlgorithms.java b/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRSAAlgorithms.java
new file mode 100644 (file)
index 0000000..84d8e0a
--- /dev/null
@@ -0,0 +1,108 @@
+/*
+ * ============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.test;
+
+import static org.junit.Assert.fail;
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTVerificationException;
+import com.auth0.jwt.interfaces.JWTVerifier;
+import java.io.IOException;
+import java.security.Security;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Date;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.RSAKeyReader;
+
+/**
+ *
+ * @author jack
+ *
+ */
+public class TestRSAAlgorithms {
+
+    private static final String ISSUER = "jwttest";
+    private static final String SUBJECT = "meandmymonkey";
+
+    @BeforeClass
+    public static void init() {
+        Security.addProvider(
+                new BouncyCastleProvider()
+       );
+    }
+
+    /**
+     * private and public key were generated in ubuntu 20.04 with
+     * $ ssh-keygen -t rsa -b 4096 -m PEM -P "" -f jwtRS512.key
+     * $ openssl rsa -in jwtRS512.key -pubout -outform PEM -out jwtRS512.key.pub
+     */
+    @Test
+    public void testRSA512() {
+        RSAPrivateKey privKey = null;
+        RSAPublicKey pubKey = null;
+        try {
+            privKey = RSAKeyReader.getPrivateKey("file://src/test/resources/jwtRS512.key");
+            pubKey = RSAKeyReader.getPublicKey("file://src/test/resources/jwtRS512.key.pub");
+        } catch (IOException e) {
+            e.printStackTrace();
+            fail(e.getMessage());
+        }
+        verifyAlg(Algorithm.RSA512(pubKey, privKey));
+    }
+
+    /**
+     * private and public key were generated in ubuntu 20.04 with
+     * $ openssl genrsa 2048 -out rsa-2048bit-jwtRS256.key
+     * $ openssl rsa -in jwtRS256.key -pubout > jwtRS256.key.pub
+     */
+    @Test
+    public void testRSA256() {
+        RSAPrivateKey privKey = null;
+        RSAPublicKey pubKey = null;
+        try {
+            privKey = RSAKeyReader.getPrivateKey("file://src/test/resources/jwtRS256.key");
+            pubKey = RSAKeyReader.getPublicKey("file://src/test/resources/jwtRS256.key.pub");
+        } catch (IOException e) {
+            e.printStackTrace();
+            fail(e.getMessage());
+        }
+        verifyAlg(Algorithm.RSA512(pubKey, privKey));
+    }
+
+    private static void verifyAlg(Algorithm a) {
+        long now = new Date().getTime();
+        final String token = JWT.create().withIssuer(ISSUER).withExpiresAt(new Date(now+10000))
+                .withIssuedAt(new Date(now))
+                .withSubject(SUBJECT)
+                .sign(a);
+        try {
+            JWTVerifier verifier = JWT.require(a).withIssuer(ISSUER).build();
+            verifier.verify(token);
+
+        } catch (JWTVerificationException e) {
+            fail(e.getMessage());
+        }
+    }
+}
index 4b20118..c08f395 100644 (file)
@@ -34,6 +34,7 @@ import java.util.List;
 import org.apache.shiro.authc.AuthenticationException;
 import org.apache.shiro.authc.AuthenticationInfo;
 import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.BearerToken;
 import org.apache.shiro.authc.UsernamePasswordToken;
 import org.apache.shiro.authz.AuthorizationInfo;
 import org.apache.shiro.subject.PrincipalCollection;
@@ -44,7 +45,6 @@ import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
 import org.opendaylight.aaa.api.shiro.principal.ODLPrincipal;
-import org.apache.shiro.authc.BearerToken;
 import org.opendaylight.aaa.shiro.tokenauthrealm.auth.AuthenticationManager;
 import org.opendaylight.aaa.shiro.tokenauthrealm.auth.TokenAuthenticators;
 import org.opendaylight.aaa.shiro.web.env.ThreadLocals;
@@ -55,7 +55,7 @@ public class TestRealm {
     private static TokenCreator tokenCreator;
 
     @BeforeClass
-    public static void init() {
+    public static void init() throws IllegalArgumentException, Exception {
         ThreadLocals.AUTH_SETVICE_TL.set(new AuthenticationManager());
         ThreadLocals.TOKEN_AUTHENICATORS_TL.set(new TokenAuthenticators());
         try {
@@ -135,6 +135,7 @@ public class TestRealm {
             fail(e.getMessage());
         }
         //odl token use case
+        ai=null;
         atoken = new UsernamePasswordToken("admin", "admin");
         try {
             ai = realm.doGetAuthenticationInfo(atoken);
@@ -155,7 +156,7 @@ public class TestRealm {
 
     public static class OAuth2RealmToTest extends OAuth2Realm {
 
-        public OAuth2RealmToTest() throws IOException {
+        public OAuth2RealmToTest() throws IllegalArgumentException, Exception {
             super();
         }
 
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/jwtRS256.key b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/jwtRS256.key
new file mode 100644 (file)
index 0000000..c0c15e0
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAyzd6BwZLS1UKchZENYyVycHZWp9iRTtLx31dZHfG8h0PLawG
+y+dXPEW8W/zVB13/Rdci9HXCnskBhzkFu9Ep+nI7X5C+lO3vxxNnGQ1CrRyHxHbb
+BYlm6J55l6tQox5qVcWe4iMbLm7F2eNKFPqEUu8OInjmLFZvS9C0qtfpqdeoyt4G
+XucUHcGZ/0E6yeq882+zYyb4pWN5PogAsP2KYeT1T6P0VCw4tda9GtokD3zOSaOg
+IvhIqe9jLAVcqWkxpuhV+IQdULBOxcJziW3AdQcB5IFQ7/SfZ9SnO5OpDTe02R5q
+bjH9k0iihrpI9HnlVrHqIEtFwDjuoPSeAOBjjwIDAQABAoIBAQCOfNeTFVa1+2rX
+k8U/xtNAJCvC3v6IjIsV1VEmoNVd7gI2g+hAEHWaTUtFNIIqKD5VOgPIZMmRjF8F
+8XWTu5UzheUbnOIEitEVRQWFC0c1GkwX9T6dIzqE4JlhPz3LIghtG6PL69GjPQh9
+PmEzVHRzsiq3AQ5jCDgBcNU89SdhbhPsfNpDq9+GaWUaVJ4MmJw52qLeSW0nh4NZ
+fMSINAfGZ/3Q2Nfe55zIk4KICyatKYLUMdcwynMwWYdZzg1e/4gxemdWdgFVUdPl
+rE6y404m+FrHl/nntL153u0C24jtEU0CJvLasu7hLjzAoANBzohcXxLY46jeNqk9
+yS4juMgBAoGBAPxn9hRH5vMxFCfT23/s1RnUB9Sal6OL8/hZ8OpwrnLaLmWDvvr5
+FBcDThhrHnJTLj0pOAxFX8kLjKgQdWB0ZqrEsG1R9AAVHxM4hXc92kDsAk4QJgCG
+tKDtzk9PKy8Jt1LnOF9n6NDLZuZim9Sv7qim6tt0L7K/mGrlCN4Gq6E3AoGBAM4c
+N2r0vObiSboryfY4xNSUZ1qLWAEJz4gyUQljSrlu2Gj5DK4rrTEd8Qyk9ehUdjuR
+giejpdjIvmjQ7NNPUogJbIoSbtKmx+k8qF7ieRulJjVBiJZLwNtGhiB4e6oZdhNl
+fJETn8MhkbOt8Sa1eEiR9u2O7IAYVwZLU/khkNxpAoGARxqKSgBPYSbsRKP767et
++I6wfgXmvd3JJqc/pOuFWTl5ZIOOo2jTbgAyWdKjSxV/qx8XeO16JEqqnxWz2y4v
+Vd/+y20QzY0lqeZ8QrEb8LoLlC4cZn2MGOGlAtaMlb2o9SPJz6aYAWmrXS9eMrY1
+BzGua4/5d+Ndbo+CxfkfFFUCgYEAjFimW8w+/TDFZ2H96g2J6f8LyZns2PgnOuSY
+Tb4w2cfi0MgVnFvdWP68bxG86PDqeXGBoSBMBCvdjF4HhXQUDNHt+K7Ii+RJaEaH
+l+S69tokBEuViFIZBrclCeNAwfkIb/jBM8CbHzIylpkxBly3hSLvc5/I5wir6XtN
+uOzkSVECgYEAy2oGf68OkNL74/WKDmQvnRxWkn78rCTzVAe0iJmJ3rAdak/Jb2Lj
+iihXn0XPsedZOZStbZYCG6GtcZCRypPi9HjO6DRRYFv3+aicjS7tVuJ3u39e5nIR
+K6eMAgFn1TAToc3gt/hUCnmreZ4ZUfQfuFK21Lqmn1FYJtck9ZHx0sw=
+-----END RSA PRIVATE KEY-----
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/jwtRS256.key.pub b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/jwtRS256.key.pub
new file mode 100644 (file)
index 0000000..add863a
--- /dev/null
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyzd6BwZLS1UKchZENYyV
+ycHZWp9iRTtLx31dZHfG8h0PLawGy+dXPEW8W/zVB13/Rdci9HXCnskBhzkFu9Ep
++nI7X5C+lO3vxxNnGQ1CrRyHxHbbBYlm6J55l6tQox5qVcWe4iMbLm7F2eNKFPqE
+Uu8OInjmLFZvS9C0qtfpqdeoyt4GXucUHcGZ/0E6yeq882+zYyb4pWN5PogAsP2K
+YeT1T6P0VCw4tda9GtokD3zOSaOgIvhIqe9jLAVcqWkxpuhV+IQdULBOxcJziW3A
+dQcB5IFQ7/SfZ9SnO5OpDTe02R5qbjH9k0iihrpI9HnlVrHqIEtFwDjuoPSeAOBj
+jwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/jwtRS512.key b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/jwtRS512.key
new file mode 100644 (file)
index 0000000..6b4e8c7
--- /dev/null
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEA5vZBjfLjlUPK0b/F8FbGAyT1jXNVv2vjl+ZGUlThDX1jn0Wh
+XER5CL9CfkHKjJE47r8pQsO6nX9s5y+XzmAU9+QggtaDA+g0Px+cvCJQzJbtDbh0
+94m3uC50S+SSnYvr7vY1zy+jdswf/pXg1z059FokRxGso36SkSv81NYbN/WQrTKo
+gY6jkZXfPP8/sn8KV8uf7jYy2ZyHtakM9c9oCopWH78mhf9ioUNbgJsAxZmiohQU
+N5a3GbLS/nsTBOcVxUezvjvfb732iChKoARj3NiNN7HFHpXEXfiZ10OjrtAb9Y1K
+9RZsu/MKcFxBhDZusXjee6/x+NluQwT3RybgkCyV/i97Sroc37wOqimxtoSJ+MZY
+ZXNAUGNbNySkjvIGL8jWMj6w/zvyiHVbQg+DqY2Qds7Tdk29swYsMQQlz9v0FS/p
+GFVWo+5HTm+3MMlaMjSofw6j5/sE4OvJ4RCcnX8Cj1Zq9PrsMLLSF5MBOCSiclpI
+C1EYQ9Oi6XrcL3bbyyKGwB/u1X1HHnUmhRdKdVwKpSHR54XlfBDDoYtVnb1HTTxX
+MuiGU0XQRLvdnytJX1Lk6NJg/UUUKhrVXiH05CZsxlPFjDlhEhp4Jh+f/mdf6llX
+vsXn8k9ujBZBBD6PI4X7GkKB45H9zicbwt65f/MjhEohkbL5oZAKySzaUuMCAwEA
+AQKCAgBF7uLCnH0UwUY0ZKEGuP+UDCjd/8JDB+QOJoe8fj722rTDkU3epk0PvPnh
+SQKPtZlLkU5pDOMAtYjAJ8ULlERFGypM868QC8tmIahPvwRALqLwuJ2SJn0eo9JK
++Jb8ZVW3MY3xgjc4zW4SpEdEZSGbP4AklNF1X+n5UxxnRb1QIGcCSoiDUjFs77h8
+u70JyzXSh7GRa4/SHHdrJhjqhTa3mlOhoTuE72Np+P9H3adKLc70zKeifVxLx73j
+mFiV73LEHYXrYC2zpA12BN0zvqCOSnPYHVfWfvrKiW/romt5j0IoA/Riabva3SiY
+BRdBdUnnKvYS9Z+K/itI18QYI0lzSuLiaCTCo/3N/2MkuRMwS3Mvae7kK43/6c3w
+sXobp8KBRMnpnT+AHENIHVJ35XKkWfTY9xMg/JkKbAXY06TitKW53ds03vb9Y9n2
+3SKBUcpbTkJJbJ50E/BiglLVxlllzVJiUIMNDGUmZO7eYQx9fs16cz4JkhzKcN+F
+zYg4BVXL8blWU6AjXzexjTNuic/IxkqJruG05tCFwVxHjhajb9xQ1ANDMcXnwPmt
+VKpU4KxrGqFgsVdZ5SE9gdu1g+zf96DdhXjHhZCfq6fsf2TYXD2SsUhx4kk9zOE/
+I4tXwf7Q7Ol24qlV9W8enc3gr1nk+buutl+I55LSM4bG4M3uQQKCAQEA/rkulfhl
+wxStbVIICRl6iuC1nhqlxOBZAbc45pRgEDyTO5IfxnVA6kVCa5DkQ5cWZOoshKg9
+MNfHbo9JIYZzElnM/XxpmqIsHpQ+ZXe5XVaaYz9DogNnH2iLtQGVVLPphtxJxTqW
+A6944GuhmZ9DmRwn0nN2nU0nUqBtLFio9+b7nChDaJj5aIkLHjx3p9ytjzzJP5nM
+0lKSo9BD97+AhCaIT7NxjKSRWRs7ftf7Bv5vxPXrpgUN8ltkg4YVIzGX7UMXT+ga
+H2kf+QkAJX1+9kbNMjkqhOH7zkv1DVqCVup9XewA2GltxoJZIVH04+QmgNWcS+XP
+cbxe0r95tuMTqQKCAQEA6B6WYpC9UxXLPfOJdWDzSO3oh13RgQo1uEHdU9rc9vfi
+vYZZsSL06uR7v6fuiuyAAayZgCTS1xr69MCAJR2056E3RthktAzOkfCJrcIyEHmy
+b9yekRyL+R8P4HxV76AYqY52PhdgDntGoXb7hcGKt6hvkmcR41cnRHRjrb7zkEVy
+55JY1woEVtt6otxHKZSnx5nlQct73Lv65QDfosfkESOmbE2W4G87XBk36I2YBywU
+kNEr49tnI09qyEPJLjTTGxFdMeqXbnCgzSwqlBlrQE8NYJBsy2GBL0EWOYeRXkuz
+RFug3o89uAOircy2virMhl6EOA0EKakWR4ZQCKlJqwKCAQEA40aBnYhL6/sIHtGh
+n9Te9Qk4o4AtRnPSluhPWdUrvXD/AZkIxv+Z0y3G7MkUEoa9kX8sB5VBO9Jb/HbW
+jpYzGD2N3OLkKvfmG8azwb9IYlLCYClzhBw7J9gVR4TJJBF/HThyjgsPDOzFEqCW
+SMbE/tkTYwBo5kOQAXZo0res07yB5bw7IRnU94PHqsvTC7CoH3TiL+Bf042fj5Bl
+BKoW1lK3Lz3x48Z2daYJuMynC398ZKX0A2bhIcyP65Z4R7WZVDaXl1GF9V7MC10P
+h2PpI37a2aQOHxCvp0s4tBh80WZaQ7Iusumm7Acj1coVkjzgafWuhj3fkSC9DpeP
+1zHXOQKCAQBCiVIOWvMKN/sUfRTwAqR6SUgYVXpShPy1Hpw1B03DtXbXYQWg0yZl
+lq0qWRb116kx0aoGo4eUhXVeZzfUa9mJdBsGQc1MF0e3ab3tgvca5eeSTSle61Hs
+TU0dykZP9BJduCqIzeaJAClU62haBQqgbrXcv5LPGhJ1eu9/xHbI6j9vxfGVYpev
+1iYnPQFhF+2oN6MR4yRUN8ZJkqCIZsgnaZKxBOS03O2lDs2J6dykYaxbfroYDLJZ
+2s//K/8lMZs57RZL0rUpwTs21Ow3m7m0q3RoM74b5o1DYGLghs3Su9xdQe6xHVpR
+vykIrN/NTzNlaP55mrGQx5lNU2Dpuq0VAoIBAQDVCfAJlu+wkZmeXm1zUOFjOMvq
+el3t55RCQ/SuhIpaNf2CWD6SOZfHfTxJ8nuYE+FJmjL6r9Z4a8ND0VPttuyBG6gY
+siuZUE31+2OBvdKBhi4stqGZWMKJqYsDFH7QIfu7wSS1kuJ/vA7MB9f7IsrHJb2z
+QBJoVMZoXhh4tqyFVatEp6yYSE4uKLvlKQSJ6W8DEuPggoiNPbhxQq2ctFUyup/S
+9MsfJ9tj99mjlPSelMUXsHcsprIZBuhskfeidTe+gy43TBm0G8l7xeAGWkBlWQMR
+L843JjebD6QCnPIS4nrW7kCRM8lv1ZId6D5Jq1Coc8b1ZrezfII7/eNgZZCv
+-----END RSA PRIVATE KEY-----
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/jwtRS512.key.pub b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/jwtRS512.key.pub
new file mode 100644 (file)
index 0000000..7191c95
--- /dev/null
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5vZBjfLjlUPK0b/F8FbG
+AyT1jXNVv2vjl+ZGUlThDX1jn0WhXER5CL9CfkHKjJE47r8pQsO6nX9s5y+XzmAU
+9+QggtaDA+g0Px+cvCJQzJbtDbh094m3uC50S+SSnYvr7vY1zy+jdswf/pXg1z05
+9FokRxGso36SkSv81NYbN/WQrTKogY6jkZXfPP8/sn8KV8uf7jYy2ZyHtakM9c9o
+CopWH78mhf9ioUNbgJsAxZmiohQUN5a3GbLS/nsTBOcVxUezvjvfb732iChKoARj
+3NiNN7HFHpXEXfiZ10OjrtAb9Y1K9RZsu/MKcFxBhDZusXjee6/x+NluQwT3Rybg
+kCyV/i97Sroc37wOqimxtoSJ+MZYZXNAUGNbNySkjvIGL8jWMj6w/zvyiHVbQg+D
+qY2Qds7Tdk29swYsMQQlz9v0FS/pGFVWo+5HTm+3MMlaMjSofw6j5/sE4OvJ4RCc
+nX8Cj1Zq9PrsMLLSF5MBOCSiclpIC1EYQ9Oi6XrcL3bbyyKGwB/u1X1HHnUmhRdK
+dVwKpSHR54XlfBDDoYtVnb1HTTxXMuiGU0XQRLvdnytJX1Lk6NJg/UUUKhrVXiH0
+5CZsxlPFjDlhEhp4Jh+f/mdf6llXvsXn8k9ujBZBBD6PI4X7GkKB45H9zicbwt65
+f/MjhEohkbL5oZAKySzaUuMCAwEAAQ==
+-----END PUBLIC KEY-----
index 260b77d..a55576b 100644 (file)
@@ -4,6 +4,7 @@
     "publicUrl": "http://nasp.diasf.de",
     "redirectUri": "/index.html#redirect=",
     "supportOdlUsers": "true",
+    "tokenLifetime":3600,
     "providers": [
         {
             "id": "keycloak",
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/test.configRS256-invalid.json b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/test.configRS256-invalid.json
new file mode 100644 (file)
index 0000000..30b80c4
--- /dev/null
@@ -0,0 +1,24 @@
+{
+    "tokenSecret": "",
+    "tokenPubKey": "file:///src/test/resources/jwtRS256.key.pub",
+    "algorithm":"RS256",
+    "tokenIssuer": "ONAP SDNC",
+    "publicUrl": "http://nasp.diasf.de",
+    "redirectUri": "/index.html#redirect=",
+    "supportOdlUsers": "true",
+    "tokenLifetime":3600,
+    "providers": [
+        {
+            "id": "keycloak",
+            "type": "KEYCLOAK",
+            "url": "http://10.20.11.160:8080",
+            "clientId": "odlux.app",
+            "secret": "5da4ea3d-8cc9-4669-bd7e-3ecb91d120cd",
+            "publickey": "",
+            "algorithm":"RS256",
+            "scope": "openid",
+            "title": "OSNL Keycloak Provider",
+            "realmName":"onap"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/test.configRS256.json b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/test.configRS256.json
new file mode 100644 (file)
index 0000000..02a4e8f
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "tokenSecret": "file:///src/test/resources/jwtRS256.key",
+    "tokenPubKey": "file:///src/test/resources/jwtRS256.key.pub",
+    "algorithm":"RS256",
+    "tokenIssuer": "ONAP SDNC",
+    "publicUrl": "http://nasp.diasf.de",
+    "redirectUri": "/index.html#redirect=",
+    "supportOdlUsers": "true",
+    "tokenLifetime":3600,
+    "providers": [
+        {
+            "id": "keycloak",
+            "type": "KEYCLOAK",
+            "url": "http://10.20.11.160:8080",
+            "clientId": "odlux.app",
+            "secret": "5da4ea3d-8cc9-4669-bd7e-3ecb91d120cd",
+            "scope": "openid",
+            "title": "OSNL Keycloak Provider",
+            "realmName":"onap"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/test.configRS512.json b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/test.configRS512.json
new file mode 100644 (file)
index 0000000..eddc6c3
--- /dev/null
@@ -0,0 +1,22 @@
+{
+    "tokenSecret": "file:///src/test/resources/jwtRS512.key",
+    "tokenPubKey": "file:///src/test/resources/jwtRS512.key.pub",
+    "algorithm":"RS512",
+    "tokenIssuer": "ONAP SDNC",
+    "publicUrl": "http://nasp.diasf.de",
+    "redirectUri": "/index.html#redirect=",
+    "supportOdlUsers": "true",
+    "tokenLifetime":3600,
+    "providers": [
+        {
+            "id": "keycloak",
+            "type": "KEYCLOAK",
+            "url": "http://10.20.11.160:8080",
+            "clientId": "odlux.app",
+            "secret": "5da4ea3d-8cc9-4669-bd7e-3ecb91d120cd",
+            "scope": "openid",
+            "title": "OSNL Keycloak Provider",
+            "realmName":"onap"
+        }
+    ]
+}
\ No newline at end of file