add unit tests for oauth-provider 32/117932/1
authorMichael DÜrre <michael.duerre@highstreet-technologies.com>
Wed, 17 Feb 2021 07:48:52 +0000 (08:48 +0100)
committerMichael DÜrre <michael.duerre@highstreet-technologies.com>
Wed, 17 Feb 2021 07:49:05 +0000 (08:49 +0100)
add unit tests and some fixes for oauth provider

Issue-ID: CCSDK-3169
Signed-off-by: Michael DÜrre <michael.duerre@highstreet-technologies.com>
Change-Id: I88c5b2123df7e0c6e49b087c3cc7d24130be5bff

34 files changed:
sdnr/wt/data-provider/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/yangtools/mapperextensions/YangToolsBuilderAnnotationIntrospector.java
sdnr/wt/data-provider/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/dataprovider/test/TestAbout.java
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/OAuthProviderConfig.java
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlPolicy.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 [new file with mode: 0644]
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 [new file with mode: 0644]
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/OAuthProviderFactory.java
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 [new file with mode: 0644]
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 [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestKeycloakAuthService.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestPolicy.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 [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlJsonMapper.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlXmlMapper.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/aaa-app-config.test.xml [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/mdsalDynAuthData.json [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/oauth/gitlab-groups-response.json [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/oauth/gitlab-token-response.json [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/oauth/gitlab-user-response.json [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/oauth/keycloak-token-response.json [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/oom.test.config.json [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/test.config.json
sdnr/wt/oauth-provider/provider-osgi/pom.xml
sdnr/wt/oauth-provider/provider-osgi/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml

index 624451c..48e512a 100644 (file)
@@ -32,8 +32,6 @@ import java.nio.file.Files;
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-
-import org.jline.utils.Log;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -111,7 +109,7 @@ public class TestAbout {
        AboutHelperServlet sv = new AboutHelperServlet();
        assertNotNull(sv.getGroupIdOrDefault(null));
     }
-    
+
 
     private class AboutHelperServlet extends AboutHttpServlet {
 
index 3ee21b2..d669a16 100644 (file)
 <!--                 </exclusion> -->
             </exclusions>
         </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal</groupId>
+            <artifactId>mdsal-binding-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
         <dependency>
             <groupId>org.opendaylight.mdsal</groupId>
             <artifactId>yang-binding</artifactId>
             <artifactId>jetty-servlet</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.dataformat</groupId>
+            <artifactId>jackson-dataformat-xml</artifactId>
+            <scope>test</scope>
+        </dependency>
+         <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>sdnr-wt-data-provider-provider</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal.binding.model.ietf</groupId>
+            <artifactId>rfc6991-ietf-yang-types</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.netconf</groupId>
+            <artifactId>sal-netconf-connector</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 </project>
index a3e4bcc..0a40e8d 100644 (file)
@@ -50,9 +50,8 @@ public class OAuth2Realm extends TokenAuthRealm {
         super();
         super.setName(REALM_NAME);
         this.config = Config.getInstance();
-        this.tokenCreator = TokenCreator.getInstance();
+        this.tokenCreator = TokenCreator.getInstance(this.config);
         LOG.info("instantiated");
-
     }
 
     @Override
index ba26106..a71f4c7 100644 (file)
@@ -48,16 +48,16 @@ public class Config {
 
 
     private List<OAuthProviderConfig> providers;
-    private String host;
     private String redirectUri;
     private String supportOdlUsers;
     private String tokenSecret;
     private String tokenIssuer;
+    private String publicUrl;
 
 
     @Override
     public String toString() {
-        return "Config [providers=" + providers + ", host=" + host + ", redirectUri=" + redirectUri
+        return "Config [providers=" + providers + ", redirectUri=" + redirectUri
                 + ", supportOdlUsers=" + supportOdlUsers + ", tokenSecret=" + tokenSecret + ", tokenIssuer="
                 + tokenIssuer + "]";
     }
@@ -72,14 +72,6 @@ public class Config {
         this.providers = providers;
     }
 
-    public String getHost() {
-        return host;
-    }
-
-    public void setHost(String host) {
-        this.host = host;
-    }
-
     public String getRedirectUri() {
         return redirectUri;
     }
@@ -112,6 +104,15 @@ public class Config {
         this.tokenIssuer = tokenIssuer;
     }
 
+
+    public String getPublicUrl() {
+        return publicUrl;
+    }
+
+    public void setPublicUrl(String publicUrl) {
+        this.publicUrl = publicUrl;
+    }
+
     @JsonIgnore
     private void handleEnvironmentVars() {
         if (isEnvExpression(tokenIssuer)) {
@@ -120,8 +121,8 @@ public class Config {
         if (isEnvExpression(tokenSecret)) {
             this.tokenSecret = getProperty(tokenSecret, null);
         }
-        if (isEnvExpression(host)) {
-            this.host = getProperty(host, null);
+        if (isEnvExpression(publicUrl)) {
+            this.publicUrl = getProperty(publicUrl, null);
         }
         if (isEnvExpression(redirectUri)) {
             this.redirectUri = getProperty(redirectUri, null);
@@ -139,9 +140,12 @@ public class Config {
         if (tokenSecret == null || tokenSecret.isEmpty()) {
             this.tokenSecret = DEFAULT_TOKENSECRET;
         }
-        if (redirectUri == null || redirectUri.isEmpty()) {
+        if (redirectUri == null || redirectUri.isEmpty() || "null".equals(redirectUri)) {
             this.redirectUri = DEFAULT_REDIRECTURI;
         }
+        if (publicUrl != null && (publicUrl.isEmpty() || "null".equals(publicUrl))) {
+            this.publicUrl = null;
+        }
         if (supportOdlUsers == null || supportOdlUsers.isEmpty()) {
             this.supportOdlUsers = DEFAULT_SUPPORTODLUSERS;
         }
@@ -150,11 +154,12 @@ public class Config {
     static boolean isEnvExpression(String key) {
         return key != null && key.contains(ENVVARIABLE);
     }
-
-    private static String generateSecret() {
+    public static String generateSecret() {
+        return generateSecret(30);
+    }
+    public static String generateSecret(int targetStringLength) {
         int leftLimit = 48; // numeral '0'
         int rightLimit = 122; // letter 'z'
-        int targetStringLength = 30;
         Random random = new Random();
 
         String generatedString = random.ints(leftLimit, rightLimit + 1)
@@ -226,10 +231,12 @@ public class Config {
     }
 
 
-
     public static Config getInstance() throws IOException {
+        return getInstance(DEFAULT_CONFIGFILENAME);
+    }
+    public static Config getInstance(String filename) throws IOException {
         if(_instance==null) {
-            _instance = load(DEFAULT_CONFIGFILENAME);
+            _instance = load(filename);
         }
         return _instance;
     }
index e4d6743..3f1673c 100644 (file)
 package org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;
 
 import com.fasterxml.jackson.annotation.JsonIgnore;
+import java.util.HashMap;
+import java.util.Map;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.OAuthProviderFactory.OAuthProvider;
 
 public class OAuthProviderConfig {
 
-    private String host;
+    private String url;
     private String clientId;
     private String secret;
     private String id;
     private String title;
     private String scope;
     private OAuthProvider type;
+    private Map<String,String> roleMapping;
 
     public OAuthProvider getType() {
         return type;
     }
 
-    public OAuthProviderConfig(String id, String host, String clientId, String secret, String scope,
+    public OAuthProviderConfig(String id, String url, String clientId, String secret, String scope,
             String title) {
         this.id = id;
-        this.host = host;
+        this.url = url;
         this.clientId = clientId;
         this.secret = secret;
         this.scope = scope;
         this.title = title;
+        this.roleMapping = new HashMap<>();
     }
 
     @Override
     public String toString() {
-        return "OAuthProviderConfig [host=" + host + ", clientId=" + clientId + ", secret=" + secret + ", id=" + id
+        return "OAuthProviderConfig [host=" + url + ", clientId=" + clientId + ", secret=" + secret + ", id=" + id
                 + ", title=" + title + ", scope=" + scope + ", type=" + type + "]";
     }
 
@@ -62,8 +66,8 @@ public class OAuthProviderConfig {
         this(null, null, null, null, null, null);
     }
 
-    public void setHost(String host) {
-        this.host = host;
+    public void setUrl(String url) {
+        this.url = url;
     }
 
     public void setClientId(String clientId) {
@@ -90,8 +94,8 @@ public class OAuthProviderConfig {
         return this.id;
     }
 
-    public String getHost() {
-        return this.host;
+    public String getUrl() {
+        return this.url;
     }
 
     public String getClientId() {
@@ -110,13 +114,21 @@ public class OAuthProviderConfig {
         return this.scope;
     }
 
+    public Map<String, String> getRoleMapping() {
+        return roleMapping;
+    }
+
+    public void setRoleMapping(Map<String, String> roleMapping) {
+        this.roleMapping = roleMapping;
+    }
+
     @JsonIgnore
     public void handleEnvironmentVars() {
         if (Config.isEnvExpression(id)) {
             this.id = Config.getProperty(id, null);
         }
-        if (Config.isEnvExpression(host)) {
-            this.host = Config.getProperty(host, null);
+        if (Config.isEnvExpression(url)) {
+            this.url = Config.getProperty(url, null);
         }
         if (Config.isEnvExpression(clientId)) {
             this.clientId = Config.getProperty(clientId, null);
index 28ef3b3..19eb4b6 100644 (file)
@@ -68,7 +68,7 @@ public class OdlPolicy {
         private boolean patch;
 
         public PolicyMethods() {
-
+            this(false, false, false, false, false);
         }
 
         public PolicyMethods(boolean get, boolean post, boolean put, boolean del, boolean patch) {
index f5d344d..cd42390 100644 (file)
@@ -48,11 +48,12 @@ 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.providers.AuthService;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.AuthService.PublicOAuthProviderConfig;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.MdSalAuthorizationStore;
 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.IDMStoreException;
 import org.opendaylight.aaa.api.IdMService;
 import org.opendaylight.aaa.shiro.filters.backport.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;
 import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.shiro.configuration.Urls;
@@ -68,11 +69,14 @@ public class AuthHttpServlet extends HttpServlet {
     //private static final String LOGOUTURI = BASEURI + "/logout";
     private static final String PROVIDERSURI = BASEURI + "/providers";
     public static final String REDIRECTURI = BASEURI + "/redirect";
+    private static final String REDIRECTURI_FORMAT = REDIRECTURI + "/%s";
     private static final String POLICIESURI = BASEURI + "/policies";
     //private static final String PROVIDERID_REGEX = "^\\" + BASEURI + "\\/providers\\/([^\\/]+)$";
     private static final String REDIRECTID_REGEX = "^\\" + BASEURI + "\\/redirect\\/([^\\/]+)$";
+    private static final String LOGIN_REDIRECT_REGEX = "^\\" + LOGINURI + "\\/([^\\/]+)$";
     //private static final Pattern PROVIDERID_PATTERN = Pattern.compile(PROVIDERID_REGEX);
     private static final Pattern REDIRECTID_PATTERN = Pattern.compile(REDIRECTID_REGEX);
+    private static final Pattern LOGIN_REDIRECT_PATTERN = Pattern.compile(LOGIN_REDIRECT_REGEX);
 
     private static final String DEFAULT_DOMAIN = "sdn";
     private static final String HEAEDER_AUTHORIZATION = "Authorization";
@@ -83,6 +87,7 @@ public class AuthHttpServlet extends HttpServlet {
             "org.opendaylight.aaa.shiro.filters.ODLHttpAuthenticationFilter2";
     private static final String CLASSNAME_ODLMDSALAUTH =
             "org.opendaylight.aaa.shiro.realm.MDSALDynamicAuthorizationFilter";
+    public static final String LOGIN_REDIRECT_FORMAT = LOGINURI + "/%s";
 
     private final ObjectMapper mapper;
     /* state <=> AuthProviderService> */
@@ -92,15 +97,17 @@ public class AuthHttpServlet extends HttpServlet {
     private final TokenCreator tokenCreator;
     private final Config config;
     private ShiroConfiguration shiroConfiguration;
+    private DataBroker dataBroker;
+    private MdSalAuthorizationStore mdsalAuthStore;
 
     public AuthHttpServlet() throws IOException {
-        this.tokenCreator = TokenCreator.getInstance();
         this.config = Config.getInstance();
+        this.tokenCreator = TokenCreator.getInstance(this.config);
         this.mapper = new ObjectMapper();
         this.providerStore = new HashMap<>();
         for (OAuthProviderConfig pc : config.getProviders()) {
             this.providerStore.put(pc.getId(), OAuthProviderFactory.create(pc.getType(), pc,
-                    this.config.getRedirectUri(), TokenCreator.getInstance()));
+                    this.config.getRedirectUri(), TokenCreator.getInstance(this.config)));
         }
 
     }
@@ -117,12 +124,19 @@ public class AuthHttpServlet extends HttpServlet {
         this.shiroConfiguration = shiroConfiguration;
     }
 
+    public void setDataBroker(DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+        this.mdsalAuthStore = new MdSalAuthorizationStore(this.dataBroker);
+    }
+
     @Override
     protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
         LOG.debug("GET request for {}", req.getRequestURI());
-        fillHost(req);
+        getHost(req);
         if (PROVIDERSURI.equals(req.getRequestURI())) {
             this.sendResponse(resp, HttpServletResponse.SC_OK, getConfigs(this.providerStore.values()));
+        } else if (req.getRequestURI().startsWith(LOGINURI)) {
+            this.handleLoginRedirect(req, resp);
         } else if (POLICIESURI.equals(req.getRequestURI())) {
             this.sendResponse(resp, HttpServletResponse.SC_OK, this.getPoliciesForUser(req));
         } else if (req.getRequestURI().startsWith(REDIRECTURI)) {
@@ -133,6 +147,22 @@ public class AuthHttpServlet extends HttpServlet {
 
     }
 
+    private void handleLoginRedirect(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        final String uri = req.getRequestURI();
+        final Matcher matcher = LOGIN_REDIRECT_PATTERN.matcher(uri);
+        if (matcher.find()) {
+            final String id = matcher.group(1);
+            AuthService provider = this.providerStore.getOrDefault(id, null);
+            if (provider != null) {
+                //provider.setLocalHostUrl(getHost(req));
+                String redirectUrl = getHost(req) + String.format(REDIRECTURI_FORMAT, id);
+                provider.sendLoginRedirectResponse(resp, redirectUrl);
+                return;
+            }
+        }
+        this.sendResponse(resp, HttpServletResponse.SC_NOT_FOUND, "");
+    }
+
     /**
      * find out what urls can be accessed by user and which are forbidden
      *
@@ -161,8 +191,13 @@ public class AuthHttpServlet extends HttpServlet {
                     try {
                         final String authClass = getAuthClass(matcher.group(1));
                         Optional<OdlPolicy> policy = Optional.empty();
-                        if (authClass.equals(CLASSNAME_ODLBASICAUTH)
-                                || authClass.equals(CLASSNAME_ODLBEARERANDBASICAUTH)) {
+                        //anon access allowed
+                        if (authClass == null) {
+                            policy = Optional.of(OdlPolicy.allowAll(urlRule.getPairKey()));
+                        } else if (authClass.equals(CLASSNAME_ODLBASICAUTH)) {
+                            policy = isBasic(req) ? this.getTokenBasedPolicy(urlRule, matcher, data)
+                                    : Optional.of(OdlPolicy.denyAll(urlRule.getPairKey()));
+                        } else if (authClass.equals(CLASSNAME_ODLBEARERANDBASICAUTH)) {
                             policy = this.getTokenBasedPolicy(urlRule, matcher, data);
                         } else if (authClass.equals(CLASSNAME_ODLMDSALAUTH)) {
                             policy = this.getMdSalBasedPolicy(urlRule, matcher, data);
@@ -172,6 +207,7 @@ public class AuthHttpServlet extends HttpServlet {
                         } else {
                             LOG.warn("unable to get policy for authClass {} for entry {}", authClass,
                                     urlRule.getPairValue());
+                            policies.add(OdlPolicy.denyAll(urlRule.getPairKey()));
                         }
                     } catch (NoDefinitionFoundException e) {
                         LOG.warn("unknown authClass: ", e);
@@ -188,20 +224,24 @@ public class AuthHttpServlet extends HttpServlet {
     }
 
     /**
-     * extract policy rule for user from MD-SAL
-     * not yet supported
+     * extract policy rule for user from MD-SAL not yet supported
+     *
      * @param urlRule
      * @param matcher
      * @param data
      * @return
      */
     private Optional<OdlPolicy> getMdSalBasedPolicy(Urls urlRule, Matcher matcher, UserTokenPayload data) {
-
+        if (this.mdsalAuthStore != null) {
+            return data != null ? this.mdsalAuthStore.getPolicy(urlRule.getPairKey(), data.getRoles())
+                    : Optional.of(OdlPolicy.denyAll(urlRule.getPairKey()));
+        }
         return Optional.empty();
     }
 
     /**
      * extract policy rule for user from url rules of config
+     *
      * @param urlRule
      * @param matcher
      * @param data
@@ -209,25 +249,27 @@ public class AuthHttpServlet extends HttpServlet {
      */
     private Optional<OdlPolicy> getTokenBasedPolicy(Urls urlRule, Matcher matcher, UserTokenPayload data) {
         final String url = urlRule.getPairKey();
-        if (!urlRule.getPairValue().contains(",")) {
+        final String rule = urlRule.getPairValue();
+        if (!rule.contains(",")) {
             LOG.debug("found rule without roles for '{}'", matcher.group(1));
             //not important if anon or authcXXX
             if (data != null || "anon".equals(matcher.group(1))) {
                 return Optional.of(OdlPolicy.allowAll(url));
             }
-        } else if (data != null) {
+        }
+        if (data != null) {
             LOG.debug("found rule with roles '{}'", matcher.group(4));
             if ("roles".equals(matcher.group(2))) {
                 if (this.rolesMatch(data.getRoles(), Arrays.asList(matcher.group(4).split(",")), false)) {
-                    Optional.of(OdlPolicy.allowAll(url));
+                    return Optional.of(OdlPolicy.allowAll(url));
                 } else {
-                    Optional.of(OdlPolicy.denyAll(url));
+                    return Optional.of(OdlPolicy.denyAll(url));
                 }
             } else if ("anyroles".equals(matcher.group(2))) {
                 if (this.rolesMatch(data.getRoles(), Arrays.asList(matcher.group(4).split(",")), true)) {
-                    Optional.of(OdlPolicy.allowAll(url));
+                    return Optional.of(OdlPolicy.allowAll(url));
                 } else {
-                    Optional.of(OdlPolicy.denyAll(url));
+                    return Optional.of(OdlPolicy.denyAll(url));
                 }
             } else {
                 LOG.warn("unable to detect url role value: {}", urlRule.getPairValue());
@@ -252,7 +294,7 @@ public class AuthHttpServlet extends HttpServlet {
 
     private UserTokenPayload getUserInfo(HttpServletRequest req) {
         if (isBearer(req)) {
-            UserTokenPayload data = TokenCreator.getInstance().decode(req);
+            UserTokenPayload data = TokenCreator.getInstance(this.config).decode(req);
             if (data != null) {
                 return data;
             }
@@ -317,8 +359,8 @@ public class AuthHttpServlet extends HttpServlet {
 
     }
 
-    private void fillHost(HttpServletRequest req) {
-        String hostUrl = this.config.getHost();
+    public String getHost(HttpServletRequest req) {
+        String hostUrl = this.config.getPublicUrl();
         if (hostUrl == null) {
             final String tmp = req.getRequestURL().toString();
             final String regex = "^(http[s]{0,1}:\\/\\/[^\\/]+)";
@@ -326,16 +368,17 @@ public class AuthHttpServlet extends HttpServlet {
             final Matcher matcher = pattern.matcher(tmp);
             if (matcher.find()) {
                 hostUrl = matcher.group(1);
-                this.config.setHost(hostUrl);
             }
         }
+        LOG.info("host={}", hostUrl);
+        return hostUrl;
 
     }
 
     private List<PublicOAuthProviderConfig> getConfigs(Collection<AuthService> values) {
         List<PublicOAuthProviderConfig> configs = new ArrayList<>();
         for (AuthService svc : values) {
-            configs.add(svc.getConfig(this.config.getHost()));
+            configs.add(svc.getConfig());
         }
         return configs;
     }
@@ -353,8 +396,8 @@ public class AuthHttpServlet extends HttpServlet {
         if (matcher.find()) {
             AuthService provider = this.providerStore.getOrDefault(matcher.group(1), null);
             if (provider != null) {
-                provider.setLocalHostUrl(this.config.getHost());
-                provider.handleRedirect(req, resp);
+                //provider.setLocalHostUrl(getHost(req));
+                provider.handleRedirect(req, resp, getHost(req));
                 return;
             }
         }
@@ -382,33 +425,6 @@ public class AuthHttpServlet extends HttpServlet {
         resp.sendError(HttpServletResponse.SC_NOT_FOUND);
     }
 
-    @Override
-    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        //        final String uri = req.getRequestURI();
-        //        final Matcher matcher = PROVIDERID_PATTERN.matcher(uri);
-        //        if (matcher.find()) {
-        //            final String id = matcher.group(1);
-        //            final OAuthProviderConfig config = this.mapper.readValue(req.getInputStream(), OAuthProviderConfig.class);
-        //            //this.providerStore.put(id, config);
-        //            sendResponse(resp, HttpServletResponse.SC_OK, "");
-        //            return;
-        //        }
-        resp.sendError(HttpServletResponse.SC_NOT_FOUND);
-    }
-
-    @Override
-    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
-        //        final String uri = req.getRequestURI();
-        //        final Matcher matcher = PROVIDERID_PATTERN.matcher(uri);
-        //        if (matcher.find()) {
-        //            final String id = matcher.group(1);
-        //            this.providerStore.remove(id);
-        //            sendResponse(resp, HttpServletResponse.SC_OK, "");
-        //            return;
-        //        }
-        resp.sendError(HttpServletResponse.SC_NOT_FOUND);
-    }
-
     private BearerToken doLogin(String username, String password, String domain) {
         if (!username.contains("@")) {
             username = String.format("%s@%s", username, domain);
@@ -416,12 +432,6 @@ public class AuthHttpServlet extends HttpServlet {
         HttpServletRequest req = new HeadersOnlyHttpServletRequest(
                 Map.of("Authorization", BaseHTTPClient.getAuthorizationHeaderValue(username, password)));
         if (this.odlAuthenticator.authenticate(req)) {
-            try {
-                LOG.info("userids={}", this.odlIdentityService.listUserIDs());
-                LOG.info("domains={}", this.odlIdentityService.listDomains(username));
-            } catch (IDMStoreException e) {
-
-            }
             List<String> roles = this.odlIdentityService.listRoles(username, domain);
             UserTokenPayload data = new UserTokenPayload();
             data.setPreferredUsername(username);
index ec685a0..3cb7975 100644 (file)
@@ -33,9 +33,11 @@ import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
 import java.util.Base64;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Optional;
+import java.util.stream.Collectors;
 import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
@@ -52,16 +54,13 @@ import org.slf4j.LoggerFactory;
 public abstract class AuthService {
 
 
-    private static final Logger LOG = LoggerFactory.getLogger(AuthService.class.getName());
+    private static final Logger LOG = LoggerFactory.getLogger(AuthService.class);
     private final MappingBaseHttpClient httpClient;
     protected final ObjectMapper mapper;
     protected final OAuthProviderConfig config;
     protected final TokenCreator tokenCreator;
     private final String redirectUri;
-    private String localHostUrl;
-    public void setLocalHostUrl(String url) {
-        this.localHostUrl = url;
-    }
+
     protected abstract String getTokenVerifierUri();
 
     protected abstract Map<String, String> getAdditionalTokenVerifierParams();
@@ -75,23 +74,31 @@ public abstract class AuthService {
 
     protected abstract String getLoginUrl(String callbackUrl);
 
+    protected abstract UserTokenPayload requestUserRoles(String access_token, long expires_at);
+
+    protected abstract boolean verifyState(String state);
+
     public AuthService(OAuthProviderConfig config, String redirectUri, TokenCreator tokenCreator) {
         this.config = config;
         this.tokenCreator = tokenCreator;
         this.redirectUri = redirectUri;
         this.mapper = new ObjectMapper();
         this.mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
-        this.httpClient = new MappingBaseHttpClient(this.config.getHost());
+        this.httpClient = new MappingBaseHttpClient(this.config.getUrl());
     }
 
-    public PublicOAuthProviderConfig getConfig(String host) {
-        return new PublicOAuthProviderConfig(this, host);
+    public PublicOAuthProviderConfig getConfig() {
+        return new PublicOAuthProviderConfig(this);
     }
 
-    public void handleRedirect(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+    protected MappingBaseHttpClient getHttpClient() {
+        return this.httpClient;
+    }
+
+    public void handleRedirect(HttpServletRequest req, HttpServletResponse resp, String host) throws IOException {
         switch (this.getResponseType()) {
             case CODE:
-                this.handleRedirectCode(req, resp);
+                this.handleRedirectCode(req, resp, host);
                 break;
             case TOKEN:
                 sendErrorResponse(resp, "not yet implemented");
@@ -99,39 +106,56 @@ public abstract class AuthService {
             case SESSION_STATE:
                 break;
         }
+    }
 
+    public void sendLoginRedirectResponse(HttpServletResponse resp, String callbackUrl) {
+        resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+        resp.setHeader("Location", this.getLoginUrl(callbackUrl));
     }
 
     private static void sendErrorResponse(HttpServletResponse resp, String message) throws IOException {
         resp.sendError(HttpServletResponse.SC_NOT_FOUND, message);
-
     }
 
-    private void handleRedirectCode(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+    private void handleRedirectCode(HttpServletRequest req, HttpServletResponse resp, String host) throws IOException {
         final String code = req.getParameter("code");
-        OAuthResponseData response = this.getTokenForUser(code);
+        final String state = req.getParameter("state");
+        OAuthResponseData response = null;
+        if(this.verifyState(state)) {
+            response = this.getTokenForUser(code, host);
+        }
         if (response != null) {
             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);
+                if (data != null) {
+                    this.handleUserInfoToken(data, resp, host);
+                } else {
+                    sendErrorResponse(resp, "unable to verify user");
+                }
             } else {
-                this.handleUserInfoToken(response.getAccess_token(), resp);
+                this.handleUserInfoToken(response.getAccess_token(), resp, host);
             }
         } else {
             sendErrorResponse(resp, "unable to verify code");
         }
+    }
 
+    private void handleUserInfoToken(UserTokenPayload data, HttpServletResponse resp, String localHostUrl)
+            throws IOException {
+        BearerToken onapToken = this.tokenCreator.createNewJWT(data);
+        sendTokenResponse(resp, onapToken, localHostUrl);
     }
 
-    private void handleUserInfoToken(String accessToken, HttpServletResponse resp) throws IOException {
+    private void handleUserInfoToken(String accessToken, HttpServletResponse resp, String localHostUrl)
+            throws IOException {
         try {
             DecodedJWT jwt = JWT.decode(accessToken);
-
             String spayload = base64Decode(jwt.getPayload());
-            LOG.debug("payload in jwt from keycload='{}'", spayload);
-
+            LOG.debug("payload in jwt='{}'", spayload);
             UserTokenPayload data = this.mapAccessToken(spayload);
-            BearerToken onapToken = this.tokenCreator.createNewJWT(data);
-            sendTokenResponse(resp, onapToken);
+            this.handleUserInfoToken(data, resp, localHostUrl);
         } catch (JWTDecodeException | JsonProcessingException e) {
             LOG.warn("unable to decode jwt token {}: ", accessToken, e);
             sendErrorResponse(resp, e.getMessage());
@@ -139,7 +163,12 @@ public abstract class AuthService {
     }
 
 
-    private void sendTokenResponse(HttpServletResponse resp, BearerToken data) throws IOException {
+    protected List<String> mapRoles(List<String> roles) {
+        final Map<String, String> map = this.config.getRoleMapping();
+        return roles.stream().map(r -> map.getOrDefault(r, r)).collect(Collectors.toList());
+    }
+
+    private void sendTokenResponse(HttpServletResponse resp, BearerToken data, String localHostUrl) throws IOException {
         if (this.redirectUri == null) {
             byte[] output = data != null ? mapper.writeValueAsString(data).getBytes() : new byte[0];
             resp.setStatus(200);
@@ -150,7 +179,7 @@ public abstract class AuthService {
             os.write(output);
         } else {
             resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
-            resp.setHeader("Location", assembleUrl(this.localHostUrl, this.redirectUri, data.getToken()));
+            resp.setHeader("Location", assembleUrl(localHostUrl, this.redirectUri, data.getToken()));
         }
     }
 
@@ -160,7 +189,7 @@ public abstract class AuthService {
         return new String(Base64.getDecoder().decode(data), StandardCharsets.UTF_8);
     }
 
-    private OAuthResponseData getTokenForUser(String code) {
+    private OAuthResponseData getTokenForUser(String code, String localHostUrl) {
 
         Map<String, String> headers = new HashMap<>();
         headers.put("Content-Type", "application/x-www-form-urlencoded");
@@ -168,15 +197,15 @@ public abstract class AuthService {
         params.put("code", code);
         params.put("client_id", this.config.getClientId());
         params.put("client_secret", this.config.getSecret());
-        params.put("redirect_uri",
-                assembleRedirectUrl(localHostUrl, AuthHttpServlet.REDIRECTURI, this.config.getId()));
+        params.put("redirect_uri", assembleRedirectUrl(localHostUrl, AuthHttpServlet.REDIRECTURI, this.config.getId()));
         StringBuilder body = new StringBuilder();
         for (Entry<String, String> p : params.entrySet()) {
             body.append(String.format("%s=%s&", p.getKey(), urlEncode(p.getValue())));
         }
 
-        Optional<MappedBaseHttpResponse<OAuthResponseData>> response = this.httpClient.sendMappedRequest(this.getTokenVerifierUri(),
-                "POST", body.substring(0, body.length() - 1), headers, OAuthResponseData.class);
+        Optional<MappedBaseHttpResponse<OAuthResponseData>> response =
+                this.httpClient.sendMappedRequest(this.getTokenVerifierUri(), "POST",
+                        body.substring(0, body.length() - 1), headers, OAuthResponseData.class);
         if (response.isPresent() && response.get().isSuccess()) {
             return response.get().body;
         }
@@ -185,8 +214,6 @@ public abstract class AuthService {
         return null;
     }
 
-
-
     /**
      * Assemble callback url for service provider {host}{baseUri}/{serviceId} e.g.
      * http://10.20.0.11:8181/oauth/redirect/keycloak
@@ -243,11 +270,10 @@ public abstract class AuthService {
             this.loginUrl = loginUrl;
         }
 
-        public PublicOAuthProviderConfig(AuthService authService, String host) {
+        public PublicOAuthProviderConfig(AuthService authService) {
             this.id = authService.config.getId();
             this.title = authService.config.getTitle();
-            this.loginUrl = authService.getLoginUrl(
-                    assembleRedirectUrl(host, AuthHttpServlet.REDIRECTURI, this.id));
+            this.loginUrl = String.format(AuthHttpServlet.LOGIN_REDIRECT_FORMAT, authService.config.getId());
         }
 
     }
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/GitlabProviderService.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/GitlabProviderService.java
new file mode 100644 (file)
index 0000000..4a8bdfa
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2021 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 com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+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.data.UserTokenPayload;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.client.MappedBaseHttpResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class GitlabProviderService extends AuthService {
+
+    private static final Logger LOG = LoggerFactory.getLogger(GitlabProviderService.class);
+    private Map<String, String> additionalTokenVerifierParams;
+    protected final List<String> randomIds;
+    private static final String API_USER_URI = "/api/v4/user";
+    private static final String API_GROUP_URI = "/api/v4/groups?min_access_level=10";
+
+    public GitlabProviderService(OAuthProviderConfig config, String redirectUri, TokenCreator tokenCreator) {
+        super(config, redirectUri, tokenCreator);
+        this.additionalTokenVerifierParams = new HashMap<>();
+        this.additionalTokenVerifierParams.put("grant_type", "authorization_code");
+        this.randomIds = new ArrayList<>();
+    }
+
+    @Override
+    protected String getTokenVerifierUri() {
+        return "/oauth/token";
+    }
+
+    @Override
+    protected String getLoginUrl(String callbackUrl) {
+        return String.format("%s/oauth/authorize?client_id=%s&response_type=code&state=%s&redirect_uri=%s",
+                this.config.getUrl(), urlEncode(this.config.getClientId()), this.createRandomId(), callbackUrl);
+    }
+
+    private String createRandomId() {
+        String rnd = null;
+        while(true) {
+            rnd=Config.generateSecret(20);
+            if(!this.randomIds.contains(rnd)) {
+                break;
+            }
+        }
+        this.randomIds.add(rnd);
+        return rnd;
+    }
+
+    @Override
+    protected ResponseType getResponseType() {
+        return ResponseType.CODE;
+    }
+
+    @Override
+    protected Map<String, String> getAdditionalTokenVerifierParams() {
+        return this.additionalTokenVerifierParams;
+
+    }
+
+    @Override
+    protected boolean doSeperateRolesRequest() {
+        return true;
+    }
+
+    @Override
+    protected UserTokenPayload mapAccessToken(String spayload) throws JsonMappingException, JsonProcessingException {
+        return null;
+    }
+
+    @Override
+    protected UserTokenPayload requestUserRoles(String access_token, 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));
+        Optional<MappedBaseHttpResponse<GitlabUserInfo>> userInfo =
+                this.getHttpClient().sendMappedRequest(API_USER_URI, "GET", null, authHeaders, GitlabUserInfo.class);
+        if (userInfo.isEmpty()) {
+            LOG.warn("unable to read user data");
+            return null;
+        }
+        Optional<MappedBaseHttpResponse<GitlabGroupInfo[]>> groupInfos = this.getHttpClient()
+                .sendMappedRequest(API_GROUP_URI, "GET", null, authHeaders, GitlabGroupInfo[].class);
+        if (groupInfos.isEmpty()) {
+            LOG.warn("unable to read group information for user");
+            return null;
+        }
+        UserTokenPayload data = new UserTokenPayload();
+        GitlabUserInfo uInfo = userInfo.get().body;
+        data.setPreferredUsername(uInfo.getUsername());
+        data.setGivenName(uInfo.getName());
+        data.setFamilyName(uInfo.getName());
+        data.setExp(expires_at);
+        List<String> roles = new ArrayList<>();
+        GitlabGroupInfo[] uRoles = groupInfos.get().body;
+        for (GitlabGroupInfo uRole : uRoles) {
+            roles.add(uRole.getName());
+        }
+        data.setRoles(this.mapRoles(roles));
+        return data;
+    }
+
+
+
+    @SuppressWarnings("unused")
+    private static class GitlabUserInfo {
+
+        private String username;
+        private String name;
+
+        public String getUsername() {
+            return username;
+        }
+
+        public void setUsername(String username) {
+            this.username = username;
+        }
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+    @SuppressWarnings("unused")
+    private static class GitlabGroupInfo {
+        private String name;
+
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+    }
+    @Override
+    protected boolean verifyState(String state) {
+        if(this.randomIds.contains(state)) {
+            this.randomIds.remove(state);
+            return true;
+        }
+        return false;
+    }
+}
index 3bfbb3b..86383c9 100644 (file)
@@ -51,17 +51,16 @@ public class KeycloakProviderService extends AuthService {
     protected String getLoginUrl(String callbackUrl) {
         return String.format(
                 "%s/auth/realms/onap/protocol/openid-connect/auth?client_id=%s&response_type=code&scope=%s&redirect_uri=%s",
-                this.config.getHost(), urlEncode(this.config.getClientId()), this.config.getScope(),
+                this.config.getUrl(), urlEncode(this.config.getClientId()), this.config.getScope(),
                 urlEncode(callbackUrl));
     }
 
-
-
-    private List<String> mapRoles(List<String> data) {
-
+    @Override
+    protected List<String> mapRoles(List<String> data) {
+        final Map<String,String> map = this.config.getRoleMapping();
         List<String> filteredRoles =
                 data.stream().filter(role -> !role.equals("uma_authorization") && !role.equals("offline_access"))
-                        .map(r -> r).collect(Collectors.toList());
+                        .map(r -> map.getOrDefault(r, r)).collect(Collectors.toList());
         return filteredRoles;
     }
 
@@ -93,5 +92,15 @@ public class KeycloakProviderService extends AuthService {
         return data;
     }
 
+    @Override
+    protected UserTokenPayload requestUserRoles(String access_token, long expires_at) {
+        return null;
+    }
+
+    @Override
+    protected boolean verifyState(String state) {
+        return true;
+    }
+
 
 }
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/MdSalAuthorizationStore.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/MdSalAuthorizationStore.java
new file mode 100644 (file)
index 0000000..b181af0
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2021 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.util.List;
+import java.util.Optional;
+import java.util.concurrent.ExecutionException;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlPolicy;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlPolicy.PolicyMethods;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.HttpAuthorization;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.authorization.Policies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.permission.Permissions;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.permission.Permissions.Actions;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MdSalAuthorizationStore {
+
+    private static final Logger LOG = LoggerFactory.getLogger(MdSalAuthorizationStore.class.getName());
+
+    private final DataBroker dataBroker;
+
+    public MdSalAuthorizationStore(DataBroker dataBroker) {
+        this.dataBroker = dataBroker;
+    }
+
+    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 {
+            odata = this.dataBroker.newReadOnlyTransaction().read(LogicalDatastoreType.CONFIGURATION, iif).get();
+        } catch (InterruptedException | ExecutionException e) {
+            LOG.warn("unable to read policies from mdsal: ", e);
+        }
+        if (odata.isEmpty()) {
+            return Optional.empty();
+        }
+
+        Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.authorization.policies.Policies> entry =
+                odata.get().getPolicies().stream().filter((e) -> path.equals(e.getResource())).findFirst();
+        if (entry.isEmpty()) {
+            return Optional.empty();
+        }
+        List<Permissions> permissions = entry.get().getPermissions();
+        if (permissions == null) {
+            return Optional.empty();
+        }
+        Optional<Permissions> rolePm = permissions.stream().filter((e) -> userRoles.contains(e.getRole())).findFirst();
+        if (rolePm.isEmpty()) {
+            return Optional.empty();
+        }
+        return Optional.of(mapPolicy(path, rolePm.get().getActions()));
+    }
+
+    private OdlPolicy mapPolicy(String path, List<Actions> actions) {
+        PolicyMethods methods = new PolicyMethods();
+        String action;
+        for (Actions a : actions) {
+            action = a.getName().toLowerCase();
+            switch (action) {
+                case "get":
+                    methods.setGet(true);
+                    break;
+                case "post":
+                    methods.setPost(true);
+                    break;
+                case "put":
+                    methods.setPut(true);
+                    break;
+                case "delete":
+                    methods.setDelete(true);
+                    break;
+                case "patch":
+                    methods.setPatch(true);
+                    break;
+                default:
+                    LOG.warn("unknown http method {}",action);
+                    break;
+            }
+        }
+        return new OdlPolicy(path, methods);
+    }
+
+}
index ad1da68..03b0f4f 100644 (file)
@@ -70,4 +70,16 @@ public class NextcloudProviderService extends AuthService {
         return null;
     }
 
+    @Override
+    protected UserTokenPayload requestUserRoles(String access_token, long expires_at) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    protected boolean verifyState(String state) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
 }
\ No newline at end of file
index a09f150..193e7a7 100644 (file)
@@ -33,12 +33,14 @@ public class OAuthProviderFactory {
                 return new KeycloakProviderService(config, redirectUri, tokenCreator);
             case NEXTCLOUD:
                 return new NextcloudProviderService(config, redirectUri, tokenCreator);
+            case GITLAB:
+                return new GitlabProviderService(config, redirectUri, tokenCreator);
         }
         return null;
     }
 
     public static enum OAuthProvider {
-        KEYCLOAK, NEXTCLOUD
+        KEYCLOAK, NEXTCLOUD, GITLAB
     }
 
 }
index 3244f90..e7e9b72 100644 (file)
@@ -41,28 +41,38 @@ public class TokenCreator {
 
     private static final Logger LOG = LoggerFactory.getLogger(AuthHttpServlet.class.getName());
     private static final long DEFAULT_TOKEN_LIFETIME_MS = 30 * 60 * 1000;
-    private static final String TOKEN_ISSUER = Config.getProperty("${TOKEN_ISSUER}", "ONAP SDNC");
+    private final String issuer;
     private static TokenCreator _instance;
-    private static final String SECRET = Config.getProperty("${TOKEN_SECRET}", "secret");
+    private final String secret;
 
     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() {
+    public static TokenCreator getInstance(Config config) {
         if (_instance == null) {
-            _instance = new TokenCreator();
+            _instance = new TokenCreator(config);
+        }
+        return _instance;
+    }
+    public static TokenCreator getInstance(String secret, String issuer) {
+        if (_instance == null) {
+            _instance = new TokenCreator(secret, issuer);
         }
         return _instance;
     }
 
-    private TokenCreator() {
-
+    private TokenCreator(Config config) {
+        this(config.getTokenSecret(),config.getTokenIssuer());
+    }
+    private TokenCreator(String secret, String issuer) {
+        this.secret = secret;
+        this.issuer = issuer;
     }
 
     public BearerToken createNewJWT(UserTokenPayload data) {
-        Algorithm algorithm = Algorithm.HMAC256(SECRET);
-        final String token = JWT.create().withIssuer(TOKEN_ISSUER).withExpiresAt(new Date(data.getExp()))
+        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())
                 .withArrayClaim(ROLES_CLAIM, data.getRoles().toArray(new String[data.getRoles().size()]))
@@ -74,8 +84,8 @@ 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(TOKEN_ISSUER).build();
+            Algorithm algorithm = Algorithm.HMAC256(secret);
+            JWTVerifier verifier = JWT.require(algorithm).withIssuer(issuer).build();
             jwt = verifier.verify(token);
 
         } catch (JWTVerificationException e) {
@@ -88,6 +98,10 @@ public class TokenCreator {
         return new Date().getTime() + DEFAULT_TOKEN_LIFETIME_MS;
     }
 
+    public long getDefaultExp(long exp_in) {
+        return new Date().getTime() + exp_in;
+    }
+
     public UserTokenPayload decode(HttpServletRequest req) throws JWTDecodeException {
         final String authHeader = req.getHeader("Authorization");
         if (authHeader == null || !authHeader.startsWith("Bearer")) {
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestAuthHttpServlet.java b/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestAuthHttpServlet.java
new file mode 100644 (file)
index 0000000..bf2a39b
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2021 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.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.google.common.util.concurrent.FluentFuture;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.jolokia.osgi.security.Authenticator;
+import org.json.JSONArray;
+import org.junit.BeforeClass;
+import org.junit.Test;
+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.OdlPolicy;
+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.HeadersOnlyHttpServletRequest;
+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.opendaylight.aaa.shiro.filters.backport.BearerToken;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.ReadTransaction;
+import org.opendaylight.mdsal.common.api.LogicalDatastoreType;
+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.ShiroConfigurationBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.HttpAuthorization;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.authorization.Policies;
+import org.opendaylight.yangtools.util.concurrent.FluentFutures;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+
+
+public class TestAuthHttpServlet {
+
+    private static final String TESTCONFIGFILE = TestConfig.TEST_CONFIG_FILENAME;
+    private static final String TESTSHIROCONFIGFILE = "src/test/resources/aaa-app-config.test.xml";
+    private static final String MDSALDYNAUTHFILENAME = "src/test/resources/mdsalDynAuthData.json";
+    private static TestServlet servlet;
+    private static DataBroker dataBroker = loadDynamicMdsalAuthDataBroker();
+    private static Authenticator odlAuthenticator = mock(Authenticator.class);
+    private static IdMService odlIdentityService = mock(IdMService.class);
+    private static ShiroConfiguration shiroConfiguration = null;
+    private static TokenCreator tokenCreator;
+//    private static final HttpServletRequest authreq = new HeadersOnlyHttpServletRequest(
+//            Map.of("Authorization", BaseHTTPClient.getAuthorizationHeaderValue("admin@sdn", "admin")));
+
+    @BeforeClass
+    public static void init() {
+
+        try {
+            Config config = createConfigFile();
+            tokenCreator = TokenCreator.getInstance(config);
+            servlet = new TestServlet();
+            shiroConfiguration = loadShiroConfig(TESTSHIROCONFIGFILE);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        servlet.setDataBroker(dataBroker);
+        servlet.setOdlAuthenticator(odlAuthenticator);
+        servlet.setOdlIdentityService(odlIdentityService);
+        servlet.setShiroConfiguration(shiroConfiguration);
+    }
+
+    private static DataBroker loadDynamicMdsalAuthDataBroker() {
+        DataBroker dataBroker = mock(DataBroker.class);
+        ReadTransaction rotx = mock(ReadTransaction.class);
+        InstanceIdentifier<Policies> iif = InstanceIdentifier.create(HttpAuthorization.class).child(Policies.class);
+        try {
+            when(rotx.read(LogicalDatastoreType.CONFIGURATION, iif))
+                    .thenReturn(loadDataBrokerFile(MDSALDYNAUTHFILENAME, Policies.class));
+        } catch (IOException e) {
+            fail("problem init databroker read" + e.getMessage());
+        }
+        when(dataBroker.newReadOnlyTransaction()).thenReturn(rotx);
+        return dataBroker;
+    }
+
+    private static <T> FluentFuture<Optional<T>> loadDataBrokerFile(String fn, Class<T> clazz) throws IOException {
+        return FluentFutures.immediateFluentFuture(Optional.ofNullable(readJson(new File(fn), clazz)));
+    }
+
+    private static ShiroConfiguration loadShiroConfig(String filename)
+            throws JsonParseException, JsonMappingException, IOException {
+        OdlXmlMapper mapper = new OdlXmlMapper();
+        return mapper.readValue(new File(filename), ShiroConfigurationBuilder.class).build();
+    }
+
+    private static Config createConfigFile() throws IOException {
+        return Config.getInstance(TESTCONFIGFILE);
+
+    }
+
+    @Test
+    public void testValidLoginRedirect() {
+
+        HttpServletRequest req = mock(HttpServletRequest.class);
+        when(req.getRequestURI()).thenReturn("/oauth/login/keycloak");
+        HttpServletResponse resp = mock(HttpServletResponse.class);
+        try {
+            servlet.doGet(req, resp);
+        } catch (ServletException | IOException e) {
+            fail(e.getMessage());
+        }
+        verify(resp).setStatus(302);
+        verify(resp).setHeader("Location",
+                "http://10.20.11.160:8080/auth/realms/onap/protocol/openid-connect/auth?client_id=odlux.app&response"
+                        + "_type=code&scope=openid&redirect_uri=http%3A%2F%2Fnasp.diasf.de%2Foauth%2Fredirect%2Fkeycloak");
+    }
+
+    @Test
+    public void testInValidLoginRedirect() {
+
+        HttpServletRequest req = mock(HttpServletRequest.class);
+        when(req.getRequestURI()).thenReturn("/oauth/login/unknownproviderid");
+        HttpServletResponse resp = mock(HttpServletResponse.class);
+        ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
+        try {
+            when(resp.getOutputStream()).thenReturn(printOut);
+            servlet.doGet(req, resp);
+        } catch (ServletException | IOException e) {
+            fail(e.getMessage());
+        }
+        verify(resp).setStatus(404);
+    }
+
+    @Test
+    public void testValidLogin() {
+
+        HttpServletRequest req = mock(HttpServletRequest.class);
+        when(req.getRequestURI()).thenReturn("/oauth/login");
+        when(req.getParameter("username")).thenReturn("admin");
+        when(req.getParameter("password")).thenReturn("admin");
+        when(odlAuthenticator.authenticate(any(HeadersOnlyHttpServletRequest.class))).thenReturn(true);
+        HttpServletResponse resp = mock(HttpServletResponse.class);
+        ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
+        try {
+            when(resp.getOutputStream()).thenReturn(printOut);
+            servlet.doPost(req, resp);
+        } catch (ServletException | IOException e) {
+            fail(e.getMessage());
+        }
+        verify(resp).setStatus(200);
+    }
+
+    @Test
+    public void testGetProviders() {
+
+        HttpServletRequest req = mock(HttpServletRequest.class);
+        when(req.getRequestURI()).thenReturn("/oauth/providers");
+        HttpServletResponse resp = mock(HttpServletResponse.class);
+        ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
+        try {
+            when(resp.getOutputStream()).thenReturn(printOut);
+            servlet.doGet(req, resp);
+        } catch (ServletException | IOException e) {
+            fail(e.getMessage());
+        }
+        verify(resp).setStatus(200);
+        String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
+        System.out.println(responseBody);
+        JSONArray a = new JSONArray(responseBody);
+        assertEquals(1, a.length());
+        assertEquals("keycloak", a.getJSONObject(0).getString("id"));
+        assertEquals("OSNL Keycloak Provider", a.getJSONObject(0).getString("title"));
+        assertEquals("/oauth/login/keycloak", a.getJSONObject(0).getString("loginUrl"));
+
+    }
+
+    @Test
+    public void testPoliciesAnon() {
+
+        HttpServletRequest req = mock(HttpServletRequest.class);
+        when(req.getRequestURI()).thenReturn("/oauth/policies");
+        HttpServletResponse resp = mock(HttpServletResponse.class);
+        ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
+        try {
+            when(resp.getOutputStream()).thenReturn(printOut);
+            servlet.doGet(req, resp);
+        } catch (ServletException | IOException e) {
+            fail(e.getMessage());
+        }
+        verify(resp).setStatus(200);
+        String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
+        System.out.println(responseBody);
+        OdlPolicy[] anonPolicies = null;
+        try {
+            anonPolicies = readJson(responseBody, OdlPolicy[].class);
+        } catch (JsonProcessingException e) {
+            fail("unable to read anon policies response");
+        }
+        assertEquals(9, anonPolicies.length);
+        OdlPolicy pApidoc = find(anonPolicies, "/apidoc/**");
+        assertNotNull(pApidoc);
+        assertAllEquals(false, pApidoc);
+        OdlPolicy pOauth = find(anonPolicies, "/oauth/**");
+        assertNotNull(pOauth);
+        assertAllEquals(true, pOauth);
+        OdlPolicy pRestconf = find(anonPolicies, "/rests/**");
+        assertNotNull(pRestconf);
+        assertAllEquals(false, pRestconf);
+    }
+
+    @Test
+    public void testPoliciesBasicAuth() {
+
+        HttpServletRequest req = mock(HttpServletRequest.class);
+        when(req.getRequestURI()).thenReturn("/oauth/policies");
+        when(req.getHeader("Authorization")).thenReturn(BaseHTTPClient.getAuthorizationHeaderValue("admin", "admin"));
+        when(odlIdentityService.listRoles("admin@sdn", "sdn")).thenReturn(Arrays.asList("admin"));
+        HttpServletResponse resp = mock(HttpServletResponse.class);
+        ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
+        try {
+            when(resp.getOutputStream()).thenReturn(printOut);
+            servlet.doGet(req, resp);
+        } catch (ServletException | IOException e) {
+            fail(e.getMessage());
+        }
+        verify(resp).setStatus(200);
+        String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
+        System.out.println(responseBody);
+        OdlPolicy[] anonPolicies = null;
+        try {
+            anonPolicies = readJson(responseBody, OdlPolicy[].class);
+        } catch (JsonProcessingException e) {
+            fail("unable to read anon policies response");
+        }
+        assertEquals(9, anonPolicies.length);
+        OdlPolicy pApidoc = find(anonPolicies, "/apidoc/**");
+        assertNotNull(pApidoc);
+        assertAllEquals(true, pApidoc);
+        OdlPolicy pOauth = find(anonPolicies, "/oauth/**");
+        assertNotNull(pOauth);
+        assertAllEquals(true, pOauth);
+        OdlPolicy pRestconf = find(anonPolicies, "/rests/**");
+        assertNotNull(pRestconf);
+        assertAllEquals(true, pRestconf);
+    }
+
+    @Test
+    public void testPoliciesBearer() {
+        HttpServletRequest req = mock(HttpServletRequest.class);
+        when(req.getRequestURI()).thenReturn("/oauth/policies");
+        String token = createToken("admin", Arrays.asList("admin", "provision")).getToken();
+        when(req.getHeader("Authorization")).thenReturn(String.format("Bearer %s", token));
+        HttpServletResponse resp = mock(HttpServletResponse.class);
+        ServletOutputStreamToByteArrayOutputStream printOut = new ServletOutputStreamToByteArrayOutputStream();
+        try {
+            when(resp.getOutputStream()).thenReturn(printOut);
+            servlet.doGet(req, resp);
+        } catch (ServletException | IOException e) {
+            fail(e.getMessage());
+        }
+        verify(resp).setStatus(200);
+        String responseBody = printOut.getByteArrayOutputStream().toString(StandardCharsets.UTF_8);
+        System.out.println(responseBody);
+        OdlPolicy[] anonPolicies = null;
+        try {
+            anonPolicies = readJson(responseBody, OdlPolicy[].class);
+        } catch (JsonProcessingException e) {
+            fail("unable to read anon policies response");
+        }
+        assertEquals(9, anonPolicies.length);
+        OdlPolicy pApidoc = find(anonPolicies, "/apidoc/**");
+        assertNotNull(pApidoc);
+        assertAllEquals(false, pApidoc);
+        OdlPolicy pOauth = find(anonPolicies, "/oauth/**");
+        assertNotNull(pOauth);
+        assertAllEquals(true, pOauth);
+        OdlPolicy pRestconf = find(anonPolicies, "/rests/**");
+        assertNotNull(pRestconf);
+        assertAllEquals(true, pRestconf);
+    }
+
+    private static BearerToken createToken(String username, List<String> roles) {
+        UserTokenPayload data = new UserTokenPayload();
+        data.setPreferredUsername(username);
+        data.setFamilyName("");
+        data.setGivenName(username);
+        data.setExp(tokenCreator.getDefaultExp());
+        data.setRoles(roles);
+        return tokenCreator.createNewJWT(data);
+    }
+
+    private static void assertAllEquals(boolean b, OdlPolicy p) {
+        assertEquals(b, p.getMethods().isGet());
+        assertEquals(b, p.getMethods().isPost());
+        assertEquals(b, p.getMethods().isPut());
+        assertEquals(b, p.getMethods().isDelete());
+        assertEquals(b, p.getMethods().isPatch());
+    }
+
+    private static OdlPolicy find(OdlPolicy[] policies, String path) {
+        for (OdlPolicy p : policies) {
+            if (path.equals(p.getPath())) {
+                return p;
+            }
+        }
+        return null;
+    }
+
+    private static <T> T readJson(String data, Class<T> clazz) throws JsonMappingException, JsonProcessingException {
+        CustomObjectMapper mapper = new CustomObjectMapper();
+        return mapper.readValue(data, clazz);
+    }
+
+    private static <T> T readJson(File file, Class<T> clazz) throws IOException {
+        OdlJsonMapper mapper = new OdlJsonMapper();
+        return mapper.readValue(file, clazz);
+    }
+
+    private static class TestServlet extends AuthHttpServlet {
+
+        private static final long serialVersionUID = 1L;
+
+        public TestServlet() throws IOException {
+            super();
+        }
+
+        @Override
+        public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+            super.doGet(req, resp);
+        }
+
+        @Override
+        public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+            super.doPost(req, resp);
+        }
+    }
+}
index 2b88141..d07950d 100644 (file)
@@ -27,10 +27,19 @@ import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
 
 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";
     @Test
     public void test() throws IOException {
 
-        Config config = Config.load("src/test/resources/test.config.json");
+        Config config = Config.load(TEST_CONFIG_FILENAME);
         System.out.println("config="+config);
     }
+    @Test
+    public void testOom() throws IOException {
+
+        Config config = Config.load(TEST_OOMCONFIG_FILENAME);
+        System.out.println("config="+config);
+
+    }
 }
index 236c0ff..65ef2cb 100644 (file)
@@ -28,6 +28,7 @@ import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import java.io.IOException;
 import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.common.http.BaseHTTPResponse;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.KeycloakUserTokenPayload;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthResponseData;
 import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.client.MappedBaseHttpResponse;
@@ -50,7 +51,8 @@ public class TestDeserializer {
                         + "U5IiwiaXNzIjoiaHR0cDovLzEwLjIwLjExLjE2MDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6Imh0dHA6Ly8xMC4yMC4xMS4xNjA6ODA4MC9hdXRoL3JlYWxtcy9tYXN0ZXIiLCJzdWIiOiIxODM4YzRmMi01ZmUzLTRmMGMtYjJkMi1kMzY0YjI3YTQ5OTciLCJ0eXAiOiJSZWZyZXNoIiwiYXpwIjoiYWRtaW4tY2xpIiwic2Vzc2lvbl9zdGF0ZSI6I"
                         + "mNjNzFmYzFmLWFkZDQtNGE4Ni1hZTVlLWMzNGRmNDAzYzc3MiIsInNjb3BlIjoiZW1haWwgcHJvZmlsZSJ9.qutqcFuQW-GzaCVNMfiYrbmHYD34GYwBqIbaQbJSY-g\",\"token_type\":\"bearer\",\"not-before-policy\":0,\"session_state\":\"cc71fc1f-add4-4a86-ae5e-c34df403c772\",\"scope\":\"email profile\"} ";
 
-        OAuthResponseData data = new MappedBaseHttpResponse<>(200,response,OAuthResponseData.class).body;
+        BaseHTTPResponse res = new BaseHTTPResponse(200, response);
+        OAuthResponseData data = new MappedBaseHttpResponse<>(res,OAuthResponseData.class).body;
         assertEquals(token,data.getAccess_token());
 
     }
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestGitlabAuthService.java b/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestGitlabAuthService.java
new file mode 100644 (file)
index 0000000..fb93800
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2021 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 static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.nio.file.Files;
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import javax.servlet.http.HttpServletRequest;
+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.OAuthProviderConfig;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.GitlabProviderService;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
+
+public class TestGitlabAuthService {
+
+    private static HttpServer server;
+    private static ExecutorService httpThreadPool;
+    private static GitlabProviderServiceToTest oauthService;
+    private static final int PORT = randomPort(50000, 55000);
+    private static final String GITURL = String.format("http://127.0.0.1:%d", PORT);
+    private static final String OAUTH_SECRET = "oauthsecret";
+    private static final String TOKENCREATOR_SECRET = "secret";
+    private static final String REDIRECT_URI = "/odlux/token?";
+
+    @BeforeClass
+    public static void init() {
+
+        TokenCreator tokenCreator = TokenCreator.getInstance(TOKENCREATOR_SECRET, "issuer");
+        OAuthProviderConfig config =
+                new OAuthProviderConfig("git", GITURL, "odlux.app", OAUTH_SECRET, "openid", "gitlab test");
+        oauthService = new GitlabProviderServiceToTest(config, REDIRECT_URI, tokenCreator);
+        try {
+            initGitlabTestWebserver(PORT, "/");
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @AfterClass
+    public static void close() {
+        stopTestWebserver();
+    }
+
+    @Test
+    public void test() {
+        HttpServletRequest req;
+        HttpServletResponse resp = null;
+        String host = "http://localhost:8412";
+        final String state = "stateabc";
+        try {
+            req = mock(HttpServletRequest.class);
+            resp = mock(HttpServletResponse.class);
+            when(req.getParameter("code")).thenReturn("abcdefg");
+            when(req.getParameter("state")).thenReturn(state);
+            oauthService.addState(state);
+            oauthService.handleRedirect(req, resp, host);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        verify(resp).setStatus(302);
+        //verify(resp).setHeader("Location",any(String.class));
+    }
+
+    public void test2() {
+        oauthService.sendLoginRedirectResponse(null, null);
+    }
+
+    public static class GitlabProviderServiceToTest extends GitlabProviderService {
+
+        public GitlabProviderServiceToTest(OAuthProviderConfig config, String redirectUri, TokenCreator tokenCreator) {
+            super(config, redirectUri, tokenCreator);
+        }
+
+        public void addState(String state) {
+            this.randomIds.add(state);
+        }
+    }
+
+    private static int randomPort(int min, int max) {
+        Random random = new Random();
+        return random.nextInt(max + 1 - min) + min;
+    }
+
+    public static void initGitlabTestWebserver(int port, String baseUri) throws IOException {
+        server = HttpServer.create(new InetSocketAddress("127.0.0.1", port), 0);
+        httpThreadPool = Executors.newFixedThreadPool(5);
+        server.setExecutor(httpThreadPool);
+        server.createContext(baseUri, new MyHandler());
+        //server.createContext("/", new MyRootHandler());
+        server.setExecutor(null); // creates a default executor
+        server.start();
+        System.out.println("http server started");
+    }
+
+    public static void stopTestWebserver() {
+        if (server != null) {
+            server.stop(0);
+            httpThreadPool.shutdownNow();
+            System.out.println("http server stopped");
+        }
+    }
+
+    private static String loadResourceFileContent(String filename) {
+        try {
+            return Files.readString(new File(filename).toPath());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        return null;
+    }
+    public static class MyHandler implements HttpHandler {
+        private static final String GITLAB_TOKEN_ENDPOINT = "/oauth/token";
+        private static final String GITLAB_USER_ENDPOINT = "/api/v4/user";
+        private static final String GITLAB_GROUP_ENDPOINT = "/api/v4/groups?min_access_level=10";
+        private static final String GITLAB_TOKEN_RESPONSE = loadResourceFileContent("src/test/resources/oauth/gitlab-token-response.json");
+        private static final String GITLAB_USER_RESPONSE =loadResourceFileContent("src/test/resources/oauth/gitlab-user-response.json");
+        private static final String GITLAB_GROUP_RESPONSE =loadResourceFileContent("src/test/resources/oauth/gitlab-groups-response.json");
+
+        @Override
+        public void handle(HttpExchange t) throws IOException {
+            final String method = t.getRequestMethod();
+            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)) {
+                        t.sendResponseHeaders(200, GITLAB_USER_RESPONSE.length());
+                        os = t.getResponseBody();
+                        os.write(GITLAB_USER_RESPONSE.getBytes());
+                    }
+                    else if(uri.equals(GITLAB_GROUP_ENDPOINT)) {
+                        t.sendResponseHeaders(200, GITLAB_GROUP_RESPONSE.length());
+                        os = t.getResponseBody();
+                        os.write(GITLAB_GROUP_RESPONSE.getBytes());
+                    }
+                } else if (method.equals("POST")) {
+                    if(uri.equals(GITLAB_TOKEN_ENDPOINT)){
+                        t.sendResponseHeaders(200, GITLAB_TOKEN_RESPONSE.length());
+                        os = t.getResponseBody();
+                        os.write(GITLAB_TOKEN_RESPONSE.getBytes());
+                    }
+                    else {
+                        t.sendResponseHeaders(404, 0);
+                    }
+                } else {
+                    t.sendResponseHeaders(404, 0);
+                }
+                System.out.println("req handled successful");
+
+            } catch (Exception e) {
+                System.out.println(e.getMessage());
+            } finally {
+                if (os != null) {
+                    os.close();
+                }
+            }
+        }
+    }
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestKeycloakAuthService.java b/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestKeycloakAuthService.java
new file mode 100644 (file)
index 0000000..945ad7f
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2021 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 static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.InetSocketAddress;
+import java.nio.file.Files;
+import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import javax.servlet.http.HttpServletRequest;
+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.OAuthProviderConfig;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.KeycloakProviderService;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
+
+public class TestKeycloakAuthService {
+
+    private static HttpServer server;
+    private static ExecutorService httpThreadPool;
+    private static KeycloakProviderServiceToTest oauthService;
+    private static final int PORT = randomPort(50000, 55000);
+    private static final String KEYCLOAKURL = String.format("http://127.0.0.1:%d", PORT);
+    private static final String OAUTH_SECRET = "oauthsecret";
+    private static final String TOKENCREATOR_SECRET = "secret";
+    private static final String REDIRECT_URI = "/odlux/token?";
+
+    @BeforeClass
+    public static void init() {
+
+        TokenCreator tokenCreator = TokenCreator.getInstance(TOKENCREATOR_SECRET, "issuer");
+        OAuthProviderConfig config =
+                new OAuthProviderConfig("kc", KEYCLOAKURL, "odlux.app", OAUTH_SECRET, "openid", "keycloak test");
+        oauthService = new KeycloakProviderServiceToTest(config, REDIRECT_URI, tokenCreator);
+        try {
+            initKeycloakTestWebserver(PORT, "/");
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @AfterClass
+    public static void close() {
+        stopTestWebserver();
+    }
+
+    @Test
+    public void test() {
+        HttpServletRequest req;
+        HttpServletResponse resp = null;
+        String host = "http://localhost:8412";
+        final String state = "stateabc";
+        try {
+            req = mock(HttpServletRequest.class);
+            resp = mock(HttpServletResponse.class);
+            when(req.getParameter("code")).thenReturn("abcdefg");
+            when(req.getParameter("state")).thenReturn(state);
+            oauthService.handleRedirect(req, resp, host);
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        verify(resp).setStatus(302);
+        //verify(resp).setHeader("Location",any(String.class));
+    }
+
+    public void test2() {
+        oauthService.sendLoginRedirectResponse(null, null);
+    }
+
+    public static class KeycloakProviderServiceToTest extends KeycloakProviderService {
+
+        public KeycloakProviderServiceToTest(OAuthProviderConfig config, String redirectUri, TokenCreator tokenCreator) {
+            super(config, redirectUri, tokenCreator);
+        }
+    }
+
+    private static int randomPort(int min, int max) {
+        Random random = new Random();
+        return random.nextInt(max + 1 - min) + min;
+    }
+
+    public static void initKeycloakTestWebserver(int port, String baseUri) throws IOException {
+        server = HttpServer.create(new InetSocketAddress("127.0.0.1", port), 0);
+        httpThreadPool = Executors.newFixedThreadPool(5);
+        server.setExecutor(httpThreadPool);
+        server.createContext(baseUri, new MyHandler());
+        //server.createContext("/", new MyRootHandler());
+        server.setExecutor(null); // creates a default executor
+        server.start();
+        System.out.println("http server started");
+    }
+
+    public static void stopTestWebserver() {
+        if (server != null) {
+            server.stop(0);
+            httpThreadPool.shutdownNow();
+            System.out.println("http server stopped");
+        }
+    }
+
+    private static String loadResourceFileContent(String filename) {
+        try {
+            return Files.readString(new File(filename).toPath());
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+        return null;
+    }
+    public static class MyHandler implements HttpHandler {
+        private static final String KEYCLOAK_TOKEN_ENDPOINT = "/auth/realms/onap/protocol/openid-connect/token";
+        private static final String KEYCLOAK_TOKEN_RESPONSE = loadResourceFileContent("src/test/resources/oauth/keycloak-token-response.json");
+
+        @Override
+        public void handle(HttpExchange t) throws IOException {
+            final String method = t.getRequestMethod();
+            final String uri = t.getRequestURI().toString();
+            System.out.println(String.format("req received: %s %s", method, t.getRequestURI()));
+            OutputStream os = null;
+            try {
+               if (method.equals("POST")) {
+                    if(uri.equals(KEYCLOAK_TOKEN_ENDPOINT)){
+                        t.sendResponseHeaders(200, KEYCLOAK_TOKEN_RESPONSE.length());
+                        os = t.getResponseBody();
+                        os.write(KEYCLOAK_TOKEN_RESPONSE.getBytes());
+                    }
+                    else {
+                        t.sendResponseHeaders(404, 0);
+                    }
+                } else {
+                    t.sendResponseHeaders(404, 0);
+                }
+                System.out.println("req handled successful");
+
+            } catch (Exception e) {
+                System.out.println(e.getMessage());
+            } finally {
+                if (os != null) {
+                    os.close();
+                }
+            }
+        }
+    }
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestPolicy.java b/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestPolicy.java
new file mode 100644 (file)
index 0000000..31d7294
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2021 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.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlPolicy;
+
+public class TestPolicy {
+
+    private static final String PATH_1 = "/p1/**";
+
+    @Test
+    public void testPolicyAllowAll() {
+        OdlPolicy p = OdlPolicy.allowAll(PATH_1);
+        assertTrue(p.getMethods().isGet());
+        assertTrue(p.getMethods().isPost());
+        assertTrue(p.getMethods().isPut());
+        assertTrue(p.getMethods().isDelete());
+        assertTrue(p.getMethods().isPatch());
+        assertEquals(PATH_1,p.getPath());
+    }
+
+    @Test
+    public void testPolicyDenyAll() {
+        OdlPolicy p = OdlPolicy.denyAll(PATH_1);
+        assertFalse(p.getMethods().isGet());
+        assertFalse(p.getMethods().isPost());
+        assertFalse(p.getMethods().isPut());
+        assertFalse(p.getMethods().isDelete());
+        assertFalse(p.getMethods().isPatch());
+        assertEquals(PATH_1,p.getPath());
+    }
+
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRealm.java b/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRealm.java
new file mode 100644 (file)
index 0000000..fe9dae3
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2021 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.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.HashSet;
+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.UsernamePasswordToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.OAuth2Realm;
+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.opendaylight.aaa.shiro.filters.backport.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;
+
+public class TestRealm {
+
+    private static OAuth2RealmToTest realm;
+    private static TokenCreator tokenCreator;
+
+    @BeforeClass
+    public static void init() {
+        ThreadLocals.AUTH_SETVICE_TL.set(new AuthenticationManager());
+        ThreadLocals.TOKEN_AUTHENICATORS_TL.set(new TokenAuthenticators());
+        try {
+            Config config = Config.getInstance(TestConfig.TEST_CONFIG_FILENAME);
+            tokenCreator = TokenCreator.getInstance(config);
+            realm = new OAuth2RealmToTest();
+        } catch (IOException e) {
+            fail(e.getMessage());
+        }
+    }
+
+
+    @Test
+    public void testTokenSupport() {
+        assertTrue(realm.supports(new UsernamePasswordToken()));
+        assertTrue(realm.supports(new BearerToken("")));
+    }
+
+
+    @Test
+    public void testAuthorizationInfo() {
+        //bearer token use case
+        PrincipalCollection c = mock(PrincipalCollection.class);
+        final List<String> roles = Arrays.asList("admin", "provision");
+        UserTokenPayload userData = createUserData("", roles);
+
+        DecodedJWT decodedJwt = tokenCreator.verify(tokenCreator.createNewJWT(userData).getToken());
+        when(c.getPrimaryPrincipal()).thenReturn(decodedJwt);
+
+        AuthorizationInfo ai = realm.doGetAuthorizationInfo(c);
+        for (String role : roles) {
+            assertTrue(ai.getRoles().contains(role));
+        }
+        assertEquals(roles.size(), ai.getRoles().size());
+        //odl token use case
+        ODLPrincipal principal = mock(ODLPrincipal.class);
+        when(principal.getRoles()).thenReturn(new HashSet<String>(roles));
+        PrincipalCollection c2 = mock(PrincipalCollection.class);
+        when(c2.getPrimaryPrincipal()).thenReturn(principal);
+        ai = realm.doGetAuthorizationInfo(c2);
+        for (String role : roles) {
+            assertTrue(ai.getRoles().contains(role));
+        }
+        assertEquals(roles.size(), ai.getRoles().size());
+
+    }
+
+    @Test
+    public void testAssertCredentialsMatch() {
+        //bearer token use case
+        UserTokenPayload userData = createUserData("", Arrays.asList("admin", "provision"));
+        AuthenticationToken atoken = new BearerToken(tokenCreator.createNewJWT(userData).getToken());
+        AuthenticationInfo ai = null;
+        try {
+            realm.assertCredentialsMatch(atoken, ai);
+        } catch (AuthenticationException e) {
+            fail(e.getMessage());
+        }
+        //odl token use case
+        atoken = new UsernamePasswordToken("admin", "admin");
+        try {
+            realm.assertCredentialsMatch(atoken, ai);
+        } catch (AuthenticationException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    @Test
+    public void testAuthenticationInfo() {
+        //bearer token use case
+        UserTokenPayload userData = createUserData("", Arrays.asList("admin", "provision"));
+        AuthenticationToken atoken = new BearerToken(tokenCreator.createNewJWT(userData).getToken());
+        AuthenticationInfo ai = null;
+        try {
+            ai = realm.doGetAuthenticationInfo(atoken);
+        } catch (AuthenticationException e) {
+            fail(e.getMessage());
+        }
+        //odl token use case
+        atoken = new UsernamePasswordToken("admin", "admin");
+        try {
+            ai = realm.doGetAuthenticationInfo(atoken);
+        } catch (AuthenticationException e) {
+            fail(e.getMessage());
+        }
+    }
+
+    private static UserTokenPayload createUserData(String username, List<String> roles) {
+        UserTokenPayload userData = new UserTokenPayload();
+        userData.setExp(tokenCreator.getDefaultExp());
+        userData.setFamilyName("");
+        userData.setGivenName("");
+        userData.setPreferredUsername(username);
+        userData.setRoles(roles);
+        return userData;
+    }
+
+    public static class OAuth2RealmToTest extends OAuth2Realm {
+
+        public OAuth2RealmToTest() throws IOException {
+            super();
+        }
+
+        @Override
+        public AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg) {
+            return super.doGetAuthorizationInfo(arg);
+        }
+
+        @Override
+        public void assertCredentialsMatch(AuthenticationToken atoken, AuthenticationInfo ai)
+                throws AuthenticationException {
+            super.assertCredentialsMatch(atoken, ai);
+        }
+
+        @Override
+        public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+            return super.doGetAuthenticationInfo(token);
+        }
+    }
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlJsonMapper.java b/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlJsonMapper.java
new file mode 100644 (file)
index 0000000..0399655
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2021 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.helper;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+import org.onap.ccsdk.features.sdnr.wt.dataprovider.yangtools.mapperextensions.YangToolsBuilderAnnotationIntrospector;
+import org.onap.ccsdk.features.sdnr.wt.dataprovider.yangtools.mapperextensions.YangToolsModule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.permission.Permissions;
+import org.opendaylight.yangtools.concepts.Builder;
+
+public class OdlJsonMapper extends ObjectMapper {
+
+    private static final long serialVersionUID = 1L;
+
+
+    public OdlJsonMapper() {
+        this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+        this.setSerializationInclusion(Include.NON_NULL);
+        this.setPropertyNamingStrategy(PropertyNamingStrategy.KEBAB_CASE);
+        this.enable(MapperFeature.USE_GETTERS_AS_SETTERS);
+        YangToolsBuilderAnnotationIntrospector introspector = new YangToolsBuilderAnnotationIntrospector();
+        //introspector.addDeserializer(Main.class, ShiroMainBuilder.class.getName());
+        introspector.addDeserializer(Permissions.class,PermissionsBuilder.class.getName());
+        this.setAnnotationIntrospector(introspector);
+        this.registerModule(new YangToolsModule());
+    }
+
+    public static class PermissionsBuilder implements Builder<Permissions> {
+        private Permissions _value;
+
+        public PermissionsBuilder() {
+
+        }
+        public PermissionsBuilder(Permissions value) {
+            this._value = value;
+        }
+
+        @Override
+        public Permissions build() {
+            return this._value;
+        }
+    }
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlXmlMapper.java b/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlXmlMapper.java
new file mode 100644 (file)
index 0000000..cc029bd
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2021 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.helper;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+import com.fasterxml.jackson.dataformat.xml.XmlMapper;
+import org.onap.ccsdk.features.sdnr.wt.dataprovider.yangtools.mapperextensions.YangToolsBuilderAnnotationIntrospector;
+
+public class OdlXmlMapper extends XmlMapper{
+
+    private static final long serialVersionUID = 1L;
+
+
+    public OdlXmlMapper() {
+        this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+        this.setSerializationInclusion(Include.NON_NULL);
+        this.setPropertyNamingStrategy(PropertyNamingStrategy.KEBAB_CASE);
+        this.enable(MapperFeature.USE_GETTERS_AS_SETTERS);
+        YangToolsBuilderAnnotationIntrospector introspector = new YangToolsBuilderAnnotationIntrospector();
+        //introspector.addDeserializer(Main.class, ShiroMainBuilder.class.getName());
+
+        this.setAnnotationIntrospector(introspector);
+    }
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/aaa-app-config.test.xml b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/aaa-app-config.test.xml
new file mode 100644 (file)
index 0000000..017c743
--- /dev/null
@@ -0,0 +1,351 @@
+<?xml version="1.0" ?>
+<!--
+     Copyright (c) 2017 Inocybe Technologies and others.  All rights reserved.
+
+     This program and the accompanying materials are made available under the
+     terms of the Eclipse Public License v1.0 which accompanies this distribution,
+     and is available at http://www.eclipse.org/legal/epl-v10.html
+-->
+
+<!--
+  ///////////////////////////////////////////////////////////////////////////////////////
+  // clustered-app-config instance responsible for AAA configuration.  In the future,  //
+  // this will contain all AAA related configuration.                                  //
+  ///////////////////////////////////////////////////////////////////////////////////////
+-->
+
+<shiro-configuration xmlns="urn:opendaylight:aaa:app:config">
+
+    <!--
+      ///////////////////////////////////////////////////////////////////////////////////
+      // shiro-configuration is the model based container that contains all shiro      //
+      // related information used in ODL AAA configuration.  It is the sole pain of    //
+      // glass for shiro related configuration, and is how to configure shiro concepts //
+      // such as:                                                                      //
+      // * realms                                                                      //
+      // * urls                                                                        //
+      // * security manager settings                                                   //
+      //                                                                               //
+      // In general, you really shouldn't muck with the settings in this file.  The    //
+      // way an operator should configure AAA shiro settings is through one of ODL's   //
+      // northbound interfaces (i.e., RESTCONF or NETCONF).  These are just the        //
+      // defaults if no values are specified in MD-SAL.  The reason this file is so    //
+      // verbose is for two reasons:                                                   //
+      // 1) to demonstrate payload examples for plausible configuration scenarios      //
+      // 2) to allow bootstrap of the controller (first time start) since otherwise    //
+      //    configuration becomes a chicken and the egg problem.                       //
+      //                                                                               //
+      ///////////////////////////////////////////////////////////////////////////////////
+    -->
+
+    <!--
+      ===================================================================================
+      =                                                                                 =
+      =                                                                                 =
+      =                                      MAIN                                       =
+      =                                                                                 =
+      =                                                                                 =
+      ===================================================================================
+    -->
+
+    <!--
+      ===================================================================================
+      ============================ ODLJndiLdapRealmAuthNOnly ============================
+      ===================================================================================
+      =                                                                                 =
+      = Description:  A Realm implementation aimed at federating with an external LDAP  =
+      =               server for authentication only.  For authorization support, refer =
+      =               to ODLJndiLdapRealm.                                              =
+      ===================================================================================
+    -->
+    <!-- Start ldapRealm commented out
+    <main>
+        <pair-key>ldapRealm</pair-key>
+        <pair-value>org.opendaylight.aaa.shiro.realm.ODLJndiLdapRealmAuthNOnly</pair-value>
+    </main>
+    <main>
+        <pair-key>ldapRealm.userDnTemplate</pair-key>
+        <pair-value>uid={0},ou=People,dc=DOMAIN,dc=TLD</pair-value>
+    </main>
+    <main>
+        <pair-key>ldapRealm.contextFactory.url</pair-key>
+        <pair-value>ldap://&lt;URL&gt;:389</pair-value>
+    </main>
+    <main>
+        <pair-key>ldapRealm.searchBase</pair-key>
+        <pair-value>dc=DOMAIN,dc=TLD</pair-value>
+    </main>
+    <main>
+        <pair-key>ldapRealm.groupRolesMap</pair-key>
+        <pair-value>&quot;person&quot;:&quot;admin&quot;, &quot;organizationalPerson&quot;:&quot;user&quot;</pair-value>
+    </main>
+    <main>
+        <pair-key>ldapRealm.ldapAttributeForComparison</pair-key>
+        <pair-value>objectClass</pair-value>
+    </main>
+    End ldapRealm commented out-->
+
+    <!--
+      ===================================================================================
+      ============================= ODLActiveDirectoryRealm =============================
+      ===================================================================================
+      =                                                                                 =
+      = Description:  A Realm implementation aimed at federating with an external AD    =
+      =               IDP server.                                                       =
+      ===================================================================================
+    -->
+    <!-- Start adRealm commented out
+    <main>
+        <pair-key>adRealm</pair-key>
+        <pair-value>org.opendaylight.aaa.shiro.realm.ODLActiveDirectoryRealm</pair-value>
+    </main>
+    <main>
+        <pair-key>adRealm.searchBase</pair-key>
+        <pair-value>&quot;CN=Users,DC=example,DC=com&quot;</pair-value>
+    </main>
+    <main>
+        <pair-key>adRealm.systemUsername</pair-key>
+        <pair-value>aduser@example.com</pair-value>
+    </main>
+    <main>
+        <pair-key>adRealm.systemPassword</pair-key>
+        <pair-value>adpassword</pair-value>
+    </main>
+    <main>
+        <pair-key>adRealm.url</pair-key>
+        <pair-value>ldaps://adserver:636</pair-value>
+    </main>
+    <main>
+        <pair-key>adRealm.groupRolesMap</pair-key>
+        <pair-value>&quot;CN=sysadmin,CN=Users,DC=example,DC=com&quot;:&quot;admin&quot;, &quot;CN=unprivileged,CN=Users,DC=example,DC=com&quot;:&quot;user&quot;</pair-value>
+    </main>
+    End adRealm commented out-->
+
+    <!--
+      ===================================================================================
+      ================================== ODLJdbcRealm ===================================
+      ===================================================================================
+      =                                                                                 =
+      = Description:  A Realm implementation aimed at federating with an external JDBC  =
+      =               DBMS.                                                             =
+      ===================================================================================
+    -->
+    <!-- Start jdbcRealm commented out
+    <main>
+        <pair-key>ds</pair-key>
+        <pair-value>com.mysql.jdbc.Driver</pair-value>
+    </main>
+    <main>
+        <pair-key>ds.serverName</pair-key>
+        <pair-value>localhost</pair-value>
+    </main>
+    <main>
+        <pair-key>ds.user</pair-key>
+        <pair-value>user</pair-value>
+    </main>
+    <main>
+        <pair-key>ds.password</pair-key>
+        <pair-value>password</pair-value>
+    </main>
+    <main>
+        <pair-key>ds.databaseName</pair-key>
+        <pair-value>db_name</pair-value>
+    </main>
+    <main>
+        <pair-key>jdbcRealm</pair-key>
+        <pair-value>ODLJdbcRealm</pair-value>
+    </main>
+    <main>
+        <pair-key>jdbcRealm.dataSource</pair-key>
+        <pair-value>$ds</pair-value>
+    </main>
+    <main>
+        <pair-key>jdbcRealm.authenticationQuery</pair-key>
+        <pair-value>&quot;SELECT password FROM users WHERE user_name = ?&quot;</pair-value>
+    </main>
+    <main>
+        <pair-key>jdbcRealm.userRolesQuery</pair-key>
+        <pair-value>&quot;SELECT role_name FROM user_rolesWHERE user_name = ?&quot;</pair-value>
+    </main>
+    End jdbcRealm commented out-->
+
+    <!--
+      ===================================================================================
+      ================================= TokenAuthRealm ==================================
+      ===================================================================================
+      =                                                                                 =
+      = Description:  A Realm implementation utilizing a per node H2 database store.    =
+      ===================================================================================
+    -->
+<!--     <main> -->
+<!--         <pair-key>tokenAuthRealm</pair-key> -->
+<!--         <pair-value>org.opendaylight.aaa.shiro.realm.TokenAuthRealm</pair-value> -->
+<!--     </main> -->
+    <main>
+        <pair-key>tokenAuthRealm</pair-key>
+        <pair-value>org.onap.ccsdk.features.sdnr.wt.oauthprovider.OAuth2Realm</pair-value>
+    </main>
+
+    <!--
+      ===================================================================================
+      =================================== MdsalRealm ====================================
+      ===================================================================================
+      =                                                                                 =
+      = Description:  A Realm implementation utilizing the aaa.yang model.              =
+      ===================================================================================
+    -->
+    <!-- Start mdsalRealm commented out
+    <main>
+        <pair-key>mdsalRealm</pair-key>
+        <pair-value>org.opendaylight.aaa.shiro.realm.MdsalRealm</pair-value>
+    </main>
+    End mdsalRealm commented out-->
+
+    <!--
+      ===================================================================================
+      ================================= MoonAuthRealm ===================================
+      ===================================================================================
+      =                                                                                 =
+      = Description:  A Realm implementation aimed at federating with OPNFV Moon.       =
+      ===================================================================================
+    -->
+    <!-- Start moonAuthRealm commented out
+    <main>
+        <pair-key>moonAuthRealm</pair-key>
+        <pair-value>org.opendaylight.aaa.shiro.realm.MoonRealm</pair-value>
+    </main>
+    <main>
+        <pair-key>moonAuthRealm.moonServerURL</pair-key>
+        <pair-value>http://&lt;host&gt;:&lt;port&gt;</pair-value>
+    </main>
+    End moonAuthRealm commented out-->
+
+    <!--
+      ===================================================================================
+      ================================= KeystoneAuthRealm == ============================
+      ===================================================================================
+      =                                                                                 =
+      = Description:  A Realm implementation aimed at federating with an OpenStack      =
+      =               Keystone.                                                         =
+      ===================================================================================
+    -->
+    <!-- Start keystoneAuthRealm commented out
+    <main>
+        <pair-key>keystoneAuthRealm</pair-key>
+        <pair-value>org.opendaylight.aaa.shiro.realm.KeystoneAuthRealm</pair-value>
+    </main>
+    <main>
+        <pair-key>keystoneAuthRealm.url</pair-key>
+        <pair-value>https://&lt;host&gt;:&lt;port&gt;</pair-value>
+    </main>
+    <main>
+        <pair-key>keystoneAuthRealm.sslVerification</pair-key>
+        <pair-value>true</pair-value>
+    </main>
+    <main>
+        <pair-key>keystoneAuthRealm.defaultDomain</pair-key>
+        <pair-value>Default</pair-value>
+    </main>
+    -->
+
+    <!--
+    Add tokenAuthRealm as the only realm.  To enable mdsalRealm, add it to the list to he right of tokenAuthRealm.
+    -->
+    <main>
+        <pair-key>securityManager.realms</pair-key>
+        <pair-value>$tokenAuthRealm</pair-value>
+    </main>
+    <!-- Used to support OAuth2 use case. -->
+    <main>
+        <pair-key>authcBasic</pair-key>
+        <pair-value>org.opendaylight.aaa.shiro.filters.ODLHttpAuthenticationFilter</pair-value>
+    </main>
+    <main>
+        <pair-key>anyroles</pair-key>
+        <pair-value>org.opendaylight.aaa.shiro.filters.AnyRoleHttpAuthenticationFilter</pair-value>
+    </main>
+    <main>
+        <pair-key>authcBearer</pair-key>
+        <pair-value>org.opendaylight.aaa.shiro.filters.ODLHttpAuthenticationFilter2</pair-value>
+    </main>
+   
+    <!-- Start moonAuthRealm commented out
+    <main>
+        <pair-key>rest</pair-key>
+        <pair-value>org.opendaylight.aaa.shiro.filters.MoonOAuthFilter</pair-value>
+    </main>
+    End moonAuthRealm commented out-->
+
+    <!-- in order to track AAA challenge attempts -->
+    <main>
+        <pair-key>accountingListener</pair-key>
+        <pair-value>org.opendaylight.aaa.shiro.filters.AuthenticationListener</pair-value>
+    </main>
+    <main>
+        <pair-key>securityManager.authenticator.authenticationListeners</pair-key>
+        <pair-value>$accountingListener</pair-value>
+    </main>
+
+    <!-- Model based authorization scheme supporting RBAC for REST endpoints -->
+    <main>
+        <pair-key>dynamicAuthorization</pair-key>
+        <pair-value>org.opendaylight.aaa.shiro.realm.MDSALDynamicAuthorizationFilter</pair-value>
+    </main>
+<!--     <main> -->
+<!--         <pair-key>securityManager.sessionManager.sessionIdCookieEnabled</pair-key> -->
+<!--         <pair-value>false</pair-value> -->
+<!--     </main> -->
+
+    <!--
+      ===================================================================================
+      =                                                                                 =
+      =                                                                                 =
+      =                                      URLS                                       =
+      =                                                                                 =
+      =                                                                                 =
+      ===================================================================================
+    -->
+    <!-- Start moonAuthRealm commented out
+    <urls>
+        <pair-key>/token</pair-key>
+        <pair-value>rest</pair-value>
+    </urls>
+    End moonAuthRealm commented out-->
+    <urls>
+        <pair-key>/**/operations/cluster-admin**</pair-key>
+        <pair-value>dynamicAuthorization</pair-value>
+    </urls>
+    <urls>
+        <pair-key>/**/v1/**</pair-key>
+        <pair-value>authcBearer, roles[admin]</pair-value>
+    </urls>
+    <urls>
+        <pair-key>/**/config/aaa*/**</pair-key>
+        <pair-value>authcBearer, roles[admin]</pair-value>
+    </urls>
+     <urls>
+        <pair-key>/oauth/**</pair-key>
+        <pair-value>anon</pair-value>
+    </urls>
+    <urls>
+        <pair-key>/odlux/**</pair-key>
+        <pair-value>anon</pair-value>
+    </urls>
+    <urls>
+        <pair-key>/apidoc/**</pair-key>
+        <pair-value>authcBasic, roles[admin]</pair-value>
+    </urls>
+     <urls>
+        <pair-key>/test123/**</pair-key>
+        <pair-value>authcBasic</pair-value>
+    </urls>
+    <urls>
+        <pair-key>/rests/**</pair-key>
+        <pair-value>authcBearer, anyroles["admin,provision"]</pair-value>
+    </urls>
+    <urls>
+        <pair-key>/**</pair-key>
+        <pair-value>authcBearer, anyroles["admin,provision"]</pair-value>
+    </urls>
+</shiro-configuration>
+
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/mdsalDynAuthData.json b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/mdsalDynAuthData.json
new file mode 100644 (file)
index 0000000..a162768
--- /dev/null
@@ -0,0 +1,694 @@
+{
+        "policies": [
+            {
+                "resource": "/restconf/**",
+                "index": 0,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/auth/v1/**",
+                "index": 1,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/config/aaa*/**",
+                "index": 2,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/jolokia/**",
+                "index": 3,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "raftstate",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/rests/data/network-topology:network-topology/topology=topology-netconf/node=513250004/**",
+                "index": 4,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "provisioner",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "huawei",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "planner",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/rests/data/network-topology:network-topology/topology=topology-netconf/node=513250005/**",
+                "index": 5,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "provisioner",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "huawei",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "planner",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/rests/data/network-topology:network-topology/topology=topology-netconf/node=513250006/**",
+                "index": 6,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "provisioner",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "siae",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "planner",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/rests/data/network-topology:network-topology/topology=topology-netconf/node=513250007/**",
+                "index": 7,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "provisioner",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "siae",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "planner",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/rests/data/network-topology:network-topology/topology=topology-netconf/node=513250008/**",
+                "index": 8,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "provisioner",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "siae",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "planner",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/rests/data/network-topology:network-topology/topology=topology-netconf/node=513250009/**",
+                "index": 9,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "provisioner",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "siae",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "planner",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/rests/data/network-topology:network-topology/topology=topology-netconf/node=513250010/**",
+                "index": 10,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "provisioner",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "ericsson",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "planner",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/rests/data/network-topology:network-topology/topology=topology-netconf/node=513250011/**",
+                "index": 11,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "provisioner",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "ericsson",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "planner",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/rests/data/network-topology:network-topology/topology=topology-netconf/node=513559991A/**",
+                "index": 14,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "provisioner",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "ericsson",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "planner",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/rests/data/network-topology:network-topology/topology=topology-netconf/node=513559991B/**",
+                "index": 15,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "provisioner",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "ericsson",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "planner",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/rests/data/network-topology:network-topology/topology=topology-netconf/node=513250012/**",
+                "index": 12,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "provisioner",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "zte",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "planner",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/rests/data/network-topology:network-topology/topology=topology-netconf/node=513250013/**",
+                "index": 13,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "provisioner",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "zte",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "planner",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            },
+            {
+                "resource": "/rests/data/network-topology:network-topology/topology=topology-netconf/**",
+                "index": 16,
+                "permissions": [
+                    {
+                        "role": "admin",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "provisioner",
+                        "actions": [
+                            "put",
+                            "get",
+                            "patch",
+                            "delete",
+                            "post"
+                        ]
+                    },
+                    {
+                        "role": "planner",
+                        "actions": [
+                            "get"
+                        ]
+                    },
+                    {
+                        "role": "monitor",
+                        "actions": [
+                            "get"
+                        ]
+                    }
+                ]
+            }
+        ]
+    }
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/oauth/gitlab-groups-response.json b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/oauth/gitlab-groups-response.json
new file mode 100644 (file)
index 0000000..85fc37c
--- /dev/null
@@ -0,0 +1,112 @@
+[
+    {
+        "id": 51,
+        "web_url": "https://my-git-server.com/groups/group1",
+        "name": "Group1",
+        "path": "group1",
+        "description": "",
+        "visibility": "private",
+        "share_with_group_lock": false,
+        "require_two_factor_authentication": false,
+        "two_factor_grace_period": 48,
+        "project_creation_level": "developer",
+        "auto_devops_enabled": null,
+        "subgroup_creation_level": "maintainer",
+        "emails_disabled": null,
+        "mentions_disabled": null,
+        "lfs_enabled": true,
+        "avatar_url": null,
+        "request_access_enabled": true,
+        "full_name": "Group1",
+        "full_path": "group1",
+        "parent_id": null
+    },
+    {
+        "id": 69,
+        "web_url": "https://my-git-server.com/groups/group2",
+        "name": "Group2",
+        "path": "group2",
+        "description": "",
+        "visibility": "private",
+        "share_with_group_lock": false,
+        "require_two_factor_authentication": false,
+        "two_factor_grace_period": 48,
+        "project_creation_level": "developer",
+        "auto_devops_enabled": null,
+        "subgroup_creation_level": "owner",
+        "emails_disabled": null,
+        "mentions_disabled": null,
+        "lfs_enabled": true,
+        "avatar_url": null,
+        "request_access_enabled": true,
+        "full_name": "Group2",
+        "full_path": "group2",
+        "parent_id": null
+    },
+    {
+        "id": 24,
+        "web_url": "https://my-git-server.com/groups/group3",
+        "name": "group3",
+        "path": "group3",
+        "description": "",
+        "visibility": "private",
+        "share_with_group_lock": false,
+        "require_two_factor_authentication": false,
+        "two_factor_grace_period": 48,
+        "project_creation_level": "developer",
+        "auto_devops_enabled": null,
+        "subgroup_creation_level": "owner",
+        "emails_disabled": null,
+        "mentions_disabled": null,
+        "lfs_enabled": true,
+        "avatar_url": null,
+        "request_access_enabled": false,
+        "full_name": "group3",
+        "full_path": "group3",
+        "parent_id": null
+    },
+    {
+        "id": 22,
+        "web_url": "https://my-git-server.com/groups/group4",
+        "name": "group4",
+        "path": "group4",
+        "description": "custom desc",
+        "visibility": "private",
+        "share_with_group_lock": false,
+        "require_two_factor_authentication": false,
+        "two_factor_grace_period": 48,
+        "project_creation_level": "developer",
+        "auto_devops_enabled": null,
+        "subgroup_creation_level": "owner",
+        "emails_disabled": null,
+        "mentions_disabled": null,
+        "lfs_enabled": true,
+        "avatar_url": "https://my-git-server.com/uploads/-/system/group/avatar/22/Factory_1b.svg.png",
+        "request_access_enabled": true,
+        "full_name": "group4",
+        "full_path": "group4",
+        "parent_id": null
+    },
+    {
+        "id": 5,
+        "web_url": "https://my-git-server.com/groups/group5",
+        "name": "group5",
+        "path": "group5",
+        "description": "my group 5",
+        "visibility": "private",
+        "share_with_group_lock": false,
+        "require_two_factor_authentication": false,
+        "two_factor_grace_period": 48,
+        "project_creation_level": "developer",
+        "auto_devops_enabled": null,
+        "subgroup_creation_level": "owner",
+        "emails_disabled": null,
+        "mentions_disabled": null,
+        "lfs_enabled": true,
+        "avatar_url": "https://my-git-server.com/uploads/-/system/group/avatar/5/mylogo.png",
+        "request_access_enabled": true,
+        "full_name": "group5",
+        "full_path": "group5",
+        "parent_id": null
+    }
+]
\ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/oauth/gitlab-token-response.json b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/oauth/gitlab-token-response.json
new file mode 100644 (file)
index 0000000..0a6bd72
--- /dev/null
@@ -0,0 +1,7 @@
+{
+    "access_token":"asfhoipmspaodm-asndfoiasnf-aisjdaisjj",
+    "expires_in":12345,
+    "refresh_expires_in":123456,
+    "refresh_token":"asdsadasd",
+    "token_type":"bearer"
+}
\ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/oauth/gitlab-user-response.json b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/oauth/gitlab-user-response.json
new file mode 100644 (file)
index 0000000..b08332b
--- /dev/null
@@ -0,0 +1,32 @@
+{
+    "id": 21,
+    "name": "me",
+    "username": "my-username",
+    "state": "active",
+    "avatar_url": "https://my-git-server.com/uploads/-/system/user/avatar/21/avatar.png",
+    "web_url": "https://my-git-server.com/my-username",
+    "created_at": "2017-05-15T14:49:38.396Z",
+    "bio": "",
+    "location": "",
+    "public_email": "",
+    "skype": "",
+    "linkedin": "",
+    "twitter": "",
+    "website_url": "",
+    "organization": "",
+    "last_sign_in_at": "2021-02-12T12:56:34.094Z",
+    "confirmed_at": "2018-01-18T09:49:08.463Z",
+    "last_activity_on": "2021-02-15",
+    "email": "me@my-server.com",
+    "theme_id": null,
+    "color_scheme_id": 1,
+    "projects_limit": 0,
+    "current_sign_in_at": "2021-02-15T03:17:12.140Z",
+    "identities": [],
+    "can_create_group": false,
+    "can_create_project": false,
+    "two_factor_enabled": false,
+    "external": false,
+    "private_profile": false,
+    "is_admin": true
+}
\ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/oauth/keycloak-token-response.json b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/oauth/keycloak-token-response.json
new file mode 100644 (file)
index 0000000..c62ed94
--- /dev/null
@@ -0,0 +1,11 @@
+{
+    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJkbWFSWXRkaHFkVXFDV2lmRWdNRHFBcWVBcU8tMnFoTDBjdnByelRGdWRRIn0.eyJleHAiOjE2MTExMzU5MjEsImlhdCI6MTYxMTEzNDEyMSwiYXV0aF90aW1lIjoxNjExMTM0MDkxLCJqdGkiOiIzYzFlZmMzZi1lMjFiLTQ3MzktYTY1YS1jNjY1M2ZhOGRjNTQiLCJpc3MiOiJodHRwOi8vMTAuMjAuMTEuMTYwOjgwODAvYXV0aC9yZWFsbXMvb25hcCIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiI0NDZhMjRiYy1kOGEwLTQzZGQtYWZhNS1lNTZlZWQ3NWRlYjgiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJvZGx1eC5hcHAiLCJzZXNzaW9uX3N0YXRlIjoiMTI5YjRhNjMtNzBhMS00MjFmLWEzM2YtOWFjZDkyZTIzM2ZmIiwiYWNyIjoiMSIsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJwcm92aXNpb24iLCJvZmZsaW5lX2FjY2VzcyIsInVtYV9hdXRob3JpemF0aW9uIl19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6Ikx1a2UgU2t5d2Fsa2VyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibHVrZS5za3l3YWxrZXIiLCJnaXZlbl9uYW1lIjoiTHVrZSIsImZhbWlseV9uYW1lIjoiU2t5d2Fsa2VyIiwiZW1haWwiOiJsdWtlLnNreXdhbGtlckBzZG5yLm9uYXAub3JnIn0.tn2NrEGYLRq1u0DkqxD2iDM72hFrDBPGA_q23S-htiRH113yt14a0CzJxU9El0YDobbzog9xm0ELbx6W4jYsGguMABqIi4W5wtTqfbaCh7gmF208CqNpwzA7nG2palMLbBPpmGXiagUm4qLWQxrBP_VOaeW_kK0VHLaiTRJ-4vHuOXSNPYEDQZNCI2QCJQS_dn83K_JI4ecBHl8UeHFLB65BqmocpDHUvf2h835xuNFFQpXJWMcPM_j_FmFQeOSUDM4HmqgdVU9_b4APnDEVFiUezQdoEOfEYNsNlhCoXlaEEn2tCZfEkZ7k72DlhqJMQzomdaGKPk2g8XhKJNwMJg",
+    "expires_in": 1800,
+    "refresh_expires_in": 1800,
+    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJhOGUzMDUwZS0wZmQxLTRjYjQtYjRiZS1jMDVlOGY4OGJhZGUifQ.eyJleHAiOjE2MTExMzU5MjEsImlhdCI6MTYxMTEzNDEyMSwianRpIjoiZmZiYWE3NDktZGVkNi00ZWMzLWI4MjYtYTI4NWY0ODY1ZGI0IiwiaXNzIjoiaHR0cDovLzEwLjIwLjExLjE2MDo4MDgwL2F1dGgvcmVhbG1zL29uYXAiLCJhdWQiOiJodHRwOi8vMTAuMjAuMTEuMTYwOjgwODAvYXV0aC9yZWFsbXMvb25hcCIsInN1YiI6IjQ0NmEyNGJjLWQ4YTAtNDNkZC1hZmE1LWU1NmVlZDc1ZGViOCIsInR5cCI6IlJlZnJlc2giLCJhenAiOiJvZGx1eC5hcHAiLCJzZXNzaW9uX3N0YXRlIjoiMTI5YjRhNjMtNzBhMS00MjFmLWEzM2YtOWFjZDkyZTIzM2ZmIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCJ9.mt9VHtiBZycHcEuVCOZVjjtyoOGYNaDVvtcA1NPScIQ",
+    "token_type": "bearer",
+    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJkbWFSWXRkaHFkVXFDV2lmRWdNRHFBcWVBcU8tMnFoTDBjdnByelRGdWRRIn0.eyJleHAiOjE2MTExMzU5MjEsImlhdCI6MTYxMTEzNDEyMSwiYXV0aF90aW1lIjoxNjExMTM0MDkxLCJqdGkiOiJjZjUzZTc0ZC1kYjZiLTQ4YTUtODkyOS1jYzU3YjY3YjAxN2QiLCJpc3MiOiJodHRwOi8vMTAuMjAuMTEuMTYwOjgwODAvYXV0aC9yZWFsbXMvb25hcCIsImF1ZCI6Im9kbHV4LmFwcCIsInN1YiI6IjQ0NmEyNGJjLWQ4YTAtNDNkZC1hZmE1LWU1NmVlZDc1ZGViOCIsInR5cCI6IklEIiwiYXpwIjoib2RsdXguYXBwIiwic2Vzc2lvbl9zdGF0ZSI6IjEyOWI0YTYzLTcwYTEtNDIxZi1hMzNmLTlhY2Q5MmUyMzNmZiIsImF0X2hhc2giOiJSUXdDclpkQmFKV0VFdmxsRVNxRjV3IiwiYWNyIjoiMSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwibmFtZSI6Ikx1a2UgU2t5d2Fsa2VyIiwicHJlZmVycmVkX3VzZXJuYW1lIjoibHVrZS5za3l3YWxrZXIiLCJnaXZlbl9uYW1lIjoiTHVrZSIsImZhbWlseV9uYW1lIjoiU2t5d2Fsa2VyIiwiZW1haWwiOiJsdWtlLnNreXdhbGtlckBzZG5yLm9uYXAub3JnIn0.rueTNrnvRa4PMo7NS8l4xxRhhNiGzXLmtcUeyWnj3AjFaUoNKuS9l85K3KjRT3zjq494YsepIGuK33I20rvFwDLclcJNHuumAgBnR5dRBi5fLhm7x8YkebhdTHPiYL4hfygpZ7APN1PtcDZnb-uEjjT-RAtjnfk3r-oP6CtqWzI5MjOPnf5HaEwWpkuTjmJf3kyyf_pdhhVkgTwuC-kD8iMjyRIzuZJxVwWVA3S43eL0R7MaIDlpJrOp9EBRfMlObAypc1bLtKwopT0sBla1CM9GmUU2ZYbQb79-hey0rd7CWx1uBkZUxt5myiExBm3pI46boXLP7dzjzxHUKg0m-A",
+    "not-before-policy": 1611134054,
+    "session_state": "129b4a63-70a1-421f-a33f-9acd92e233ff",
+    "scope": "openid profile email"
+}
\ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/resources/oom.test.config.json b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/oom.test.config.json
new file mode 100644 (file)
index 0000000..4e5707f
--- /dev/null
@@ -0,0 +1,21 @@
+{
+    "tokenSecret": "secret",
+    "tokenIssuer": "ONAP SDNC",
+    "publicUrl": "https://sdnc.onap:30205",
+    "redirectUri": "null",
+    "supportOdlUsers": "true",
+    "providers": [
+        {
+            "id": "htgit",
+            "type": "GITLAB",
+            "url": "https://git-.com",
+            "clientId": "f52440b7dcd4bb75",
+            "secret": "9bd45916f52440b7dcd4bb75",
+            "scope": "api+openid+read_user+profile",
+            "title": " Gitlab",
+            "roleMapping": {
+                "mygitlabgroup": "admin"
+            }
+        }
+    ]
+}
\ No newline at end of file
index 88137fd..157ddb7 100644 (file)
@@ -1,14 +1,14 @@
 {
-    "tokenSecret": "${OAUTH_TOKEN_SECRET}",
-    "tokenIssuer": "${OAUTH_TOKEN_ISSUER}",
-    "host": "",
-    "redirectUri": "${OAUTH_ODLUX_REDIRECT_URI}",
-    "supportOdlUsers": "${OAUTH_SUPPORT_ODLUSERS}",
+    "tokenSecret": "secret2134",
+    "tokenIssuer": "ONAP SDNC",
+    "publicUrl": "http://nasp.diasf.de",
+    "redirectUri": "/index.html#redirect=",
+    "supportOdlUsers": "true",
     "providers": [
         {
             "id": "keycloak",
             "type": "KEYCLOAK",
-            "host": "http://10.20.11.160:8080",
+            "url": "http://10.20.11.160:8080",
             "clientId": "odlux.app",
             "secret": "5da4ea3d-8cc9-4669-bd7e-3ecb91d120cd",
             "scope": "openid",
index 3d17baf..6ff4de2 100644 (file)
                             org.opendaylight.aaa.api.shiro.principal,
                             org.opendaylight.aaa.shiro.realm,
                             org.opendaylight.aaa.shiro.filters.backport,
+                            org.opendaylight.mdsal.binding.api,
                             org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619,
                             org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.shiro.configuration,
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214,
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.authorization,
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.permission,
+                            org.opendaylight.yangtools.yang.binding,
                             com.fasterxml.jackson.databind,
                             com.fasterxml.jackson.databind.deser.std,
                             com.fasterxml.jackson.databind.ser.std,
index f7dd467..ae11de6 100644 (file)
@@ -30,6 +30,8 @@
 
     <reference id="odlIdentityService" interface="org.opendaylight.aaa.api.IdMService" />
 
+    <reference id="dataBroker" interface="org.opendaylight.mdsal.binding.api.DataBroker" />
+    
     <odl:clustered-app-config
           binding-class="org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfiguration"
           id="shiroConfiguration" default-config-file-name="aaa-app-config.xml" />
@@ -39,6 +41,7 @@
           <property ref="odlAuthenticator" name="odlAuthenticator" />
           <property ref="odlIdentityService" name="odlIdentityService" />
           <property ref="shiroConfiguration" name="shiroConfiguration" />
+          <property ref="dataBroker" name="dataBroker" />
     </bean>
 
     <service interface="javax.servlet.http.HttpServlet" ref="authServlet">