aboutsummaryrefslogtreecommitdiffstats
path: root/sdnr/wt/oauth-provider/oauth-core
diff options
context:
space:
mode:
Diffstat (limited to 'sdnr/wt/oauth-provider/oauth-core')
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/pom.xml191
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/OAuth2Realm.java143
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java347
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/CustomObjectMapper.java39
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/InvalidConfigurationException.java32
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakRole.java80
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakUserTokenPayload.java231
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/NoDefinitionFoundException.java33
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthProviderConfig.java202
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthResponseData.java88
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthToken.java57
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlPolicy.java130
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlShiroConfiguration.java67
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlXmlMapper.java44
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OpenIdConfigResponseData.java65
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/UnableToConfigureOAuthService.java12
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/UserTokenPayload.java103
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/filters/AnyRoleHttpAuthenticationFilter.java75
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/filters/BearerAndBasicHttpAuthenticationFilter.java161
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/filters/CustomizedMDSALDynamicAuthorizationFilter.java188
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/AuthHttpServlet.java527
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/HeadersOnlyHttpServletRequest.java469
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappedBaseHttpResponse.java63
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappingBaseHttpClient.java63
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/AuthService.java356
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/GitlabProviderService.java180
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/KeycloakProviderService.java115
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/MdSalAuthorizationStore.java118
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/NextcloudProviderService.java91
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/OAuthProviderFactory.java47
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/PemUtils.java106
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/RSAKeyReader.java47
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/TokenCreator.java202
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestAuthHttpServlet.java404
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestConfig.java80
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestDeserializer.java101
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestGitlabAuthService.java198
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestKeycloakAuthService.java196
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestPolicy.java56
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestProperty.java42
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRSAAlgorithms.java108
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRealm.java219
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlJsonMapper.java65
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlXmlMapper.java46
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/aaa-app-config.test.xml77
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS256.key27
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS256.key.pub9
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS512.key51
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS512.key.pub14
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/mdsalDynAuthData.json694
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/oauth/gitlab-groups-response.json112
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/oauth/gitlab-token-response.json7
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/oauth/gitlab-user-response.json32
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/oauth/keycloak-token-response.json11
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/oom.test.config.json21
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.config.json20
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.configRS256-invalid.json24
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.configRS256.json22
-rw-r--r--sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.configRS512.json22
59 files changed, 7330 insertions, 0 deletions
diff --git a/sdnr/wt/oauth-provider/oauth-core/pom.xml b/sdnr/wt/oauth-provider/oauth-core/pom.xml
new file mode 100644
index 000000000..ef00bf8e9
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/pom.xml
@@ -0,0 +1,191 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ ============LICENSE_START=======================================================
+ ~ ONAP : ccsdk features
+ ~ ================================================================================
+ ~ Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
+ ~ All rights reserved.
+ ~ ================================================================================
+ ~ Update Copyright (C) 2020 AT&T 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=======================================================
+ ~
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.onap.ccsdk.parent</groupId>
+ <artifactId>binding-parent</artifactId>
+ <version>2.6.1</version>
+ <relativePath/>
+ </parent>
+
+ <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+ <artifactId>sdnr-wt-oauth-core</artifactId>
+ <version>1.7.0-SNAPSHOT</version>
+ <packaging>jar</packaging>
+
+ <name>ccsdk-features :: ${project.artifactId}</name>
+ <licenses>
+ <license>
+ <name>Apache License, Version 2.0</name>
+ <url>http://www.apache.org/licenses/LICENSE-2.0</url>
+ </license>
+ </licenses>
+
+ <properties>
+ <maven.javadoc.skip>true</maven.javadoc.skip>
+ <checkstyle.skip>true</checkstyle.skip>
+ </properties>
+ <dependencies>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sdnr-wt-common</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.auth0</groupId>
+ <artifactId>java-jwt</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.bouncycastle</groupId>
+ <artifactId>bcprov-jdk15on</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.opendaylight.aaa</groupId>
+ <artifactId>aaa-shiro</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.opendaylight.aaa</groupId>
+ <artifactId>aaa-cert</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.opendaylight.aaa</groupId>
+ <artifactId>aaa-filterchain</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.opendaylight.aaa</groupId>
+ <artifactId>aaa-password-service-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.opendaylight.aaa.web</groupId>
+ <artifactId>web-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.opendaylight.aaa.web</groupId>
+ <artifactId>servlet-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>commons-text</groupId>
+ <artifactId>commons-text</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.google.code.gson</groupId>
+ <artifactId>gson</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>org.opendaylight.mdsal</groupId>
+ <artifactId>mdsal-binding-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.h2database</groupId>
+ <artifactId>h2</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>ehcache-root</groupId>
+ <artifactId>ehcache</artifactId>
+ </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>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.dataformat</groupId>
+ <artifactId>jackson-dataformat-xml</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>${project.groupId}</groupId>
+ <artifactId>sdnr-wt-yang-utils</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>osgi.cmpn</artifactId>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-core</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-server</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.eclipse.jetty</groupId>
+ <artifactId>jetty-servlet</artifactId>
+ <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>
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/OAuth2Realm.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/OAuth2Realm.java
new file mode 100644
index 000000000..b9f3d6119
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/OAuth2Realm.java
@@ -0,0 +1,143 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider;
+
+import com.auth0.jwt.interfaces.DecodedJWT;
+import java.io.IOException;
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.authc.SimpleAuthenticationInfo;
+import org.apache.shiro.authc.UsernamePasswordToken;
+import org.apache.shiro.authz.AuthorizationInfo;
+import org.apache.shiro.authz.SimpleAuthorizationInfo;
+import org.apache.shiro.subject.PrincipalCollection;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.InvalidConfigurationException;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
+import org.opendaylight.aaa.api.shiro.principal.ODLPrincipal;
+import org.apache.shiro.authc.BearerToken;
+import org.opendaylight.aaa.shiro.realm.TokenAuthRealm;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class OAuth2Realm extends TokenAuthRealm {
+
+ public static final String REALM_NAME = "OAuth2Realm";
+ private static final Logger LOG = LoggerFactory.getLogger(OAuth2Realm.class);
+ private final TokenCreator tokenCreator;
+ private final Config config;
+
+ public OAuth2Realm() throws IllegalArgumentException, IOException, InvalidConfigurationException {
+ super();
+ super.setName(REALM_NAME);
+ this.config = Config.getInstance();
+ this.tokenCreator = TokenCreator.getInstance(this.config);
+ LOG.info("instantiated");
+ }
+
+ @Override
+ public boolean supports(AuthenticationToken token) {
+ boolean supports = (token instanceof BearerToken)
+ || (this.config.doSupportOdlUsers() && (token instanceof UsernamePasswordToken));
+ LOG.debug("supports {} is {}", token == null ? null : token.getClass().getName(), supports);
+ return supports;
+ }
+
+ @Override
+ public String getName() {
+ return REALM_NAME;
+ }
+
+ @Override
+ protected void assertCredentialsMatch(AuthenticationToken atoken, AuthenticationInfo ai)
+ throws AuthenticationException {
+ LOG.debug("assertCredentialsMatch");
+ if (atoken instanceof BearerToken) {
+ if (this.tokenCreator.verify(((BearerToken) atoken).getToken()) == null) {
+ throw new AuthenticationException("Credentials do not match");
+ }
+ } else if (this.config.doSupportOdlUsers() && (atoken instanceof UsernamePasswordToken)) {
+ //nothing to do
+ } else {
+ throw new AuthenticationException("AuthenticationInfo is not an OAuth2AuthenticationInfo");
+ }
+ }
+
+
+ // check what I can do
+ @Override
+ protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg) {
+
+ LOG.debug("auth info in shiro");
+ Object principal = arg.getPrimaryPrincipal();
+ if (principal instanceof DecodedJWT) {
+ LOG.debug("detected jwt token");
+ try {
+ DecodedJWT token = (DecodedJWT) arg.getPrimaryPrincipal();
+ String[] roles = token.getClaim("roles").asArray(String.class);
+ SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
+ for (String role : roles) {
+ LOG.trace("found role {} in token", role);
+ authorizationInfo.addRole(role);
+ }
+ return authorizationInfo;
+ } catch (ClassCastException e) {
+ LOG.error("Couldn't decode authorization request", e);
+ }
+ } else if (principal instanceof ODLPrincipal) {
+ LOG.debug("detected basic token");
+ ODLPrincipal odlPrincipal = (ODLPrincipal) principal;
+ return new SimpleAuthorizationInfo(odlPrincipal.getRoles());
+ }
+ return new SimpleAuthorizationInfo();
+ }
+
+
+
+ // check who I am
+ @Override
+ protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+
+ LOG.debug("auth token in shiro:");
+ if (token instanceof UsernamePasswordToken && this.config.doSupportOdlUsers()) {
+ LOG.debug("basic auth token found");
+ return super.doGetAuthenticationInfo(token);
+ } else if (token instanceof BearerToken) {
+ LOG.debug("jwt token found");
+ BearerToken oauthToken = (BearerToken) token;
+
+ DecodedJWT jwt = this.tokenCreator.verify(oauthToken.getToken());
+ if (jwt != null) {
+ SimpleAuthenticationInfo authenticationInfo =
+ new SimpleAuthenticationInfo(jwt, token.getCredentials(), getName());
+ return authenticationInfo;
+
+ }
+ } else {
+ LOG.debug("no valid token found");
+ }
+ throw new AuthenticationException("unable to verify token " + token);
+
+ }
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java
new file mode 100644
index 000000000..6798026f3
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java
@@ -0,0 +1,347 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;
+
+import com.fasterxml.jackson.annotation.JsonGetter;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonSetter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Config {
+
+ private static final Logger LOG = LoggerFactory.getLogger(Config.class);
+ private static final String DEFAULT_CONFIGFILENAME = "etc/oauth-provider.config.json";
+ private static final String ENVVARIABLE = "${";
+ private static final String REGEXENVVARIABLE = "(\\$\\{[A-Z0-9_-]+\\})";
+ private static final Pattern pattern = Pattern.compile(REGEXENVVARIABLE);
+ private static final String DEFAULT_TOKENISSUER = "Opendaylight";
+ private static final String DEFAULT_TOKENSECRET = generateSecret();
+ private static final String DEFAULT_REDIRECTURI = "/odlux/index.html#/oauth?token=";
+ private static final String DEFAULT_SUPPORTODLUSERS = "true";
+ public static final String TOKENALG_HS256 = "HS256";
+ public static final String TOKENALG_RS256 = "RS256";
+ public static final String TOKENALG_RS512 = "RS512";
+ private static final String CLIENTALG_PRE = "Client";
+ public static final String TOKENALG_CLIENT_RS256 = CLIENTALG_PRE + TOKENALG_RS256;
+ public static final String TOKENALG_CLIENT_RS512 = CLIENTALG_PRE + TOKENALG_RS512;
+ private static final String DEFAULT_TOKEN_ALGORITHM = TOKENALG_HS256;
+
+ private static final long DEFAULT_TOKEN_LIFETIME = 30 * 60;
+ private static final List<String> VALID_ALGORITHMS =
+ Arrays.asList(TOKENALG_HS256, TOKENALG_RS256, TOKENALG_RS512, TOKENALG_CLIENT_RS256, TOKENALG_CLIENT_RS512);
+ private static final List<String> VALID_ALGORITHMS_FOR_INTERNAL_LOGIN =
+ Arrays.asList(TOKENALG_HS256, TOKENALG_RS256, TOKENALG_RS512);
+ private static SecureRandom random;
+ private static Config _instance;
+
+ private List<OAuthProviderConfig> providers;
+ private String redirectUri;
+ private String supportOdlUsers;
+ private String tokenSecret;
+ private String tokenPubKey;
+ private String algorithm;
+ private String tokenIssuer;
+ private String publicUrl;
+ private long tokenLifetime;
+
+ @Override
+ public String toString() {
+ return "Config [providers=" + providers + ", redirectUri=" + redirectUri + ", supportOdlUsers="
+ + supportOdlUsers + ", tokenSecret=***, tokenPubKey=" + tokenPubKey + ", algorithm=" + algorithm
+ + ", tokenIssuer=" + tokenIssuer + ", publicUrl=" + publicUrl + ", tokenLifetime=" + tokenLifetime
+ + "]";
+ }
+
+ public List<OAuthProviderConfig> getProviders() {
+ return providers;
+ }
+
+ public void setProviders(List<OAuthProviderConfig> providers) {
+ this.providers = providers;
+ }
+
+ public String getRedirectUri() {
+ return redirectUri;
+ }
+
+ public void setRedirectUri(String redirectUri) {
+ this.redirectUri = redirectUri;
+ }
+
+ public String getSupportOdlUsers() {
+ return supportOdlUsers;
+ }
+
+ public void setSupportOdlUsers(String supportOdlUsers) {
+ this.supportOdlUsers = supportOdlUsers;
+ }
+
+ public String getTokenSecret() {
+ return tokenSecret;
+ }
+
+ public void setTokenSecret(String tokenSecret) {
+ this.tokenSecret = tokenSecret;
+ }
+
+ public String getAlgorithm() {
+ return this.algorithm;
+ }
+
+ public void setAlgorithm(String alg) {
+ this.algorithm = alg;
+ }
+
+ @JsonGetter("tokenPubKey")
+ public String getPublicKey() {
+ return this.tokenPubKey;
+ }
+
+ @JsonSetter("tokenPubKey")
+ public void setPublicKey(String pubKey) {
+ this.tokenPubKey = pubKey;
+ }
+
+ public String getTokenIssuer() {
+ return tokenIssuer;
+ }
+
+ public void setTokenIssuer(String tokenIssuer) {
+ this.tokenIssuer = tokenIssuer;
+ }
+
+ public String getPublicUrl() {
+ return publicUrl;
+ }
+
+ public void setPublicUrl(String publicUrl) {
+ this.publicUrl = publicUrl;
+ }
+
+ public long getTokenLifetime() {
+ return this.tokenLifetime;
+ }
+
+ public void setTokenLifetime(long lifetime) {
+ this.tokenLifetime = lifetime;
+ }
+
+ @JsonIgnore
+ private void handleEnvironmentVars() {
+ if (isEnvExpression(this.tokenIssuer)) {
+ this.tokenIssuer = getProperty(this.tokenIssuer, null);
+ }
+ if (isEnvExpression(this.tokenSecret)) {
+ this.tokenSecret = getProperty(this.tokenSecret, null);
+ }
+ if (isEnvExpression(this.tokenPubKey)) {
+ this.tokenPubKey = getProperty(this.tokenPubKey, null);
+ }
+ if (isEnvExpression(this.algorithm)) {
+ this.algorithm = getProperty(this.algorithm, null);
+ }
+ if (isEnvExpression(this.publicUrl)) {
+ this.publicUrl = getProperty(this.publicUrl, null);
+ }
+ if (isEnvExpression(this.redirectUri)) {
+ this.redirectUri = getProperty(this.redirectUri, null);
+ }
+ if (isEnvExpression(this.supportOdlUsers)) {
+ this.supportOdlUsers = getProperty(this.supportOdlUsers, null);
+ }
+ if (this.providers != null && !this.providers.isEmpty()) {
+ for (OAuthProviderConfig cfg : this.providers) {
+ cfg.handleEnvironmentVars();
+ }
+ }
+ }
+
+ @JsonIgnore
+ private void handleDefaultValues() {
+ if (this.tokenIssuer == null || this.tokenIssuer.isEmpty()) {
+ this.tokenIssuer = DEFAULT_TOKENISSUER;
+ }
+ if (this.algorithm == null || this.algorithm.isEmpty()) {
+ this.algorithm = DEFAULT_TOKEN_ALGORITHM;
+ }
+ if (TOKENALG_HS256.equals(this.algorithm) && (this.tokenSecret == null || this.tokenSecret.isEmpty())) {
+ this.tokenSecret = DEFAULT_TOKENSECRET;
+ }
+ if (this.redirectUri == null || this.redirectUri.isEmpty() || "null".equals(this.redirectUri)) {
+ this.redirectUri = DEFAULT_REDIRECTURI;
+ }
+ if (this.publicUrl != null && (this.publicUrl.isEmpty() || "null".equals(this.publicUrl))) {
+ this.publicUrl = null;
+ }
+ if (this.supportOdlUsers == null || this.supportOdlUsers.isEmpty()) {
+ this.supportOdlUsers = DEFAULT_SUPPORTODLUSERS;
+ }
+ if (this.tokenLifetime <= 0) {
+ this.tokenLifetime = DEFAULT_TOKEN_LIFETIME;
+ }
+ }
+
+ static boolean isEnvExpression(String key) {
+ return key != null && key.contains(ENVVARIABLE);
+ }
+
+ public static String generateSecret() {
+ return generateSecret(30);
+ }
+
+ public static String generateSecret(int targetStringLength) {
+ int leftLimit = 48; // numeral '0'
+ int rightLimit = 122; // letter 'z'
+ if (random == null) {
+ random = new SecureRandom();
+ }
+ String generatedString = random.ints(leftLimit, rightLimit + 1)
+ .filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97)).limit(targetStringLength)
+ .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();
+ return generatedString;
+ }
+
+ /**
+ *
+ * @param key environment var
+ * @param defValue default value if no env var found
+ * @return
+ */
+ public static String getProperty(final String key, final String defValue) {
+ String value = defValue;
+ //try to read env var
+ boolean found = false;
+ if (isEnvExpression(key)) {
+
+ LOG.info("try to find env var(s) for {}", key);
+ final Matcher matcher = pattern.matcher(key);
+ String tmp = new String(key);
+ while (matcher.find() && matcher.groupCount() > 0) {
+ final String mkey = matcher.group(1);
+ if (mkey != null) {
+ try {
+ LOG.info("match found for v={} and env key={}", key, mkey);
+ String envvar = mkey.substring(2, mkey.length() - 1);
+ String env = System.getenv(envvar);
+ tmp = tmp.replace(mkey, env == null ? "" : env);
+ if (env != null && !env.isEmpty()) {
+ found = true;
+ }
+ } catch (SecurityException e) {
+ LOG.warn("unable to read env {}: {}", key, e);
+ }
+ }
+ }
+ if (found) {
+ value = tmp;
+ }
+ }
+ return value;
+ }
+
+ public static boolean getPropertyBoolean(String key, boolean defaultValue) {
+ final String value = getProperty(key, String.valueOf(defaultValue));
+ return value.equals("true");
+ }
+
+ public static Config load(String filename) throws IOException, InvalidConfigurationException {
+ CustomObjectMapper mapper = new CustomObjectMapper();
+ File file = new File(filename);
+ if (!file.exists()) {
+ throw new FileNotFoundException();
+ }
+ String content = String.join("", Files.readAllLines(file.toPath()));
+ Config cfg = mapper.readValue(content, Config.class);
+ cfg.handleEnvironmentVars();
+ cfg.handleDefaultValues();
+ cfg.validate();
+ return cfg;
+ }
+
+
+ @JsonIgnore
+ private void validate() throws InvalidConfigurationException {
+ //verify that algorithm is supported
+ if (!VALID_ALGORITHMS.contains(this.algorithm)) {
+ throw new InvalidConfigurationException(String.format("Algorithm '%s' is not supported ", this.algorithm));
+ }
+ //verify that set values are matching the algorithm
+ //if hs256 check if secret is set
+ if (this.algorithm.startsWith("HS")) {
+ if (this.tokenSecret == null || this.tokenSecret.isBlank()) {
+ throw new InvalidConfigurationException(
+ String.format("There is no secret set for algorithm '%s'", this.algorithm));
+ }
+ }
+ //if rs256 or rs512 check if secret(private key) and pubkey are set
+ if (this.algorithm.startsWith("RS")) {
+ if (this.tokenSecret == null || this.tokenSecret.isBlank()) {
+ throw new InvalidConfigurationException(
+ String.format("There is no secret set for algorithm '%s'", this.algorithm));
+ }
+ if (this.tokenPubKey == null || this.tokenPubKey.isBlank()) {
+ throw new InvalidConfigurationException(
+ String.format("There is no public key for algorithm '%s'", this.algorithm));
+ }
+ }
+ //if client rs256 or client rs512 check if pubkey are set
+ if (this.algorithm.startsWith("Client")) {
+ if (this.tokenPubKey == null || this.tokenPubKey.isBlank()) {
+ throw new InvalidConfigurationException(
+ String.format("There is no public key for algorithm '%s'", this.algorithm));
+ }
+ }
+ }
+
+ @JsonIgnore
+ public boolean doSupportOdlUsers() {
+ return "true".equals(this.supportOdlUsers);
+ }
+
+
+ public static Config getInstance() throws IOException, InvalidConfigurationException {
+ return getInstance(DEFAULT_CONFIGFILENAME);
+ }
+
+ public static Config getInstance(String filename) throws IOException, InvalidConfigurationException {
+ if (_instance == null) {
+ _instance = load(filename);
+ }
+ return _instance;
+ }
+
+ public boolean loginActive() {
+ return VALID_ALGORITHMS_FOR_INTERNAL_LOGIN.contains(this.algorithm);
+ }
+
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/CustomObjectMapper.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/CustomObjectMapper.java
new file mode 100644
index 000000000..aa23d4dc1
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/CustomObjectMapper.java
@@ -0,0 +1,39 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;
+
+import com.fasterxml.jackson.annotation.JsonInclude.Include;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.MapperFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+public class CustomObjectMapper extends ObjectMapper{
+
+ private static final long serialVersionUID = 1L;
+
+
+ public CustomObjectMapper() {
+ this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+ this.setSerializationInclusion(Include.NON_NULL);
+ this.enable(MapperFeature.USE_GETTERS_AS_SETTERS);
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/InvalidConfigurationException.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/InvalidConfigurationException.java
new file mode 100644
index 000000000..a0e97de74
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/InvalidConfigurationException.java
@@ -0,0 +1,32 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;
+
+public class InvalidConfigurationException extends Exception {
+
+ public InvalidConfigurationException(String str) {
+ super(str);
+ }
+
+ private static final long serialVersionUID = 1L;
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakRole.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakRole.java
new file mode 100644
index 000000000..67186baa7
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakRole.java
@@ -0,0 +1,80 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;
+
+public class KeycloakRole {
+ private String id;
+ private String name;
+ private String description;
+ private boolean composite;
+ private boolean clientRole;
+ private String containerId; // realmname
+
+ public String getName() {
+ return name;
+ }
+
+ public boolean isClientRole() {
+ return clientRole;
+ }
+
+ public void setClientRole(boolean clientRole) {
+ this.clientRole = clientRole;
+ }
+
+ public String getContainerId() {
+ return containerId;
+ }
+
+ public void setContainerId(String containerId) {
+ this.containerId = containerId;
+ }
+
+ public boolean isComposite() {
+ return composite;
+ }
+
+ public void setComposite(boolean composite) {
+ this.composite = composite;
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+} \ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakUserTokenPayload.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakUserTokenPayload.java
new file mode 100644
index 000000000..c99ec0d71
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakUserTokenPayload.java
@@ -0,0 +1,231 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.List;
+
+/**
+ * {
+ "exp": 1610362593,
+ "iat": 1610361393,
+ "jti": "09bd6f2c-5dba-44a0-bd76-cd0d440137d0",
+ "iss": "http://10.20.11.160:8080/auth/realms/onap",
+ "aud": "account",
+ "sub": "446a24bc-d8a0-43dd-afa5-e56eed75deb8",
+ "typ": "Bearer",
+ "azp": "admin-cli",
+ "session_state": "db2c96f4-cc9b-47e8-a83f-a01c50d656f2",
+ "acr": "1",
+ "realm_access": {
+ "roles": [
+ "provision",
+ "offline_access",
+ "uma_authorization"
+ ]
+ },
+ "resource_access": {
+ "account": {
+ "roles": [
+ "manage-account",
+ "manage-account-links",
+ "view-profile"
+ ]
+ }
+ },
+ "scope": "profile email",
+ "email_verified": false,
+ "name": "Luke Skywalker",
+ "preferred_username": "luke.skywalker",
+ "given_name": "Luke",
+ "family_name": "Skywalker",
+ "email": "luke.skywalker@sdnr.onap.org"
+}
+ * @author jack
+ *
+ */
+public class KeycloakUserTokenPayload {
+
+ private long exp;
+ private long iat;
+ private String jti;
+ private String iss;
+ private String aud;
+ private String sub;
+ private String typ;
+ private String azp;
+ @JsonProperty("session_state")
+ private String sessionState;
+ private String acr;
+ @JsonProperty("realm_access")
+ private RealmAccessData realmAccess;
+ @JsonProperty("resource_access")
+ private ResourceAccessData resourceAccess;
+ private String scope;
+ @JsonProperty("email_verified")
+ private String emailVerified;
+ private String name;
+ @JsonProperty("preferred_username")
+ private String preferredUsername;
+ @JsonProperty("given_name")
+ private String givenName;
+ @JsonProperty("family_name")
+ private String familyName;
+ private String email;
+
+ public long getExp() {
+ return exp;
+ }
+ public void setExp(long exp) {
+ this.exp = exp;
+ }
+ public long getIat() {
+ return iat;
+ }
+ public void setIat(long iat) {
+ this.iat = iat;
+ }
+ public String getJti() {
+ return jti;
+ }
+ public void setJti(String jti) {
+ this.jti = jti;
+ }
+ public String getIss() {
+ return iss;
+ }
+ public void setIss(String iss) {
+ this.iss = iss;
+ }
+ public String getAud() {
+ return aud;
+ }
+ public void setAud(String aud) {
+ this.aud = aud;
+ }
+ public String getSub() {
+ return sub;
+ }
+ public void setSub(String sub) {
+ this.sub = sub;
+ }
+ public String getTyp() {
+ return typ;
+ }
+ public void setTyp(String typ) {
+ this.typ = typ;
+ }
+ public String getAzp() {
+ return azp;
+ }
+ public void setAzp(String azp) {
+ this.azp = azp;
+ }
+ public String getSessionState() {
+ return sessionState;
+ }
+ public void setSessionState(String sessionState) {
+ this.sessionState = sessionState;
+ }
+ public String getAcr() {
+ return acr;
+ }
+ public void setAcr(String acr) {
+ this.acr = acr;
+ }
+ public RealmAccessData getRealmAccess() {
+ return realmAccess;
+ }
+ public void setRealmAccess(RealmAccessData realmAccess) {
+ this.realmAccess = realmAccess;
+ }
+ public ResourceAccessData getResourceAccess() {
+ return resourceAccess;
+ }
+ public void setResourceAccess(ResourceAccessData resourceAccess) {
+ this.resourceAccess = resourceAccess;
+ }
+ public String getScope() {
+ return scope;
+ }
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+ public String getEmailVerified() {
+ return emailVerified;
+ }
+ public void setEmailVerified(String emailVerified) {
+ this.emailVerified = emailVerified;
+ }
+ public String getName() {
+ return name;
+ }
+ public void setName(String name) {
+ this.name = name;
+ }
+ public String getPreferredUsername() {
+ return preferredUsername;
+ }
+ public void setPreferredUsername(String preferredUsername) {
+ this.preferredUsername = preferredUsername;
+ }
+ public String getGivenName() {
+ return givenName;
+ }
+ public void setGivenName(String givenName) {
+ this.givenName = givenName;
+ }
+ public String getFamilyName() {
+ return familyName;
+ }
+ public void setFamilyName(String familyName) {
+ this.familyName = familyName;
+ }
+ public String getEmail() {
+ return email;
+ }
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+
+ public static class RealmAccessData {
+ private List<String> roles;
+
+ public List<String> getRoles(){
+ return this.roles;
+ }
+ public void setRoles(List<String> roles) {
+ this.roles = roles;
+ }
+ }
+ public static class ResourceAccessData {
+ private RealmAccessData account;
+
+ public RealmAccessData getAccount() {
+ return this.account;
+ }
+ public void setAccount(RealmAccessData account) {
+ this.account = account;
+ }
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/NoDefinitionFoundException.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/NoDefinitionFoundException.java
new file mode 100644
index 000000000..d13be9602
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/NoDefinitionFoundException.java
@@ -0,0 +1,33 @@
+/*
+ * ============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.data;
+
+public class NoDefinitionFoundException extends Exception {
+
+ private static final long serialVersionUID = 1L;
+
+ public NoDefinitionFoundException(String message) {
+ super(message);
+ }
+
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthProviderConfig.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthProviderConfig.java
new file mode 100644
index 000000000..4fb0d0069
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthProviderConfig.java
@@ -0,0 +1,202 @@
+/*
+ * ============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.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 url;
+ private String internalUrl;
+ private String clientId;
+ private String secret;
+ private String id;
+ private String title;
+ private String scope;
+ private String realmName;
+ private String openIdConfigUrl;
+
+ private boolean trustAll;
+ private OAuthProvider type;
+ private Map<String, String> roleMapping;
+
+ public OAuthProvider getType() {
+ return type;
+ }
+
+ public OAuthProviderConfig(String id, String url, String internalUrl, String clientId, String secret, String scope,
+ String title, String realmName, String openIdConfigUrl, boolean trustAll) {
+ this.id = id;
+ this.url = url;
+ this.internalUrl = internalUrl;
+ this.clientId = clientId;
+ this.secret = secret;
+ this.scope = scope;
+ this.title = title;
+ this.realmName = realmName;
+ this.trustAll = trustAll;
+ this.openIdConfigUrl = openIdConfigUrl;
+ this.roleMapping = new HashMap<>();
+ }
+
+ @Override
+ public String toString() {
+ return "OAuthProviderConfig [url=" + url + ", clientId=" + clientId + ", secret=" + secret + ", id=" + id
+ + ", title=" + title + ", scope=" + scope + ", realmName=" + realmName + ", trustAll=" + trustAll
+ + ", type=" + type + ", roleMapping=" + roleMapping + "]";
+ }
+
+ public void setType(OAuthProvider type) {
+ this.type = type;
+ }
+
+ public OAuthProviderConfig() {
+ this(null, null, null, null, null, null, null, null, null, false);
+ }
+
+ public void setUrl(String url) {
+ this.url = url;
+ }
+
+ public void setClientId(String clientId) {
+ this.clientId = clientId;
+ }
+
+ public void setSecret(String secret) {
+ this.secret = secret;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public void setScope(String scope) {
+ this.scope = scope;
+ }
+
+ public String getId() {
+ return this.id;
+ }
+
+ public String getUrl() {
+ return this.url;
+ }
+
+ public String getClientId() {
+ return this.clientId;
+ }
+
+ public String getSecret() {
+ return this.secret;
+ }
+
+ public String getTitle() {
+ return this.title;
+ }
+
+ public String getScope() {
+ return this.scope;
+ }
+
+ public String getRealmName() {
+ return realmName;
+ }
+
+ public void setRealmName(String realmName) {
+ this.realmName = realmName;
+ }
+
+ public boolean trustAll() {
+ return trustAll;
+ }
+
+ public void setTrustAll(boolean trustAll) {
+ this.trustAll = trustAll;
+ }
+
+ public Map<String, String> getRoleMapping() {
+ return roleMapping;
+ }
+
+ public void setRoleMapping(Map<String, String> roleMapping) {
+ this.roleMapping = roleMapping;
+ }
+
+ public String getInternalUrl() {
+ return internalUrl;
+ }
+
+ public void setInternalUrl(String internalUrl) {
+ this.internalUrl = internalUrl;
+ }
+
+ public void setOpenIdConfigUrl(String openIdConfigUrl){ this.openIdConfigUrl = openIdConfigUrl;}
+
+ public String getOpenIdConfigUrl() { return this.openIdConfigUrl;}
+ @JsonIgnore
+ public void handleEnvironmentVars() {
+ if (Config.isEnvExpression(this.id)) {
+ this.id = Config.getProperty(this.id, null);
+ }
+ if (Config.isEnvExpression(this.url)) {
+ this.url = Config.getProperty(this.url, null);
+ }
+ if (Config.isEnvExpression(this.internalUrl)) {
+ this.internalUrl = Config.getProperty(this.internalUrl, null);
+ }
+ if (Config.isEnvExpression(this.clientId)) {
+ this.clientId = Config.getProperty(this.clientId, null);
+ }
+ if (Config.isEnvExpression(this.secret)) {
+ this.secret = Config.getProperty(this.secret, null);
+ }
+ if (Config.isEnvExpression(this.scope)) {
+ this.scope = Config.getProperty(this.scope, null);
+ }
+ if (Config.isEnvExpression(this.title)) {
+ this.title = Config.getProperty(this.title, null);
+ }
+ if (Config.isEnvExpression(this.realmName)) {
+ this.realmName = Config.getProperty(this.realmName, null);
+ }
+ if (Config.isEnvExpression(this.openIdConfigUrl)) {
+ this.openIdConfigUrl = Config.getProperty(this.openIdConfigUrl, null);
+ }
+ }
+
+ @JsonIgnore
+ public String getUrlOrInternal() {
+ return this.internalUrl != null && this.internalUrl.length() > 0 ? this.internalUrl : this.url;
+ }
+
+ @JsonIgnore
+ public boolean hasToBeConfigured(){
+ return this.openIdConfigUrl!=null && this.openIdConfigUrl.length()>0;
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthResponseData.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthResponseData.java
new file mode 100644
index 000000000..0e25b5b0f
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthResponseData.java
@@ -0,0 +1,88 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;
+
+public class OAuthResponseData {
+
+ private String access_token;
+ private double expires_in;
+ private double refresh_expires_in;
+ private String refresh_token;
+ private String token_type;
+ private String id_token;
+
+ public OAuthResponseData() {
+ }
+
+ public OAuthResponseData(String token) {
+ this.access_token = token;
+ }
+
+ public String getAccess_token() {
+ return access_token;
+ }
+
+ public String getToken_type() {
+ return token_type;
+ }
+
+ public void setToken_type(String token_type) {
+ this.token_type = token_type;
+ }
+
+ public String getRefresh_token() {
+ return refresh_token;
+ }
+
+ public void setRefresh_token(String refresh_token) {
+ this.refresh_token = refresh_token;
+ }
+
+ public double getRefresh_expires_in() {
+ return refresh_expires_in;
+ }
+
+ public void setRefresh_expires_in(double refresh_expires_in) {
+ this.refresh_expires_in = refresh_expires_in;
+ }
+
+ public double getExpires_in() {
+ return expires_in;
+ }
+
+ public void setExpires_in(double expires_in) {
+ this.expires_in = expires_in;
+ }
+
+ public void setAccess_token(String access_token) {
+ this.access_token = access_token;
+ }
+
+ public void setId_token(String id_token){ this.id_token = id_token;}
+ public String getId_token(){ return this.id_token;}
+ @Override
+ public String toString() {
+ return "OAuthResponseData [access_token=" + access_token + ", expires_in=" + expires_in
+ + ", refresh_expires_in=" + refresh_expires_in + ", refresh_token=" + refresh_token + ", token_type="
+ + token_type + "]";
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthToken.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthToken.java
new file mode 100644
index 000000000..0371f377d
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthToken.java
@@ -0,0 +1,57 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import org.apache.shiro.authc.BearerToken;
+
+public class OAuthToken {
+ private final String access_token;
+ private final String token_type;
+ private final long expires_at;
+ private final long issued_at;
+
+ public OAuthToken(BearerToken btoken) {
+ this.access_token = btoken.getToken();
+ this.token_type = "Bearer";
+ DecodedJWT token = JWT.decode(this.access_token);
+ this.expires_at = token.getExpiresAt().getTime() / 1000L;
+ this.issued_at = token.getIssuedAt().getTime() / 1000L;
+ }
+
+ public String getAccess_token() {
+ return access_token;
+ }
+
+ public String getToken_type() {
+ return token_type;
+ }
+
+ public long getExpires_at() {
+ return expires_at;
+ }
+ public long getIssued_at() {
+ return issued_at;
+ }
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlPolicy.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlPolicy.java
new file mode 100644
index 000000000..19eb4b68e
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlPolicy.java
@@ -0,0 +1,130 @@
+/*
+ * ============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.data;
+
+public class OdlPolicy {
+
+ private String path;
+ private PolicyMethods methods;
+
+
+ public OdlPolicy() {
+
+ }
+
+ public OdlPolicy(String path, PolicyMethods methods) {
+ this.path = path;
+ this.methods = methods;
+ }
+
+ public PolicyMethods getMethods() {
+ return methods;
+ }
+
+ public void setMethods(PolicyMethods methods) {
+ this.methods = methods;
+ }
+
+ public String getPath() {
+ return path;
+ }
+
+ public void setPath(String path) {
+ this.path = path;
+ }
+
+ public static OdlPolicy allowAll(String path) {
+ return new OdlPolicy(path, PolicyMethods.allowAll());
+ }
+
+ public static OdlPolicy denyAll(String path) {
+ return new OdlPolicy(path, PolicyMethods.denyAll());
+ }
+
+ public static class PolicyMethods {
+ private boolean get;
+ private boolean post;
+ private boolean put;
+ private boolean delete;
+ private boolean patch;
+
+ public PolicyMethods() {
+ this(false, false, false, false, false);
+ }
+
+ public PolicyMethods(boolean get, boolean post, boolean put, boolean del, boolean patch) {
+ this.get = get;
+ this.post = post;
+ this.put = put;
+ this.delete = del;
+ this.patch = patch;
+ }
+
+ public boolean isGet() {
+ return get;
+ }
+
+ public void setGet(boolean get) {
+ this.get = get;
+ }
+
+ public boolean isPost() {
+ return post;
+ }
+
+ public void setPost(boolean post) {
+ this.post = post;
+ }
+
+ public boolean isPut() {
+ return put;
+ }
+
+ public void setPut(boolean put) {
+ this.put = put;
+ }
+
+ public boolean isDelete() {
+ return delete;
+ }
+
+ public void setDelete(boolean delete) {
+ this.delete = delete;
+ }
+
+ public boolean isPatch() {
+ return patch;
+ }
+
+ public void setPatch(boolean patch) {
+ this.patch = patch;
+ }
+
+ public static PolicyMethods allowAll() {
+ return new PolicyMethods(true, true, true, true, true);
+ }
+
+ public static PolicyMethods denyAll() {
+ return new PolicyMethods(false, false, false, false, false);
+ }
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlShiroConfiguration.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlShiroConfiguration.java
new file mode 100644
index 000000000..f5e067450
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlShiroConfiguration.java
@@ -0,0 +1,67 @@
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;
+
+import java.util.List;
+
+public class OdlShiroConfiguration {
+
+ private List<MainItem> main;
+ private List<UrlItem> urls;
+
+
+
+ public List<MainItem> getMain() {
+ return main;
+ }
+
+ public void setMain(List<MainItem> main) {
+ this.main = main;
+ }
+ public List<UrlItem> getUrls() {
+ return urls;
+ }
+ public void setUrls(List<UrlItem> urls) {
+ this.urls = urls;
+ }
+ public OdlShiroConfiguration(){
+
+ }
+
+ public static class BaseItem{
+ private String pairKey;
+ private String pairValue;
+
+ public String getPairKey() {
+ return pairKey;
+ }
+
+ public void setPairKey(String pairKey) {
+ this.pairKey = pairKey;
+ }
+
+ public String getPairValue() {
+ return pairValue;
+ }
+
+ public void setPairValue(String pairValue) {
+ this.pairValue = pairValue;
+ }
+
+ public BaseItem(){
+
+ }
+
+ }
+
+ public static class MainItem extends BaseItem{
+ public MainItem(){
+ super();
+ }
+
+ }
+ public static class UrlItem extends BaseItem{
+ public UrlItem(){
+ super();
+ }
+ }
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlXmlMapper.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlXmlMapper.java
new file mode 100644
index 000000000..cbdc1d0d9
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlXmlMapper.java
@@ -0,0 +1,44 @@
+/*
+ * ============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.data;
+
+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.yang.mapper.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();
+ this.setAnnotationIntrospector(introspector);
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OpenIdConfigResponseData.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OpenIdConfigResponseData.java
new file mode 100644
index 000000000..d94631fe3
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OpenIdConfigResponseData.java
@@ -0,0 +1,65 @@
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;
+
+public class OpenIdConfigResponseData {
+
+ private String issuer;
+ private String authorization_endpoint;
+ private String token_endpoint;
+ private String userinfo_endpoint;
+
+ private String end_session_endpoint;
+ private String jwks_uri;
+
+ public OpenIdConfigResponseData(){
+
+ }
+
+ public String getIssuer() {
+ return issuer;
+ }
+
+ public void setIssuer(String issuer) {
+ this.issuer = issuer;
+ }
+
+ public String getAuthorization_endpoint() {
+ return authorization_endpoint;
+ }
+
+ public void setAuthorization_endpoint(String authorization_endpoint) {
+ this.authorization_endpoint = authorization_endpoint;
+ }
+
+ public String getToken_endpoint() {
+ return token_endpoint;
+ }
+
+ public void setToken_endpoint(String token_endpoint) {
+ this.token_endpoint = token_endpoint;
+ }
+
+ public String getUserinfo_endpoint() {
+ return userinfo_endpoint;
+ }
+
+ public void setUserinfo_endpoint(String userinfo_endpoint) {
+ this.userinfo_endpoint = userinfo_endpoint;
+ }
+
+ public String getJwks_uri() {
+ return jwks_uri;
+ }
+
+ public void setJwks_uri(String jwks_uri) {
+ this.jwks_uri = jwks_uri;
+ }
+
+ public String getEnd_session_endpoint() {
+ return end_session_endpoint;
+ }
+
+ public void setEnd_session_endpoint(String end_session_endpoint) {
+ this.end_session_endpoint = end_session_endpoint;
+ }
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/UnableToConfigureOAuthService.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/UnableToConfigureOAuthService.java
new file mode 100644
index 000000000..b791a4040
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/UnableToConfigureOAuthService.java
@@ -0,0 +1,12 @@
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;
+
+public class UnableToConfigureOAuthService extends Exception {
+
+ public UnableToConfigureOAuthService(String configUrl){
+ super(String.format("Unable to configure OAuth service from url %s", configUrl));
+ }
+ public UnableToConfigureOAuthService(String configUrl, int responseCode){
+ super(String.format("Unable to configure OAuth service from url %s. bad response with code %d", configUrl, responseCode));
+ }
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/UserTokenPayload.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/UserTokenPayload.java
new file mode 100644
index 000000000..f7731f0b8
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/UserTokenPayload.java
@@ -0,0 +1,103 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;
+
+import java.util.List;
+
+public class UserTokenPayload {
+
+ public static final String PROVIDERID_INTERNAL="Internal";
+
+ private List<String> roles;
+ private String preferredUsername;
+ private String givenName;
+ private String familyName;
+ private long exp;
+ private long iat;
+
+ private String providerId;
+
+ public long getExp() {
+ return exp;
+ }
+
+ public long getIat() {
+ return this.iat;
+ }
+
+ public void setPreferredUsername(String preferredUsername) {
+ this.preferredUsername = preferredUsername;
+ }
+
+ public void setGivenName(String givenName) {
+ this.givenName = givenName;
+ }
+
+ public void setFamilyName(String familyName) {
+ this.familyName = familyName;
+ }
+
+ public void setExp(long exp) {
+ this.exp = exp;
+ }
+
+ public void setIat(long iat) {
+ this.iat = iat;
+ }
+
+ public String getPreferredUsername() {
+ return preferredUsername;
+ }
+
+ public String getGivenName() {
+ return givenName;
+ }
+
+ public String getFamilyName() {
+ return familyName;
+ }
+
+ public List<String> getRoles() {
+ return this.roles;
+ }
+
+ public void setRoles(List<String> roles) {
+ this.roles = roles;
+ }
+
+ public void setProviderId(String providerId){ this.providerId = providerId;}
+
+ public String getProviderId(){ return this.providerId;}
+
+ public static UserTokenPayload createInternal(String username, List<String> roles) {
+ UserTokenPayload data = new UserTokenPayload();
+ data.setPreferredUsername(username);
+ data.setRoles(roles);
+ data.setProviderId(PROVIDERID_INTERNAL);
+ return data;
+ }
+
+
+ public boolean isInternal() {
+ return PROVIDERID_INTERNAL.equals(this.providerId);
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/filters/AnyRoleHttpAuthenticationFilter.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/filters/AnyRoleHttpAuthenticationFilter.java
new file mode 100644
index 000000000..0dc58efff
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/filters/AnyRoleHttpAuthenticationFilter.java
@@ -0,0 +1,75 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.filters;
+
+import java.util.Arrays;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.web.filter.authz.RolesAuthorizationFilter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * Requires the requesting user to be {@link org.apache.shiro.subject.Subject#isAuthenticated() authenticated} for the
+ * request to continue, and if they're not, requires the user to login via the HTTP Bearer protocol-specific challenge.
+ * Upon successful login, they're allowed to continue on to the requested resource/url.
+ * <p/>
+ * The {@link #onAccessDenied(ServletRequest, ServletResponse)} method will only be called if the subject making the
+ * request is not {@link org.apache.shiro.subject.Subject#isAuthenticated() authenticated}
+ *
+ * @see <a href="https://tools.ietf.org/html/rfc2617">RFC 2617</a>
+ * @see <a href="https://tools.ietf.org/html/rfc6750#section-2.1">OAuth2 Authorization Request Header Field</a>
+ * @since 1.5
+ */
+
+public class AnyRoleHttpAuthenticationFilter extends RolesAuthorizationFilter {
+
+ /**
+ * This class's private logger.
+ */
+ private static final Logger LOG = LoggerFactory.getLogger(AnyRoleHttpAuthenticationFilter.class);
+
+ @Override
+ public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
+ final Subject subject = getSubject(request, response);
+ final String[] rolesArray = (String[]) mappedValue;
+ LOG.debug("isAccessAllowed {}", Arrays.asList(rolesArray));
+
+ if (rolesArray == null || rolesArray.length == 0) {
+ //no roles specified, so nothing to check - allow access.
+ LOG.debug("no role specified: access allowed");
+ return true;
+ }
+
+ for (String roleName : rolesArray) {
+ LOG.debug("checking role {}", roleName);
+ if (subject.hasRole(roleName)) {
+ LOG.debug("role matched to {}: access allowed", roleName);
+ return true;
+ }
+ }
+ LOG.debug("no role matched: access denied");
+ return false;
+ }
+} \ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/filters/BearerAndBasicHttpAuthenticationFilter.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/filters/BearerAndBasicHttpAuthenticationFilter.java
new file mode 100644
index 000000000..51c064819
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/filters/BearerAndBasicHttpAuthenticationFilter.java
@@ -0,0 +1,161 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.filters;
+
+import java.util.Locale;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.codec.Base64;
+import org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter;
+import org.apache.shiro.web.filter.authc.BearerHttpAuthenticationFilter;
+import org.apache.shiro.web.util.WebUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class BearerAndBasicHttpAuthenticationFilter extends BearerHttpAuthenticationFilter {
+
+ // defined in lower-case for more efficient string comparison
+ private static final Logger LOG = LoggerFactory.getLogger(BearerAndBasicHttpAuthenticationFilter.class);
+ private ODLHttpAuthenticationHelperFilter basicAuthFilter;
+
+ public BearerAndBasicHttpAuthenticationFilter() {
+ this.basicAuthFilter = new ODLHttpAuthenticationHelperFilter();
+ }
+
+ protected static final String OPTIONS_HEADER = "OPTIONS";
+
+ @Override
+ protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
+ final String authHeader = this.getAuthzHeader(request);
+ if (authHeader != null && authHeader.startsWith("Basic")) {
+ return this.createBasicAuthToken(request, response);
+ }
+ return super.createToken(request, response);
+ }
+
+ @Override
+ protected String[] getPrincipalsAndCredentials(String scheme, String token) {
+ LOG.debug("getPrincipalsAndCredentials with scheme {} and token {}", scheme, token);
+ if (scheme.toLowerCase().equals("basic")) {
+ return this.basicAuthFilter.getPrincipalsAndCredentials(scheme, token);
+ }
+ return super.getPrincipalsAndCredentials(scheme, token);
+ }
+
+ @Override
+ protected boolean isLoginAttempt(String authzHeader) {
+ LOG.debug("isLoginAttempt with header {}", authzHeader);
+ if (this.basicAuthFilter.isLoginAttempt(authzHeader)) {
+ return true;
+ }
+ return super.isLoginAttempt(authzHeader);
+ }
+
+ @Override
+ protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
+ final HttpServletRequest httpRequest = WebUtils.toHttp(request);
+ final String httpMethod = httpRequest.getMethod();
+ //always allow options requests
+ if (OPTIONS_HEADER.equalsIgnoreCase(httpMethod)) {
+ return true;
+ }
+
+ if (this.basicAuthFilter.isAccessAllowed(httpRequest, response, mappedValue)) {
+ LOG.debug("isAccessAllowed succeeded on basicAuth");
+ return true;
+ }
+
+ return super.isAccessAllowed(request, response, mappedValue);
+ }
+
+ protected AuthenticationToken createBasicAuthToken(ServletRequest request, ServletResponse response) {
+ String authorizationHeader = getAuthzHeader(request);
+ if (authorizationHeader == null || authorizationHeader.length() == 0) {
+ // Create an empty authentication token since there is no
+ // Authorization header.
+ return createToken("", "", request, response);
+ }
+
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("Attempting to execute login with headers [" + authorizationHeader + "]");
+ }
+
+ String[] prinCred = getPrincipalsAndCredentials(authorizationHeader, request);
+ if (prinCred == null || prinCred.length < 2) {
+ // Create an authentication token with an empty password,
+ // since one hasn't been provided in the request.
+ String username = prinCred == null || prinCred.length == 0 ? "" : prinCred[0];
+ return createToken(username, "", request, response);
+ }
+
+ String username = prinCred[0];
+ String password = prinCred[1];
+
+ return createToken(username, password, request, response);
+ }
+
+ private static class ODLHttpAuthenticationHelperFilter extends BasicHttpAuthenticationFilter {
+
+ private static final Logger LOG = LoggerFactory.getLogger(ODLHttpAuthenticationHelperFilter.class);
+
+ // defined in lower-case for more efficient string comparison
+ protected static final String BEARER_SCHEME = "bearer";
+
+ protected static final String OPTIONS_HEADER = "OPTIONS";
+
+ public ODLHttpAuthenticationHelperFilter() {
+ LOG.info("Creating the ODLHttpAuthenticationFilter");
+ }
+
+ @Override
+ protected String[] getPrincipalsAndCredentials(String scheme, String encoded) {
+ final String decoded = Base64.decodeToString(encoded);
+ // attempt to decode username/password; otherwise decode as token
+ if (decoded.contains(":")) {
+ return decoded.split(":");
+ }
+ return new String[]{encoded};
+ }
+
+ @Override
+ protected boolean isLoginAttempt(String authzHeader) {
+ final String authzScheme = getAuthzScheme().toLowerCase(Locale.ROOT);
+ final String authzHeaderLowerCase = authzHeader.toLowerCase(Locale.ROOT);
+ return authzHeaderLowerCase.startsWith(authzScheme)
+ || authzHeaderLowerCase.startsWith(BEARER_SCHEME);
+ }
+
+ @Override
+ protected boolean isAccessAllowed(ServletRequest request, ServletResponse response,
+ Object mappedValue) {
+ final HttpServletRequest httpRequest = WebUtils.toHttp(request);
+ final String httpMethod = httpRequest.getMethod();
+ if (OPTIONS_HEADER.equalsIgnoreCase(httpMethod)) {
+ return true;
+ } else {
+ return super.isAccessAllowed(httpRequest, response, mappedValue);
+ }
+ }
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/filters/CustomizedMDSALDynamicAuthorizationFilter.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/filters/CustomizedMDSALDynamicAuthorizationFilter.java
new file mode 100644
index 000000000..27ca3b3f9
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/filters/CustomizedMDSALDynamicAuthorizationFilter.java
@@ -0,0 +1,188 @@
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.filters;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+import com.google.common.collect.Iterables;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.concurrent.ExecutionException;
+import javax.servlet.Filter;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.shiro.subject.Subject;
+import org.apache.shiro.web.filter.authz.AuthorizationFilter;
+import org.opendaylight.mdsal.binding.api.ClusteredDataTreeChangeListener;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.opendaylight.mdsal.binding.api.DataTreeIdentifier;
+import org.opendaylight.mdsal.binding.api.DataTreeModification;
+import org.opendaylight.mdsal.binding.api.ReadTransaction;
+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.Policies;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.permission.Permissions;
+import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@SuppressWarnings("checkstyle:AbbreviationAsWordInName")
+public class CustomizedMDSALDynamicAuthorizationFilter extends AuthorizationFilter
+ implements ClusteredDataTreeChangeListener<HttpAuthorization> {
+
+ private static final Logger LOG = LoggerFactory.getLogger(CustomizedMDSALDynamicAuthorizationFilter.class);
+
+ private static final DataTreeIdentifier<HttpAuthorization> AUTHZ_CONTAINER = DataTreeIdentifier.create(
+ LogicalDatastoreType.CONFIGURATION, InstanceIdentifier.create(HttpAuthorization.class));
+
+ private static DataBroker dataBroker;
+
+ public static void setDataBroker(DataBroker dataBroker2){
+ dataBroker = dataBroker2;
+ }
+ private ListenerRegistration<?> reg;
+ private volatile ListenableFuture<Optional<HttpAuthorization>> authContainer;
+
+ public CustomizedMDSALDynamicAuthorizationFilter() {
+
+ }
+
+ @Override
+ public Filter processPathConfig(final String path, final String config) {
+ /*if (dataBroker == null){
+ throw new RuntimeException("dataBroker is not initialized");
+ }*/
+
+ return super.processPathConfig(path, config);
+ }
+
+ @Override
+ public void destroy() {
+ if (reg != null) {
+ reg.close();
+ reg = null;
+ }
+ super.destroy();
+ }
+
+ @Override
+ public void onDataTreeChanged(final Collection<DataTreeModification<HttpAuthorization>> changes) {
+ final HttpAuthorization newVal = Iterables.getLast(changes).getRootNode().getDataAfter();
+ LOG.debug("Updating authorization information to {}", newVal);
+ authContainer = Futures.immediateFuture(Optional.ofNullable(newVal));
+ }
+
+ @Override
+ public boolean isAccessAllowed(final ServletRequest request, final ServletResponse response,
+ final Object mappedValue) {
+ if (dataBroker == null){
+ throw new RuntimeException("dataBroker is not initialized");
+ }
+ if(reg == null){
+ try (ReadTransaction tx = dataBroker.newReadOnlyTransaction()) {
+ authContainer = tx.read(AUTHZ_CONTAINER.getDatastoreType(), AUTHZ_CONTAINER.getRootIdentifier());
+ }
+ reg = dataBroker.registerDataTreeChangeListener(AUTHZ_CONTAINER, this);
+ }
+ checkArgument(request instanceof HttpServletRequest, "Expected HttpServletRequest, received {}", request);
+
+
+ final boolean defaultReturnValue=false;
+ final Subject subject = getSubject(request, response);
+ final HttpServletRequest httpServletRequest = (HttpServletRequest)request;
+ final String requestURI = httpServletRequest.getRequestURI();
+ LOG.debug("isAccessAllowed for user={} to requestURI={}", subject, requestURI);
+
+ final Optional<HttpAuthorization> authorizationOptional;
+ try {
+ authorizationOptional = authContainer.get();
+ } catch (ExecutionException | InterruptedException e) {
+ // Something went completely wrong trying to read the authz container. Deny access.
+ LOG.warn("MDSAL attempt to read Http Authz Container failed, disallowing access", e);
+ return false;
+ }
+
+ if (!authorizationOptional.isPresent()) {
+ // The authorization container does not exist-- hence no authz rules are present
+ // Allow access.
+ LOG.debug("Authorization Container does not exist");
+ return defaultReturnValue;
+ }
+
+ final HttpAuthorization httpAuthorization = authorizationOptional.get();
+ final var policies = httpAuthorization.getPolicies();
+ List<Policies> policiesList = policies != null ? policies.getPolicies() : null;
+ if (policiesList == null || policiesList.isEmpty()) {
+ // The authorization container exists, but no rules are present. Allow access.
+ LOG.debug("Exiting early since no authorization rules exist");
+ sendError(response, 403, "");
+ return defaultReturnValue;
+ }
+
+ // Sort the Policies list based on index
+ policiesList = new ArrayList<>(policiesList);
+ policiesList.sort(Comparator.comparing(Policies::getIndex));
+
+ for (Policies policy : policiesList) {
+ final String resource = policy.getResource();
+ final boolean pathsMatch = pathsMatch(resource, requestURI);
+ if (pathsMatch) {
+ LOG.debug("paths match for policy {} pattern={} and requestURI={}", policy.getIndex(), resource, requestURI);
+ final String method = httpServletRequest.getMethod();
+ LOG.trace("method={}", method);
+ List<Permissions> permissions = policy.getPermissions();
+ LOG.trace("perm={}", permissions);
+ if(permissions !=null) {
+ for (Permissions permission : permissions) {
+ final String role = permission.getRole();
+ LOG.trace("role={}", role);
+ Set<Permissions.Actions> actions = permission.getActions();
+ if (actions != null) {
+ for (Permissions.Actions action : actions) {
+ LOG.trace("action={}", action.getName());
+ if (action.getName().equalsIgnoreCase(method)) {
+ final boolean hasRole = subject.hasRole(role);
+ LOG.trace("hasRole({})={}", role, hasRole);
+ if (hasRole) {
+ return true;
+ }
+ }
+ }
+ }
+ else{
+ LOG.trace("no actions found");
+ }
+ }
+ }
+ else {
+ LOG.trace("no permissions found");
+ }
+ LOG.debug("couldn't authorize the user for access");
+ sendError(response, 403, "");
+ return false;
+ }
+ }
+ LOG.debug("no path found that matches {}", requestURI);
+ sendError(response, 403, "");
+ return defaultReturnValue;
+ }
+
+ private void sendError(ServletResponse response, int code, String message) {
+ if(response instanceof HttpServletResponse){
+ try {
+ ((HttpServletResponse)response).sendError(code, message);
+ } catch (IOException e) {
+ LOG.warn("unable to send {} {} response: ", code, message, e);
+ }
+ }
+ else{
+ LOG.warn("unable to send {} {} response", code, message);
+ }
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/AuthHttpServlet.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/AuthHttpServlet.java
new file mode 100644
index 000000000..562fe5472
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/AuthHttpServlet.java
@@ -0,0 +1,527 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.http;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.servlet.ServletException;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.ShiroException;
+import org.apache.shiro.authc.BearerToken;
+import org.apache.shiro.codec.Base64;
+import org.apache.shiro.session.Session;
+import org.apache.shiro.subject.Subject;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.*;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlShiroConfiguration.MainItem;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlShiroConfiguration.UrlItem;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.filters.CustomizedMDSALDynamicAuthorizationFilter;
+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.AuthenticationException;
+import org.opendaylight.aaa.api.Claim;
+import org.opendaylight.aaa.api.PasswordCredentialAuth;
+import org.opendaylight.aaa.api.PasswordCredentials;
+import org.opendaylight.aaa.tokenauthrealm.auth.PasswordCredentialBuilder;
+import org.opendaylight.mdsal.binding.api.DataBroker;
+import org.osgi.service.http.HttpService;
+import org.osgi.service.http.NamespaceException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class AuthHttpServlet extends HttpServlet {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AuthHttpServlet.class.getName());
+ private static final long serialVersionUID = 1L;
+ private static final String BASEURI = "/oauth";
+ private static final String LOGINURI = BASEURI + "/login";
+ 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 REDIRECTID_REGEX = "^\\" + BASEURI + "\\/redirect\\/([^\\/]+)$";
+ private static final String LOGIN_REDIRECT_REGEX = "^\\" + LOGINURI + "\\/([^\\/]+)$";
+ 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";
+
+ private static final String LOGOUT_REDIRECT_URL_PARAMETER = "redirect_uri";
+ private static final String CLASSNAME_ODLBASICAUTH =
+ "org.opendaylight.aaa.shiro.filters.ODLHttpAuthenticationFilter";
+ private static final String CLASSNAME_ODLBEARERANDBASICAUTH =
+ "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 static final String URI_PRE = BASEURI;
+
+ private static final String CONFIGFILE ="/opt/opendaylight/etc/opendaylight/datastore/initial/config/aaa-app-config.xml";
+ private final ObjectMapper mapper;
+ /* state <=> AuthProviderService> */
+ private final Map<String, AuthService> providerStore;
+ private final TokenCreator tokenCreator;
+ private final Config config;
+ private static MdSalAuthorizationStore mdsalAuthStore;
+ private PasswordCredentialAuth passwordCredentialAuth;
+ private OdlShiroConfiguration shiroConfiguration;
+
+ public AuthHttpServlet() throws IllegalArgumentException, IOException, InvalidConfigurationException,
+ UnableToConfigureOAuthService {
+ this(CONFIGFILE);
+ }
+ public AuthHttpServlet(String shiroconfigfile) throws IllegalArgumentException, IOException, InvalidConfigurationException,
+ UnableToConfigureOAuthService {
+ this.config = Config.getInstance();
+ this.shiroConfiguration = loadShiroConfig(shiroconfigfile);
+ 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)));
+ }
+ }
+
+ public void setDataBroker(DataBroker dataBroker) {
+ CustomizedMDSALDynamicAuthorizationFilter.setDataBroker(dataBroker);
+ mdsalAuthStore = new MdSalAuthorizationStore(dataBroker);
+ }
+
+ public void setPasswordCredentialAuth(PasswordCredentialAuth passwordCredentialAuth) {
+ this.passwordCredentialAuth = passwordCredentialAuth;
+ }
+
+
+ public void onUnbindService(HttpService httpService) {
+ httpService.unregister(AuthHttpServlet.URI_PRE);
+
+ }
+
+ public void onBindService(HttpService httpService)
+ throws ServletException, NamespaceException {
+ if (httpService == null) {
+ LOG.warn("Unable to inject HttpService into loader.");
+ } else {
+ httpService.registerServlet(AuthHttpServlet.URI_PRE, this, null, null);
+ LOG.info("oauth servlet registered.");
+ }
+ }
+ private static OdlShiroConfiguration loadShiroConfig(String filename) throws IOException {
+ OdlXmlMapper mapper = new OdlXmlMapper();
+ return mapper.readValue(new File(filename), OdlShiroConfiguration.class);
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ LOG.debug("GET request for {}", req.getRequestURI());
+ 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 (req.getRequestURI().equals(LOGOUTURI)) {
+ this.handleLogout(req, resp);
+ } else if (POLICIESURI.equals(req.getRequestURI())) {
+ this.sendResponse(resp, HttpServletResponse.SC_OK, this.getPoliciesForUser(req));
+ } else if (req.getRequestURI().startsWith(REDIRECTURI)) {
+ this.handleRedirect(req, resp);
+ } else {
+ resp.sendError(HttpServletResponse.SC_NOT_FOUND);
+ }
+
+ }
+
+ private void handleLogout(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ final String bearerToken = this.tokenCreator.getBearerToken(req, true);
+ String redirectUrl = req.getParameter(LOGOUT_REDIRECT_URL_PARAMETER);
+ if (redirectUrl == null) {
+ redirectUrl = this.config.getPublicUrl();
+ }
+ UserTokenPayload userInfo = this.tokenCreator.decode(bearerToken);
+ if (bearerToken != null && userInfo != null && !userInfo.isInternal()) {
+ AuthService provider = this.providerStore.getOrDefault(userInfo.getProviderId(), null);
+
+ if (provider != null) {
+ provider.sendLogoutRedirectResponse(bearerToken, resp, redirectUrl);
+ this.logout();
+ return;
+ }
+ }
+ this.logout();
+ resp.sendRedirect(redirectUrl);
+
+ }
+
+ 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) {
+ 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
+ * <p>
+ * urlEntries: "anon" -> any access allowed "authcXXX" -> no grouping rule -> any access for user allowed "authcXXX,
+ * roles[abc] -> user needs to have role abc "authcXXX, roles["abc,def"] -> user needs to have roles abc AND def
+ * "authcXXX, anyroles[abc] -> user needs to have role abc "authcXXX, anyroles["abc,def"] -> user needs to have
+ * roles abc OR def
+ *
+ * @param req
+ * @return
+ */
+ private List<OdlPolicy> getPoliciesForUser(HttpServletRequest req) {
+ List<OdlPolicy> policies = new ArrayList<>();
+ List<UrlItem> urlRules = this.shiroConfiguration.getUrls();
+ UserTokenPayload data = this.getUserInfo(req);
+ if (urlRules != null) {
+ LOG.debug("try to find rules for user {} with roles {}",
+ data == null ? "null" : data.getPreferredUsername(), data == null ? "null" : data.getRoles());
+ final String regex = "^([^,]+)[,]?[\\ ]?([anyroles]+)?(\\[\"?([a-zA-Z,]+)\"?\\])?";
+ final Pattern pattern = Pattern.compile(regex);
+ Matcher matcher;
+ for (UrlItem urlRule : urlRules) {
+ matcher = pattern.matcher(urlRule.getPairValue());
+ if (matcher.find()) {
+ try {
+ final String authClass = getAuthClass(matcher.group(1));
+ Optional<OdlPolicy> policy = Optional.empty();
+ //anon access allowed
+ if (authClass == null) {
+ policy = Optional.of(OdlPolicy.allowAll(urlRule.getPairKey()));
+ } else if (authClass.equals(CLASSNAME_ODLBASICAUTH) || "authcBasic".equals(urlRule.getPairKey())) {
+ 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, data);
+ }
+ if (policy.isPresent()) {
+ policies.add(policy.get());
+ } 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);
+ }
+
+ } else {
+ LOG.warn("unable to detect url role value: {}", urlRule.getPairValue());
+ }
+ }
+ } else {
+ LOG.debug("no url rules found");
+ }
+ return policies;
+ }
+
+ /**
+ * extract policy rule for user from MD-SAL not yet supported
+ *
+ * @param urlRule
+ * @param data
+ * @return
+ */
+ private Optional<OdlPolicy> getMdSalBasedPolicy(UrlItem urlRule, UserTokenPayload data) {
+ if (mdsalAuthStore != null) {
+ return data != null ? 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
+ * @return
+ */
+ private Optional<OdlPolicy> getTokenBasedPolicy(UrlItem urlRule, Matcher matcher,
+ UserTokenPayload data) {
+ final String url = urlRule.getPairKey();
+ 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));
+ }
+ }
+ 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)) {
+ return Optional.of(OdlPolicy.allowAll(url));
+ } else {
+ 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)) {
+ return Optional.of(OdlPolicy.allowAll(url));
+ } else {
+ return Optional.of(OdlPolicy.denyAll(url));
+ }
+ } else {
+ LOG.warn("unable to detect url role value: {}", urlRule.getPairValue());
+ }
+ } else {
+ return Optional.of(OdlPolicy.denyAll(url));
+ }
+ return Optional.empty();
+ }
+
+ private String getAuthClass(String key) throws NoDefinitionFoundException {
+ if ("anon".equals(key)) {
+ return null;
+ }
+ if("authcBasic".equals(key)){
+ return CLASSNAME_ODLBASICAUTH;
+ }
+ List<MainItem> list = shiroConfiguration.getMain();
+ Optional<MainItem> main =
+ list == null ? Optional.empty() : list.stream().filter(e -> e.getPairKey().equals(key)).findFirst();
+ if (main.isPresent()) {
+ return main.get().getPairValue();
+ }
+ throw new NoDefinitionFoundException("unable to find def for " + key);
+ }
+
+ private UserTokenPayload getUserInfo(HttpServletRequest req) {
+ if (isBearer(req)) {
+ UserTokenPayload data = this.tokenCreator.decode(req);
+ if (data != null) {
+ return data;
+ }
+ } else if (isBasic(req)) {
+ String username = getBasicAuthUsername(req);
+ if (username != null) {
+ final String domain = getBasicAuthDomain(username);
+ if (!username.contains("@")) {
+ username = String.format("%s@%s", username, domain);
+ }
+ List<String> roles = List.of();// odlIdentityService.listRoles(username, domain);
+ return UserTokenPayload.createInternal(username, roles);
+ }
+ }
+ return null;
+ }
+
+ private static String getBasicAuthDomain(String username) {
+ if (username.contains("@")) {
+ return username.split("@")[1];
+ }
+ return DEFAULT_DOMAIN;
+ }
+
+ private static String getBasicAuthUsername(HttpServletRequest req) {
+ final String header = req.getHeader(HEAEDER_AUTHORIZATION);
+ final String decoded = Base64.decodeToString(header.substring(6));
+ // attempt to decode username/password; otherwise decode as token
+ if (decoded.contains(":")) {
+ return decoded.split(":")[0];
+ }
+ LOG.warn("unable to detect username from basicauth header {}", header);
+ return null;
+ }
+
+ private static boolean isBasic(HttpServletRequest req) {
+ final String header = req.getHeader(HEAEDER_AUTHORIZATION);
+ return header != null && header.startsWith("Basic");
+ }
+
+ private static boolean isBearer(HttpServletRequest req) {
+ final String header = req.getHeader(HEAEDER_AUTHORIZATION);
+ return header != null && header.startsWith("Bearer");
+ }
+
+ private boolean rolesMatch(List<String> userRoles, List<String> policyRoles, boolean any) {
+ if (any) {
+ for (String policyRole : policyRoles) {
+ if (userRoles.contains(policyRole)) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ for (String policyRole : policyRoles) {
+ if (!userRoles.contains(policyRole)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ }
+
+ 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}:\\/\\/[^\\/]+)";
+ final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
+ final Matcher matcher = pattern.matcher(tmp);
+ if (matcher.find()) {
+ hostUrl = matcher.group(1);
+ }
+ }
+ 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());
+ }
+ return configs;
+ }
+
+ /**
+ * GET /oauth/redirect/{providerID}
+ *
+ * @param req
+ * @param resp
+ * @throws IOException
+ */
+ private void handleRedirect(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+ final String uri = req.getRequestURI();
+ final Matcher matcher = REDIRECTID_PATTERN.matcher(uri);
+ if (matcher.find()) {
+ AuthService provider = this.providerStore.getOrDefault(matcher.group(1), null);
+ if (provider != null) {
+ //provider.setLocalHostUrl(getHost(req));
+ provider.handleRedirect(req, resp, getHost(req));
+ return;
+ }
+ }
+ resp.sendError(HttpServletResponse.SC_FORBIDDEN);
+ }
+
+ @Override
+ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+
+ LOG.debug("POST request for {}", req.getRequestURI());
+ if (this.config.loginActive() && this.config.doSupportOdlUsers() && LOGINURI.equals(req.getRequestURI())) {
+ final String username = req.getParameter("username");
+ final String domain = req.getParameter("domain");
+ BearerToken token =
+ this.doLogin(username, req.getParameter("password"), domain != null ? domain : DEFAULT_DOMAIN);
+ if (token != null) {
+ sendResponse(resp, HttpServletResponse.SC_OK, new OAuthToken(token));
+ LOG.debug("login for odluser {} succeeded", username);
+ return;
+ } else {
+ LOG.debug("login failed");
+ }
+
+ }
+ resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
+ }
+
+ private BearerToken doLogin(String username, String password, String domain) {
+
+ PasswordCredentials pc =
+ (new PasswordCredentialBuilder()).setUserName(username).setPassword(password).setDomain(domain).build();
+ Claim claim = null;
+ try {
+ claim = this.passwordCredentialAuth.authenticate(pc);
+ } catch (AuthenticationException e) {
+ LOG.warn("unable to authentication user {} for domain {}: ", username, domain, e);
+ }
+ if (claim != null) {
+ List<String> roles = claim.roles().stream().toList();//odlIdentityService.listRoles(username, domain);
+ UserTokenPayload data = new UserTokenPayload();
+ data.setPreferredUsername(username);
+ data.setFamilyName("");
+ data.setGivenName(username);
+ data.setIat(this.tokenCreator.getDefaultIat());
+ data.setExp(this.tokenCreator.getDefaultExp());
+ data.setRoles(roles);
+ return this.tokenCreator.createNewJWT(data);
+ } else {
+ LOG.info("unable to read auth from authservice");
+ }
+ return null;
+ }
+
+
+/* private void sendResponse(HttpServletResponse resp, int code) throws IOException {
+ this.sendResponse(resp, code, null);
+ }*/
+
+ private void sendResponse(HttpServletResponse resp, int code, Object data) throws IOException {
+ byte[] output = data != null ? mapper.writeValueAsString(data).getBytes() : new byte[0];
+ // output
+ resp.setStatus(code);
+ resp.setContentLength(output.length);
+ resp.setContentType("application/json");
+ ServletOutputStream os = resp.getOutputStream();
+ os.write(output);
+
+ }
+
+ private void logout() {
+ /* final Subject subject = SecurityUtils.getSubject();
+ try {
+ subject.logout();
+ Session session = subject.getSession(false);
+ if (session != null) {
+ session.stop();
+ }
+ } catch (ShiroException e) {
+ LOG.debug("Couldn't log out {}", subject, e);
+ }*/
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/HeadersOnlyHttpServletRequest.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/HeadersOnlyHttpServletRequest.java
new file mode 100644
index 000000000..31b6d696f
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/HeadersOnlyHttpServletRequest.java
@@ -0,0 +1,469 @@
+/*
+ * ============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.http;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpUpgradeHandler;
+import javax.servlet.http.Part;
+
+public class HeadersOnlyHttpServletRequest implements HttpServletRequest{
+
+ private final Map<String,String> headers;
+
+ public HeadersOnlyHttpServletRequest(Map<String,String> headers) {
+ this.headers = headers;
+ }
+ @Override
+ public Object getAttribute(String name) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setCharacterEncoding(String env) throws UnsupportedEncodingException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public int getContentLength() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public long getContentLengthLong() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public String getContentType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getParameter(String name) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getParameterNames() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String[] getParameterValues(String name) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Map<String, String[]> getParameterMap() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getProtocol() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getScheme() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getServerName() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int getServerPort() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public BufferedReader getReader() throws IOException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getRemoteHost() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public void setAttribute(String name, Object o) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void removeAttribute(String name) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public Locale getLocale() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Enumeration<Locale> getLocales() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isSecure() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String path) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getRealPath(String path) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int getRemotePort() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public String getLocalName() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getLocalAddr() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int getLocalPort() {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync() throws IllegalStateException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
+ throws IllegalStateException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isAsyncStarted() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isAsyncSupported() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public AsyncContext getAsyncContext() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public DispatcherType getDispatcherType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getAuthType() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Cookie[] getCookies() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public long getDateHeader(String name) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public String getHeader(String name) {
+ return this.headers.getOrDefault(name,null);
+ }
+
+ @Override
+ public Enumeration<String> getHeaders(String name) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getHeaderNames() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public int getIntHeader(String name) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ @Override
+ public String getMethod() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getPathInfo() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getPathTranslated() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getContextPath() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getQueryString() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getRemoteUser() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isUserInRole(String role) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getRequestedSessionId() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getRequestURI() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public StringBuffer getRequestURL() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String getServletPath() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession(boolean create) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public String changeSessionId() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdValid() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromCookie() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromURL() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromUrl() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ public void login(String username, String password) throws ServletException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public void logout() throws ServletException {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ public Collection<Part> getParts() throws IOException, ServletException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public Part getPart(String name) throws IOException, ServletException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass) throws IOException, ServletException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappedBaseHttpResponse.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappedBaseHttpResponse.java
new file mode 100644
index 000000000..6b1a8eddd
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappedBaseHttpResponse.java
@@ -0,0 +1,63 @@
+/*
+ * ============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.http.client;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.onap.ccsdk.features.sdnr.wt.common.http.BaseHTTPResponse;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.CustomObjectMapper;
+
+public class MappedBaseHttpResponse<T> {
+
+
+ public static final int CODE404 = 404;
+ public static final int CODE200 = 200;
+ public static final MappedBaseHttpResponse<String> UNKNOWN = new MappedBaseHttpResponse<>(-1, null);
+ private static final ObjectMapper mapper = new CustomObjectMapper();
+ public final int code;
+ public final T body;
+
+ public MappedBaseHttpResponse(int code, String body, Class<T> clazz)
+ throws JsonMappingException, JsonProcessingException {
+ this(code, body != null ? mapper.readValue(body, clazz) : null);
+ }
+
+ private MappedBaseHttpResponse(int code, T body) {
+ this.code = code;
+ this.body = body;
+ }
+
+ public MappedBaseHttpResponse(BaseHTTPResponse response, Class<T> clazz)
+ throws JsonMappingException, JsonProcessingException {
+ this(response.code, response.body, clazz);
+ }
+
+ @Override
+ public String toString() {
+ return "BaseHTTPResponse [code=" + code + ", body=" + body + "]";
+ }
+
+ public boolean isSuccess() {
+ return this.code == CODE200;
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappingBaseHttpClient.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappingBaseHttpClient.java
new file mode 100644
index 000000000..ca455dc72
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappingBaseHttpClient.java
@@ -0,0 +1,63 @@
+/*
+ * ============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.http.client;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Optional;
+import org.onap.ccsdk.features.sdnr.wt.common.http.BaseHTTPClient;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MappingBaseHttpClient extends BaseHTTPClient {
+
+ private static Logger LOG = LoggerFactory.getLogger(MappingBaseHttpClient.class);
+
+ public MappingBaseHttpClient(String base, boolean trustAllCerts) {
+ super(base, trustAllCerts);
+ }
+
+ public MappingBaseHttpClient(String host) {
+ super(host);
+ }
+
+ public <T> Optional<MappedBaseHttpResponse<String>> sendMappedRequest(String uri, String method, String body,
+ Map<String, String> headers) {
+ return this.sendMappedRequest(uri, method, body != null ? body.getBytes(CHARSET) : null, headers, String.class);
+ }
+
+ public <T> Optional<MappedBaseHttpResponse<T>> sendMappedRequest(String uri, String method, String body,
+ Map<String, String> headers, Class<T> clazz) {
+ return this.sendMappedRequest(uri, method, body != null ? body.getBytes(CHARSET) : null, headers, clazz);
+ }
+
+ protected <T> Optional<MappedBaseHttpResponse<T>> sendMappedRequest(String uri, String method, byte[] body,
+ Map<String, String> headers, Class<T> clazz) {
+ try {
+ return Optional.of(new MappedBaseHttpResponse<T>(this.sendRequest(uri, method, body, headers), clazz));
+ } catch (IOException e) {
+ LOG.warn("problem during request for {}: ", uri, e);
+ }
+ return Optional.empty();
+ }
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/AuthService.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/AuthService.java
new file mode 100644
index 000000000..2dc0b5746
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/AuthService.java
@@ -0,0 +1,356 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.exceptions.JWTDecodeException;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.IOException;
+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;
+
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.*;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.AuthHttpServlet;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.client.MappedBaseHttpResponse;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.client.MappingBaseHttpClient;
+import org.apache.shiro.authc.BearerToken;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AuthService {
+
+
+ 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 final String tokenEndpointRelative;
+ private final String authEndpointAbsolute;
+ private final String logoutEndpointAbsolute;
+
+ private final Map<String, String> logoutTokenMap;
+ protected abstract String getTokenVerifierUri();
+
+ protected abstract Map<String, String> getAdditionalTokenVerifierParams();
+
+ protected abstract ResponseType getResponseType();
+
+ protected abstract boolean doSeperateRolesRequest();
+
+ protected abstract UserTokenPayload mapAccessToken(String spayload)
+ throws JsonMappingException, JsonProcessingException;
+
+ protected abstract String getLoginUrl(String callbackUrl);
+ protected abstract String getLogoutUrl();
+
+ protected abstract UserTokenPayload requestUserRoles(String access_token, long issued_at, long expires_at);
+
+ protected abstract boolean verifyState(String state);
+
+ public AuthService(OAuthProviderConfig config, String redirectUri, TokenCreator tokenCreator) throws UnableToConfigureOAuthService {
+ 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.getUrlOrInternal(), this.config.trustAll());
+ this.logoutTokenMap = new HashMap<>();
+ if (this.config.hasToBeConfigured()){
+ Optional<MappedBaseHttpResponse<OpenIdConfigResponseData>> oresponse = this.httpClient.sendMappedRequest(
+ this.config.getOpenIdConfigUrl(), "GET", null, null, OpenIdConfigResponseData.class);
+ if(oresponse.isEmpty()){
+ throw new UnableToConfigureOAuthService(this.config.getOpenIdConfigUrl());
+ }
+ MappedBaseHttpResponse<OpenIdConfigResponseData> response = oresponse.get();
+ if(!response.isSuccess()){
+ throw new UnableToConfigureOAuthService(this.config.getOpenIdConfigUrl(), response.code);
+ }
+ this.tokenEndpointRelative = trimUrl(this.config.getUrlOrInternal(),response.body.getToken_endpoint());
+ this.authEndpointAbsolute = extendUrl(this.config.getUrlOrInternal(),response.body.getAuthorization_endpoint());
+ this.logoutEndpointAbsolute = extendUrl(this.config.getUrlOrInternal(),response.body.getEnd_session_endpoint());
+ }
+ else{
+ this.tokenEndpointRelative = null;
+ this.authEndpointAbsolute = null;
+ this.logoutEndpointAbsolute = null;
+ }
+ }
+
+ public static String trimUrl(String baseUrl, String endpoint) {
+ if(endpoint.startsWith(baseUrl)){
+ return endpoint.substring(baseUrl.length());
+ }
+ if(endpoint.startsWith("http")){
+ return endpoint.substring(endpoint.indexOf("/",8));
+ }
+ return endpoint;
+ }
+ public static String extendUrl(String baseUrl, String endpoint) {
+ if(endpoint.startsWith("http")){
+ endpoint= endpoint.substring(endpoint.indexOf("/",8));
+ }
+ if(baseUrl.endsWith("/")){
+ baseUrl=baseUrl.substring(0,baseUrl.length()-2);
+ }
+ return baseUrl+endpoint;
+ }
+
+ public PublicOAuthProviderConfig getConfig() {
+ return new PublicOAuthProviderConfig(this);
+ }
+
+ 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, host);
+ break;
+ case TOKEN:
+ sendErrorResponse(resp, "not yet implemented");
+ break;
+ case SESSION_STATE:
+ break;
+ }
+ }
+
+ public void sendLoginRedirectResponse(HttpServletResponse resp, String callbackUrl) {
+ resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+ String url = this.authEndpointAbsolute !=null?String.format(
+ "%s?client_id=%s&response_type=code&scope=%s&redirect_uri=%s",
+ this.authEndpointAbsolute, urlEncode(this.config.getClientId()), this.config.getScope(),
+ urlEncode(callbackUrl)):this.getLoginUrl(callbackUrl);
+ resp.setHeader("Location", url);
+ }
+ public void sendLogoutRedirectResponse(String token, HttpServletResponse resp, String redirectUrl)
+ throws IOException {
+ String idToken = this.logoutTokenMap.getOrDefault(token, null);
+ String logoutEndpoint = this.logoutEndpointAbsolute!=null?this.logoutEndpointAbsolute:this.getLogoutUrl();
+ if(idToken==null) {
+ LOG.debug("unable to find token in map. Do unsafe logout.");
+ resp.sendRedirect(this.logoutEndpointAbsolute);
+ return;
+ }
+ LOG.debug("id token found. redirect to specific logout");
+ resp.sendRedirect(String.format("%s?id_token_hint=%s&post_logout_redirect_uri=%s",logoutEndpoint, idToken,
+ urlEncode(redirectUrl)));
+ }
+
+
+
+ private static void sendErrorResponse(HttpServletResponse resp, String message) throws IOException {
+ resp.sendError(HttpServletResponse.SC_NOT_FOUND, message);
+ }
+
+ private void handleRedirectCode(HttpServletRequest req, HttpServletResponse resp, String host) throws IOException {
+ final String code = req.getParameter("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()) {
+ LOG.debug("do a seperate role request");
+ long expiresAt = this.tokenCreator.getDefaultExp();
+ long issuedAt = this.tokenCreator.getDefaultIat();
+ UserTokenPayload data = this.requestUserRoles(response.getAccess_token(), issuedAt, expiresAt);
+ if (data != null) {
+ BearerToken createdToken = this.handleUserInfoToken(data, resp, host);
+ this.logoutTokenMap.put(createdToken.getToken(),response.getId_token());
+ } else {
+ sendErrorResponse(resp, "unable to verify user");
+ }
+ } else {
+ BearerToken createdToken = this.handleUserInfoToken(response.getAccess_token(), resp, host);
+ this.logoutTokenMap.put(createdToken.getToken(),response.getId_token());
+ }
+ } else {
+ sendErrorResponse(resp, "unable to verify code");
+ }
+ }
+
+ private BearerToken handleUserInfoToken(UserTokenPayload data, HttpServletResponse resp, String localHostUrl)
+ throws IOException {
+ BearerToken onapToken = this.tokenCreator.createNewJWT(data);
+ sendTokenResponse(resp, onapToken, localHostUrl);
+ return onapToken;
+ }
+
+ private BearerToken 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='{}'", spayload);
+ UserTokenPayload data = this.mapAccessToken(spayload);
+ return this.handleUserInfoToken(data, resp, localHostUrl);
+ } catch (JWTDecodeException | JsonProcessingException e) {
+ LOG.warn("unable to decode jwt token {}: ", accessToken, e);
+ sendErrorResponse(resp, e.getMessage());
+ }
+ return null;
+ }
+
+
+ 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);
+ resp.setContentLength(output.length);
+ resp.setContentType("application/json");
+ resp.addCookie(this.tokenCreator.createAuthCookie(data));
+ ServletOutputStream os = null;
+ os = resp.getOutputStream();
+ os.write(output);
+ } else {
+ resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+ resp.setHeader("Location", assembleUrl(localHostUrl, this.redirectUri, data.getToken()));
+ resp.addCookie(this.tokenCreator.createAuthCookie(data));
+ }
+ }
+
+
+
+ private static String base64Decode(String data) {
+ return new String(Base64.getDecoder().decode(data), StandardCharsets.UTF_8);
+ }
+
+ private OAuthResponseData getTokenForUser(String code, String localHostUrl) {
+
+ Map<String, String> headers = new HashMap<>();
+ headers.put("Content-Type", "application/x-www-form-urlencoded");
+ headers.put("Accept", "application/json");
+ Map<String, String> params = this.getAdditionalTokenVerifierParams();
+ 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()));
+ StringBuilder body = new StringBuilder();
+ for (Entry<String, String> p : params.entrySet()) {
+ body.append(String.format("%s=%s&", p.getKey(), urlEncode(p.getValue())));
+ }
+
+ String url = this.tokenEndpointRelative !=null?this.tokenEndpointRelative :this.getTokenVerifierUri();
+ Optional<MappedBaseHttpResponse<OAuthResponseData>> response =
+ this.httpClient.sendMappedRequest(url, "POST",
+ body.substring(0, body.length() - 1), headers, OAuthResponseData.class);
+ if (response.isPresent() && response.get().isSuccess()) {
+ return response.get().body;
+ }
+ LOG.warn("problem get token for code {}", code);
+
+ return null;
+ }
+
+ /**
+ * Assemble callback url for service provider {host}{baseUri}/{serviceId} e.g.
+ * http://10.20.0.11:8181/oauth/redirect/keycloak
+ *
+ * @param host
+ * @param baseUri
+ * @param serviceId
+ * @return
+ */
+ public static String assembleRedirectUrl(String host, String baseUri, String serviceId) {
+ return String.format("%s%s/%s", host, baseUri, serviceId);
+ }
+
+ private static String assembleUrl(String host, String uri, String token) {
+ return String.format("%s%s%s", host, uri, token);
+ }
+
+ public static String urlEncode(String s) {
+ return URLEncoder.encode(s, StandardCharsets.UTF_8);
+ }
+
+
+
+ public enum ResponseType {
+ CODE, TOKEN, SESSION_STATE
+ }
+
+
+ public static class PublicOAuthProviderConfig {
+
+ private String id;
+ private String title;
+ private String loginUrl;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getLoginUrl() {
+ return loginUrl;
+ }
+
+ public void setLoginUrl(String loginUrl) {
+ this.loginUrl = loginUrl;
+ }
+
+ public PublicOAuthProviderConfig(AuthService authService) {
+ this.id = authService.config.getId();
+ this.title = authService.config.getTitle();
+ this.loginUrl = String.format(AuthHttpServlet.LOGIN_REDIRECT_FORMAT, authService.config.getId());
+ }
+
+ }
+
+
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/GitlabProviderService.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/GitlabProviderService.java
new file mode 100644
index 000000000..d271948c2
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/GitlabProviderService.java
@@ -0,0 +1,180 @@
+/*
+ * ============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.UnableToConfigureOAuthService;
+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) throws UnableToConfigureOAuthService {
+ 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);
+ }
+
+ @Override
+ protected String getLogoutUrl() {
+ return String.format("%s/oauth/logout", this.config.getUrl());
+ }
+
+ 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 issued_at, long expires_at) {
+ LOG.info("reqesting user roles with token={}", access_token);
+ Map<String, String> authHeaders = new HashMap<>();
+ authHeaders.put("Authorization", String.format("Bearer %s", access_token));
+ 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.setIat(issued_at);
+ 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;
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/KeycloakProviderService.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/KeycloakProviderService.java
new file mode 100644
index 000000000..bdbf9286a
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/KeycloakProviderService.java
@@ -0,0 +1,115 @@
+/*
+ * ============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.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.KeycloakUserTokenPayload;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthProviderConfig;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UnableToConfigureOAuthService;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
+
+public class KeycloakProviderService extends AuthService {
+
+ public static final String ID = "keycloak";
+ private Map<String, String> additionalTokenVerifierParams;
+
+ public KeycloakProviderService(OAuthProviderConfig config, String redirectUri, TokenCreator tokenCreator) throws UnableToConfigureOAuthService {
+ super(config, redirectUri, tokenCreator);
+ this.additionalTokenVerifierParams = new HashMap<>();
+ this.additionalTokenVerifierParams.put("grant_type", "authorization_code");
+ }
+
+ @Override
+ protected String getTokenVerifierUri() {
+ return String.format("/auth/realms/%s/protocol/openid-connect/token", urlEncode(this.config.getRealmName()));
+ }
+
+ @Override
+ protected String getLoginUrl(String callbackUrl) {
+ return String.format(
+ "%s/auth/realms/%s/protocol/openid-connect/auth?client_id=%s&response_type=code&scope=%s&redirect_uri=%s",
+ this.config.getUrl(), urlEncode(this.config.getRealmName()), urlEncode(this.config.getClientId()),
+ this.config.getScope(), urlEncode(callbackUrl));
+ }
+
+ @Override
+ protected String getLogoutUrl() {
+ return String.format("%s/auth/realms/%s/protocol/openid-connect/logout", this.config.getUrl(),
+ urlEncode(this.config.getRealmName()));
+ }
+
+ @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 -> map.getOrDefault(r, r)).collect(Collectors.toList());
+ return filteredRoles;
+ }
+
+ @Override
+ protected ResponseType getResponseType() {
+ return ResponseType.CODE;
+ }
+
+ @Override
+ protected Map<String, String> getAdditionalTokenVerifierParams() {
+ return this.additionalTokenVerifierParams;
+
+ }
+
+ @Override
+ protected boolean doSeperateRolesRequest() {
+ return false;
+ }
+
+ @Override
+ protected UserTokenPayload mapAccessToken(String spayload) throws JsonMappingException, JsonProcessingException {
+ KeycloakUserTokenPayload payload = mapper.readValue(spayload, KeycloakUserTokenPayload.class);
+ UserTokenPayload data = new UserTokenPayload();
+ data.setIat(payload.getIat() * 1000L);
+ data.setExp(payload.getExp() * 1000L);
+ data.setFamilyName(payload.getFamilyName());
+ data.setGivenName(payload.getGivenName());
+ data.setProviderId(this.config.getId());
+ data.setPreferredUsername(payload.getPreferredUsername());
+ data.setRoles(this.mapRoles(payload.getRealmAccess().getRoles()));
+ return data;
+ }
+
+ @Override
+ protected UserTokenPayload requestUserRoles(String access_token, long issued_at, long expires_at) {
+ return null;
+ }
+
+ @Override
+ protected boolean verifyState(String state) {
+ return true;
+ }
+
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/MdSalAuthorizationStore.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/MdSalAuthorizationStore.java
new file mode 100644
index 000000000..4bf35e72d
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/MdSalAuthorizationStore.java
@@ -0,0 +1,118 @@
+/*
+ * ============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.Set;
+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.binding.api.ReadTransaction;
+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();
+ // The implicite close is not handled correctly by underlaying opendaylight netconf service
+ ReadTransaction transaction = this.dataBroker.newReadOnlyTransaction();
+ try {
+ odata = transaction.read(LogicalDatastoreType.CONFIGURATION, iif).get();
+ } catch (ExecutionException e) {
+ LOG.warn("unable to read policies from mdsal: ", e);
+ } catch (InterruptedException e) {
+ LOG.warn("Interrupted!", e);
+ // Restore interrupted state...
+ Thread.currentThread().interrupt();
+ }
+ if (odata.isEmpty()) {
+ return Optional.empty();
+ }
+ List<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.authorization.policies.Policies> data =
+ odata.get().getPolicies();
+ if (data == null) {
+ return Optional.empty();
+ }
+ Optional<org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.authorization.policies.Policies> entry =
+ data.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, Set<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);
+ }
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/NextcloudProviderService.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/NextcloudProviderService.java
new file mode 100644
index 000000000..73bae5d4c
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/NextcloudProviderService.java
@@ -0,0 +1,91 @@
+/*
+ * ============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.Map;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthProviderConfig;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UnableToConfigureOAuthService;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
+
+public class NextcloudProviderService extends AuthService {
+
+ public NextcloudProviderService(OAuthProviderConfig config, String redirectUri, TokenCreator tokenCreator) throws UnableToConfigureOAuthService {
+ super(config, redirectUri, tokenCreator);
+ // TODO Auto-generated constructor stub
+ }
+
+ @Override
+ protected String getTokenVerifierUri() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected Map<String, String> getAdditionalTokenVerifierParams() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected ResponseType getResponseType() {
+ // TODO Auto-generated method stub
+ return ResponseType.TOKEN;
+ }
+
+ @Override
+ protected boolean doSeperateRolesRequest() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ @Override
+ protected UserTokenPayload mapAccessToken(String spayload) throws JsonMappingException, JsonProcessingException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected String getLoginUrl(String callbackUrl) {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ @Override
+ protected String getLogoutUrl() {
+ return null;
+ }
+
+ @Override
+ protected UserTokenPayload requestUserRoles(String access_token, long issued_at, 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
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/OAuthProviderFactory.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/OAuthProviderFactory.java
new file mode 100644
index 000000000..152569930
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/OAuthProviderFactory.java
@@ -0,0 +1,47 @@
+/*
+ * ============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 org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthProviderConfig;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UnableToConfigureOAuthService;
+
+public class OAuthProviderFactory {
+
+
+ public static AuthService create(OAuthProvider key, OAuthProviderConfig config, String redirectUri,
+ TokenCreator tokenCreator) throws UnableToConfigureOAuthService {
+ switch (key) {
+ case KEYCLOAK:
+ 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, GITLAB
+ }
+
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/PemUtils.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/PemUtils.java
new file mode 100644
index 000000000..fac46f6b1
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/PemUtils.java
@@ -0,0 +1,106 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.PublicKey;
+import java.security.spec.EncodedKeySpec;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.PKCS8EncodedKeySpec;
+import java.security.spec.X509EncodedKeySpec;
+import org.bouncycastle.util.io.pem.PemObject;
+import org.bouncycastle.util.io.pem.PemReader;
+
+public class PemUtils {
+
+ private static byte[] parsePEMFile(File pemFile) throws IOException {
+ if (!pemFile.isFile() || !pemFile.exists()) {
+ throw new FileNotFoundException(String.format("The file '%s' doesn't exist.", pemFile.getAbsolutePath()));
+ }
+ return parsePEMFile(new FileReader(pemFile));
+ }
+ private static byte[] parsePEMFile(Reader inputReader) throws IOException {
+ PemReader reader = new PemReader(inputReader);
+ PemObject pemObject = reader.readPemObject();
+ byte[] content = pemObject.getContent();
+ reader.close();
+ return content;
+ }
+ private static PublicKey getPublicKey(byte[] keyBytes, String algorithm) {
+ PublicKey publicKey = null;
+ try {
+ KeyFactory kf = KeyFactory.getInstance(algorithm);
+ EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
+ publicKey = kf.generatePublic(keySpec);
+ } catch (NoSuchAlgorithmException e) {
+ System.out.println("Could not reconstruct the public key, the given algorithm could not be found.");
+ } catch (InvalidKeySpecException e) {
+ System.out.println("Could not reconstruct the public key");
+ }
+
+ return publicKey;
+ }
+
+ private static PrivateKey getPrivateKey(byte[] keyBytes, String algorithm) {
+ PrivateKey privateKey = null;
+ try {
+ KeyFactory kf = KeyFactory.getInstance(algorithm);
+ EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
+ privateKey = kf.generatePrivate(keySpec);
+ } catch (NoSuchAlgorithmException e) {
+ System.out.println("Could not reconstruct the private key, the given algorithm could not be found.");
+ } catch (InvalidKeySpecException e) {
+ System.out.println("Could not reconstruct the private key");
+ }
+
+ return privateKey;
+ }
+
+ public static PublicKey readPublicKeyFromFile(String filepath, String algorithm) throws IOException {
+ byte[] bytes = PemUtils.parsePEMFile(new File(filepath));
+ return PemUtils.getPublicKey(bytes, algorithm);
+ }
+
+ public static PublicKey readPublicKey(String filecontent, String algorithm) throws IOException {
+ byte[] bytes = PemUtils.parsePEMFile(new StringReader(filecontent));
+ return PemUtils.getPublicKey(bytes, algorithm);
+ }
+
+ public static PrivateKey readPrivateKeyFromFile(String filepath, String algorithm) throws IOException {
+ byte[] bytes = PemUtils.parsePEMFile(new File(filepath));
+ return PemUtils.getPrivateKey(bytes, algorithm);
+ }
+
+ public static PrivateKey readPrivateKey(String filecontent, String algorithm) throws IOException {
+ byte[] bytes = PemUtils.parsePEMFile(new StringReader(filecontent));
+ return PemUtils.getPrivateKey(bytes, algorithm);
+ }
+
+} \ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/RSAKeyReader.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/RSAKeyReader.java
new file mode 100644
index 000000000..028dff9dd
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/RSAKeyReader.java
@@ -0,0 +1,47 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers;
+
+import java.io.IOException;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+
+public class RSAKeyReader {
+
+ private static final String PREFIX_FILEURL = "file://";
+
+ public static RSAPrivateKey getPrivateKey(String filenameOrContent) throws IOException {
+ if (filenameOrContent.startsWith(PREFIX_FILEURL)) {
+ return (RSAPrivateKey) PemUtils.readPrivateKeyFromFile(filenameOrContent.substring(PREFIX_FILEURL.length()),
+ "RSA");
+ }
+ return (RSAPrivateKey) PemUtils.readPrivateKey(filenameOrContent, "RSA");
+ }
+
+ public static RSAPublicKey getPublicKey(String filenameOrContent) throws IOException {
+ if (filenameOrContent.startsWith(PREFIX_FILEURL)) {
+ return (RSAPublicKey) PemUtils.readPublicKeyFromFile(filenameOrContent.substring(PREFIX_FILEURL.length()),
+ "RSA");
+ }
+ return (RSAPublicKey) PemUtils.readPublicKey(filenameOrContent, "RSA");
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/TokenCreator.java b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/TokenCreator.java
new file mode 100644
index 000000000..d8720e823
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/TokenCreator.java
@@ -0,0 +1,202 @@
+/*
+ * ============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.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTDecodeException;
+import com.auth0.jwt.exceptions.JWTVerificationException;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import com.auth0.jwt.interfaces.JWTVerifier;
+import java.io.IOException;
+import java.security.Security;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Optional;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.AuthHttpServlet;
+import org.apache.shiro.authc.BearerToken;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TokenCreator {
+
+ private static final Logger LOG = LoggerFactory.getLogger(AuthHttpServlet.class.getName());
+ private final String issuer;
+ private static TokenCreator _instance;
+ private final long tokenLifetimeSeconds;
+ private final Algorithm algorithm;
+
+ private static final String ROLES_CLAIM = "roles";
+ private static final String FAMILYNAME_CLAIM = "family_name";
+ private static final String NAME_CLAIM = "name";
+ private static final String PROVIDERID_CLAIM = "provider_id";
+ private static final String COOKIE_NAME_AUTH = "token";
+
+ static {
+ Security.addProvider(
+ new BouncyCastleProvider()
+ );
+ }
+ public static TokenCreator getInstance(Config config) throws IllegalArgumentException, IOException {
+ if (_instance == null) {
+ _instance = new TokenCreator(config);
+ }
+ return _instance;
+ }
+
+ public static TokenCreator getInstance(String alg, String secret, String issuer, long tokenLifetime)
+ throws IllegalArgumentException, IOException {
+ return getInstance(alg, secret, null, issuer, tokenLifetime);
+ }
+
+ public static TokenCreator getInstance(String alg, String secret, String pubkey, String issuer, long tokenLifetime)
+ throws IllegalArgumentException, IOException {
+ if (_instance == null) {
+ _instance = new TokenCreator(alg, secret, pubkey, issuer, tokenLifetime);
+ }
+ return _instance;
+ }
+
+ private TokenCreator(Config config) throws IllegalArgumentException, IOException {
+ this(config.getAlgorithm(), config.getTokenSecret(), config.getPublicKey(), config.getTokenIssuer(),
+ config.getTokenLifetime());
+ }
+
+ private TokenCreator(String alg, String secret, String pubkey, String issuer, long tokenLifetime)
+ throws IllegalArgumentException, IOException {
+ this.issuer = issuer;
+ this.tokenLifetimeSeconds = tokenLifetime;
+ this.algorithm = this.createAlgorithm(alg, secret, pubkey);
+ }
+
+ private Algorithm createAlgorithm(String alg, String secret, String pubkey)
+ throws IllegalArgumentException, IOException {
+ if (alg == null) {
+ alg = Config.TOKENALG_HS256;
+ }
+ switch (alg) {
+ case Config.TOKENALG_HS256:
+ return Algorithm.HMAC256(secret);
+ case Config.TOKENALG_RS256:
+ return Algorithm.RSA256(RSAKeyReader.getPublicKey(pubkey), RSAKeyReader.getPrivateKey(secret));
+ case Config.TOKENALG_RS512:
+ return Algorithm.RSA512(RSAKeyReader.getPublicKey(pubkey), RSAKeyReader.getPrivateKey(secret));
+ case Config.TOKENALG_CLIENT_RS256:
+ return Algorithm.RSA256(RSAKeyReader.getPublicKey(pubkey), null);
+ case Config.TOKENALG_CLIENT_RS512:
+ return Algorithm.RSA512(RSAKeyReader.getPublicKey(pubkey), null);
+ }
+ throw new IllegalArgumentException(String.format("unable to find algorithm for %s", alg));
+
+ }
+
+ public BearerToken createNewJWT(UserTokenPayload data) {
+ final String token = JWT.create().withIssuer(issuer).withExpiresAt(new Date(data.getExp()))
+ .withIssuedAt(new Date(data.getIat())).withSubject(data.getPreferredUsername())
+ .withClaim(NAME_CLAIM, data.getGivenName()).withClaim(FAMILYNAME_CLAIM, data.getFamilyName())
+ .withClaim(PROVIDERID_CLAIM, data.getProviderId())
+ .withArrayClaim(ROLES_CLAIM, data.getRoles().toArray(new String[data.getRoles().size()]))
+ .sign(this.algorithm);
+ LOG.trace("token created: {}", token);
+ return new BearerToken(token);
+ }
+
+ public DecodedJWT verify(String token) {
+ DecodedJWT jwt = null;
+ LOG.debug("try to verify token {}", token);
+ try {
+ JWTVerifier verifier = JWT.require(this.algorithm).withIssuer(issuer).build();
+ jwt = verifier.verify(token);
+
+ } catch (JWTVerificationException e) {
+ LOG.warn("unable to verify token {}:", token, e);
+ }
+ return jwt;
+ }
+
+ public long getDefaultExp() {
+ return new Date().getTime() + (this.tokenLifetimeSeconds * 1000);
+ }
+
+ public long getDefaultExp(long expIn) {
+ return new Date().getTime() + expIn;
+ }
+
+ public long getDefaultIat() {
+ return new Date().getTime();
+ }
+
+ public String getBearerToken(HttpServletRequest req) {
+ return this.getBearerToken(req, false);
+ }
+
+ public String getBearerToken(HttpServletRequest req, boolean checkCookie) {
+ final String authHeader = req.getHeader("Authorization");
+ if ((authHeader == null || !authHeader.startsWith("Bearer")) && checkCookie) {
+ Cookie[] cookies = req.getCookies();
+ Optional<Cookie> ocookie = Optional.empty();
+ if (cookies != null) {
+ ocookie = Arrays.stream(cookies).filter(c -> c != null && COOKIE_NAME_AUTH.equals(c.getName()))
+ .findFirst();
+ }
+ if (ocookie.isEmpty()) {
+ return null;
+ }
+ return ocookie.get().getValue();
+ }
+ return authHeader.substring(7);
+ }
+
+ public UserTokenPayload decode(HttpServletRequest req) throws JWTDecodeException {
+ final String token = this.getBearerToken(req);
+ return token != null ? this.decode(token) : null;
+ }
+
+ public UserTokenPayload decode(String token) {
+ if (token == null) {
+ return null;
+ }
+ DecodedJWT jwt = JWT.decode(token);
+ UserTokenPayload data = new UserTokenPayload();
+ data.setRoles(Arrays.asList(jwt.getClaim(ROLES_CLAIM).asArray(String.class)));
+ data.setExp(jwt.getExpiresAt().getTime());
+ data.setFamilyName(jwt.getClaim(FAMILYNAME_CLAIM).asString());
+ data.setGivenName(jwt.getClaim(NAME_CLAIM).asString());
+ data.setPreferredUsername(jwt.getClaim(NAME_CLAIM).asString());
+ data.setProviderId(jwt.getClaim(PROVIDERID_CLAIM).asString());
+ return data;
+ }
+
+ public Cookie createAuthCookie(BearerToken data) {
+ Cookie cookie = new Cookie(COOKIE_NAME_AUTH, data.getToken());
+ cookie.setMaxAge((int) this.tokenLifetimeSeconds);
+ cookie.setPath("/");
+ cookie.setHttpOnly(true);
+ cookie.setSecure(true);
+ return cookie;
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestAuthHttpServlet.java b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestAuthHttpServlet.java
new file mode 100644
index 000000000..3e9205733
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestAuthHttpServlet.java
@@ -0,0 +1,404 @@
+/*
+ * ============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 java.util.Set;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import org.junit.Ignore;
+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.mockito.internal.matchers.Any;
+import org.onap.ccsdk.features.sdnr.wt.common.http.BaseHTTPClient;
+import org.onap.ccsdk.features.sdnr.wt.common.test.ServletOutputStreamToByteArrayOutputStream;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.CustomObjectMapper;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.InvalidConfigurationException;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlPolicy;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.AuthHttpServlet;
+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.Claim;
+import org.opendaylight.aaa.api.IdMService;
+import org.apache.shiro.authc.BearerToken;
+import org.opendaylight.aaa.api.PasswordCredentialAuth;
+import org.opendaylight.aaa.api.PasswordCredentials;
+import org.opendaylight.aaa.shiro.web.env.AAAShiroWebEnvironment;
+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 PasswordCredentialAuth passwordCredentialAuth;
+ private static TokenCreator tokenCreator;
+// private static final HttpServletRequest authreq = new HeadersOnlyHttpServletRequest(
+// Map.of("Authorization", BaseHTTPClient.getAuthorizationHeaderValue("admin@sdn", "admin")));
+
+ @BeforeClass
+ public static void init() throws IllegalArgumentException, Exception {
+
+ try {
+ Config config = createConfigFile();
+ tokenCreator = TokenCreator.getInstance(config);
+ servlet = new TestServlet();
+ } catch (IOException | InvalidConfigurationException e) {
+ fail(e.getMessage());
+ }
+ servlet.setDataBroker(dataBroker);
+ passwordCredentialAuth = mock(PasswordCredentialAuth.class);
+
+ servlet.setPasswordCredentialAuth(passwordCredentialAuth);
+ }
+
+ 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, InvalidConfigurationException {
+ 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");
+ Claim claim = new Claim() {
+ @Override
+ public String clientId() {
+ return "admin";
+ }
+
+ @Override
+ public String userId() {
+ return "admin";
+ }
+
+ @Override
+ public String user() {
+ return null;
+ }
+
+ @Override
+ public String domain() {
+ return "sdn";
+ }
+
+ @Override
+ public Set<String> roles() {
+ return Set.of("admin");
+ }
+ };
+ when(passwordCredentialAuth.authenticate(any(PasswordCredentials.class))).thenReturn(claim);
+ 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
+/*
+ @Ignore
+*/
+ 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(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 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 IllegalArgumentException, Exception {
+ super(TESTSHIROCONFIGFILE);
+ }
+
+ @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);
+ }
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestConfig.java b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestConfig.java
new file mode 100644
index 000000000..80ae8cf95
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestConfig.java
@@ -0,0 +1,80 @@
+/*
+ * ============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 java.io.IOException;
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.InvalidConfigurationException;
+
+public class TestConfig {
+
+ public static String TEST_CONFIG_FILENAME = "src/test/resources/test.config.json";
+ public static String TEST_OOMCONFIG_FILENAME = "src/test/resources/oom.test.config.json";
+ public static String TEST_RS256_FILENAME = "src/test/resources/test.configRS256.json";
+ public static String TEST_RS256INVALID_FILENAME = "src/test/resources/test.configRS256-invalid.json";
+ public static String TEST_RS512_FILENAME = "src/test/resources/test.configRS512.json";
+
+
+ @Test
+ public void test() throws IOException, InvalidConfigurationException {
+
+ Config config = Config.load(TEST_CONFIG_FILENAME);
+ System.out.println("config="+config);
+ assertEquals(60*60,config.getTokenLifetime());
+ assertNotNull(config.getAlgorithm());
+ assertNotNull(config.getTokenSecret());
+ //assertNotNull(config.getPublicKey());
+ assertEquals(Config.TOKENALG_HS256, config.getAlgorithm());
+ }
+ @Test
+ public void testOom() throws IOException, InvalidConfigurationException {
+
+ Config config = Config.load(TEST_OOMCONFIG_FILENAME);
+ System.out.println("config="+config);
+ assertEquals(30*60,config.getTokenLifetime());
+
+ }
+ @Test
+ public void testRS256() throws IOException, InvalidConfigurationException {
+
+ Config config = Config.load(TEST_RS256_FILENAME);
+ System.out.println("config="+config);
+ assertEquals(60*60,config.getTokenLifetime());
+
+ }
+ @Test
+ public void testRS512() throws IOException, InvalidConfigurationException {
+
+ Config config = Config.load(TEST_RS512_FILENAME);
+ System.out.println("config="+config);
+ assertEquals(60*60,config.getTokenLifetime());
+
+ }
+ @Test(expected = InvalidConfigurationException.class)
+ public void testRS256Invalid() throws IOException, InvalidConfigurationException {
+
+ Config.load(TEST_RS256INVALID_FILENAME);
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestDeserializer.java b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestDeserializer.java
new file mode 100644
index 000000000..421b61919
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestDeserializer.java
@@ -0,0 +1,101 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import com.fasterxml.jackson.core.JsonProcessingException;
+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;
+
+public class TestDeserializer {
+
+ @Test
+ public void test1() throws IOException {
+ final String token = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ1OHNXaTF4QWxjT1pyelY4X0l2VjliMlJTaFdZUWV4aXZYUXNYLTFTME"
+ + "RNIn0.eyJleHAiOjE2MTAzNjE2OTQsImlhdCI6MTYxMDM2MTM5NCwianRpIjoiOWRhOThmMTYtOTEyOS00N2NmLTgzOGQtNWQzYmVkYzYyZTJjIiwiaXNzIjoiaHR0cDovLzEwLjIwLjExLjE2MDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjE4MzhjNGYyLTVmZTMtNGYwYy1iMmQyLWQzNjRiMjdhNDk5NyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLWNsaSIsInNlc3Npb25fc3RhdGUiOiJjYzcxZmMxZi1hZGQ0LTRhODYtYWU1ZS1jMzRkZjQwM2M3NzIiLCJhY3IiOiIxIiwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiJ9.PUT4NzCM1ej3sNMMCkQa1NuQQwDgn19G-OnWL4NgLvZ3ocJUZ1Yfr9KAPkrJHaiK_HXQqwTA-Ma6Qn7BBMoXNdFjwu0k_HpqyUbBDilGN4wpkGiUeS1p5SW4T_hnWJtwCJ5BYkEvF6WaEbi7MFCbEVO9LVcUvsa-7St1WZ8V8RVfbWgjAu7ejlxe6RYUDMYzIKDj5F5y1-qCyoKzGIjt5ajcA9FWrexHifLJECKO8ZG08Wp7xQld1sYPOdde6XHMwiyNelTwd_EzCBgUw_8664rETGDVtyfuYchowo5Z6fmn4U87L6EGjEuxiAE8f3USy_jh6UF0LnvyTyq_9I"
+ + "M1VA";
+ final String response =
+ "{\"access_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ1OHNXaTF4QWxjT1pyelY4X0l2VjliMlJTaFdZUWV4aXZYUXNYLTFTME"
+ + "RNIn0.eyJleHAiOjE2MTAzNjE2OTQsImlhdCI6MTYxMDM2MTM5NCwianRpIjoiOWRhOThmMTYtOTEyOS00N2NmLTgzOGQtNWQzYmVkYzYyZTJjIiwiaXNzIjoiaHR0cDovLzEwLjIwLjExLjE2MDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjE4MzhjNGYyLTVmZTMtNGYwYy1iMmQyLWQzNjRiMjdhNDk5NyIsInR5cCI6IkJlYXJlciIsImF6cCI6I"
+ + "mFkbWluLWNsaSIsInNlc3Npb25fc3RhdGUiOiJjYzcxZmMxZi1hZGQ0LTRhODYtYWU1ZS1jMzRkZjQwM2M3NzIiLCJhY3IiOiIxIiwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiJ9.PUT4NzCM1ej3sNMMCkQa1NuQQwDgn19G-OnWL4NgLvZ3ocJUZ1Yfr9KAPkrJHaiK_HX"
+ + "QqwTA-Ma6Qn7BBMoXNdFjwu0k_HpqyUbBDilGN4wpkGiUeS1p5SW4T_hnWJtwCJ5BYkEvF6WaEbi7MFCbEVO9LVcUvsa-7St1WZ8V8RVfbWgjAu7ejlxe6RYUDMYzIKDj5F5y1-qCyoKzGIjt5ajcA9FWrexHifLJECKO8ZG08Wp7xQld1sYPOdde6XHMwiyNelTwd_EzCBgUw_8664rETGDVtyfuYchowo5Z6fmn4U87L6EGjEuxiAE8f3USy_jh6UF0LnvyTyq_9I"
+ + "M1VA\",\"expires_in\":300,\"refresh_expires_in\":1800,\"refresh_token\":\"eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICI1NzdiN2Q3MC00NzMwLTQ0MDMtODk4My04ZjJmYTg4M2U2M2EifQ.eyJleHAiOjE2MTAzNjMxOTQsImlhdCI6MTYxMDM2MTM5NCwianRpIjoiMmNjMGY4YWYtNWY2OC00YmFhLWEyOTctNjMxMjk2YzhmY2"
+ + "U5IiwiaXNzIjoiaHR0cDovLzEwLjIwLjExLjE2MDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsImF1ZCI6Imh0dHA6Ly8xMC4yMC4xMS4xNjA6ODA4MC9hdXRoL3JlYWxtcy9tYXN0ZXIiLCJzdWIiOiIxODM4YzRmMi01ZmUzLTRmMGMtYjJkMi1kMzY0YjI3YTQ5OTciLCJ0eXAiOiJSZWZyZXNoIiwiYXpwIjoiYWRtaW4tY2xpIiwic2Vzc2lvbl9zdGF0ZSI6I"
+ + "mNjNzFmYzFmLWFkZDQtNGE4Ni1hZTVlLWMzNGRmNDAzYzc3MiIsInNjb3BlIjoiZW1haWwgcHJvZmlsZSJ9.qutqcFuQW-GzaCVNMfiYrbmHYD34GYwBqIbaQbJSY-g\",\"token_type\":\"bearer\",\"not-before-policy\":0,\"session_state\":\"cc71fc1f-add4-4a86-ae5e-c34df403c772\",\"scope\":\"email profile\"} ";
+
+ BaseHTTPResponse res = new BaseHTTPResponse(200, response);
+ OAuthResponseData data = new MappedBaseHttpResponse<>(res,OAuthResponseData.class).body;
+ assertEquals(token,data.getAccess_token());
+
+ }
+
+ @Test
+ public void testUserPayloadDeser() throws JsonMappingException, JsonProcessingException {
+ final String payload = "{\n"
+ + " \"exp\": 1610362593,\n"
+ + " \"iat\": 1610361393,\n"
+ + " \"jti\": \"09bd6f2c-5dba-44a0-bd76-cd0d440137d0\",\n"
+ + " \"iss\": \"http://10.20.11.160:8080/auth/realms/onap\",\n"
+ + " \"aud\": \"account\",\n"
+ + " \"sub\": \"446a24bc-d8a0-43dd-afa5-e56eed75deb8\",\n"
+ + " \"typ\": \"Bearer\",\n"
+ + " \"azp\": \"admin-cli\",\n"
+ + " \"session_state\": \"db2c96f4-cc9b-47e8-a83f-a01c50d656f2\",\n"
+ + " \"acr\": \"1\",\n"
+ + " \"realm_access\": {\n"
+ + " \"roles\": [\n"
+ + " \"provision\",\n"
+ + " \"offline_access\",\n"
+ + " \"uma_authorization\"\n"
+ + " ]\n"
+ + " },\n"
+ + " \"resource_access\": {\n"
+ + " \"account\": {\n"
+ + " \"roles\": [\n"
+ + " \"manage-account\",\n"
+ + " \"manage-account-links\",\n"
+ + " \"view-profile\"\n"
+ + " ]\n"
+ + " }\n"
+ + " },\n"
+ + " \"scope\": \"profile email\",\n"
+ + " \"email_verified\": false,\n"
+ + " \"name\": \"Luke Skywalker\",\n"
+ + " \"preferred_username\": \"luke.skywalker\",\n"
+ + " \"given_name\": \"Luke\",\n"
+ + " \"family_name\": \"Skywalker\",\n"
+ + " \"email\": \"luke.skywalker@sdnr.onap.org\"\n"
+ + "}";
+
+ ObjectMapper mapper = new ObjectMapper();
+ KeycloakUserTokenPayload data = mapper.readValue(payload,KeycloakUserTokenPayload.class);
+ assertNotNull(data.getRealmAccess());
+ assertEquals(3, data.getRealmAccess().getRoles().size());
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestGitlabAuthService.java b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestGitlabAuthService.java
new file mode 100644
index 000000000..6c2390ea0
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestGitlabAuthService.java
@@ -0,0 +1,198 @@
+/*
+ * ============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.Config;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthProviderConfig;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UnableToConfigureOAuthService;
+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() throws IllegalArgumentException, Exception {
+
+ TokenCreator tokenCreator = TokenCreator.getInstance(Config.TOKENALG_HS256, TOKENCREATOR_SECRET, "issuer", 30*60);
+ OAuthProviderConfig config = new OAuthProviderConfig("git", GITURL, null, "odlux.app", OAUTH_SECRET, "openid",
+ "gitlab test", "", null, false);
+ 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) throws UnableToConfigureOAuthService {
+ 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;
+ 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/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestKeycloakAuthService.java b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestKeycloakAuthService.java
new file mode 100644
index 000000000..acc7c6b36
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestKeycloakAuthService.java
@@ -0,0 +1,196 @@
+/*
+ * ============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.Ignore;
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthProviderConfig;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UnableToConfigureOAuthService;
+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() throws IllegalArgumentException, Exception {
+
+ TokenCreator tokenCreator = TokenCreator.getInstance(Config.TOKENALG_HS256, TOKENCREATOR_SECRET, "issuer", 30*60);
+ OAuthProviderConfig config = new OAuthProviderConfig("kc", KEYCLOAKURL, null, "odlux.app", OAUTH_SECRET,
+ "openid", "keycloak test", "onap",null, false);
+ 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);
+ }
+ @Ignore
+ @Test
+ public void test3() {
+ HttpServletResponse resp = mock(HttpServletResponse.class);
+ String token = "";
+ try {
+ oauthService.sendLogoutRedirectResponse(token, resp,"http://sdnr.onap/odlux/index.html");
+ verify(resp).setStatus(302);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ public static class KeycloakProviderServiceToTest extends KeycloakProviderService {
+
+ public KeycloakProviderServiceToTest(OAuthProviderConfig config, String redirectUri,
+ TokenCreator tokenCreator) throws UnableToConfigureOAuthService {
+ 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_LOGOUT_ENDPOINT = "/auth/realms/onap/protocol/openid-connect/logout";
+ 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("GET".equals(method)){
+ if(KEYCLOAK_LOGOUT_ENDPOINT.equals(uri)){
+ t.sendResponseHeaders(200, 0);
+ }
+ }
+ else if ("POST".equals(method)) {
+ 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/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestPolicy.java b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestPolicy.java
new file mode 100644
index 000000000..31d72944c
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestPolicy.java
@@ -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/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestProperty.java b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestProperty.java
new file mode 100644
index 000000000..2d03bab1d
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestProperty.java
@@ -0,0 +1,42 @@
+/*
+ * ============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.assertNotNull;
+import static org.junit.Assert.assertNull;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
+
+public class TestProperty {
+
+ @Ignore
+ @Test
+ public void test() {
+ String hostname = Config.getProperty("${HOSTNAME}", null);
+ System.out.println(hostname);
+ assertNotNull(hostname);
+ hostname = Config.getProperty("${HOSTNAME2}", null);
+ System.out.println(hostname);
+ assertNull(hostname);
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRSAAlgorithms.java b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRSAAlgorithms.java
new file mode 100644
index 000000000..84d8e0a96
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRSAAlgorithms.java
@@ -0,0 +1,108 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2020 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.test;
+
+import static org.junit.Assert.fail;
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.exceptions.JWTVerificationException;
+import com.auth0.jwt.interfaces.JWTVerifier;
+import java.io.IOException;
+import java.security.Security;
+import java.security.interfaces.RSAPrivateKey;
+import java.security.interfaces.RSAPublicKey;
+import java.util.Date;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.RSAKeyReader;
+
+/**
+ *
+ * @author jack
+ *
+ */
+public class TestRSAAlgorithms {
+
+ private static final String ISSUER = "jwttest";
+ private static final String SUBJECT = "meandmymonkey";
+
+ @BeforeClass
+ public static void init() {
+ Security.addProvider(
+ new BouncyCastleProvider()
+ );
+ }
+
+ /**
+ * private and public key were generated in ubuntu 20.04 with
+ * $ ssh-keygen -t rsa -b 4096 -m PEM -P "" -f jwtRS512.key
+ * $ openssl rsa -in jwtRS512.key -pubout -outform PEM -out jwtRS512.key.pub
+ */
+ @Test
+ public void testRSA512() {
+ RSAPrivateKey privKey = null;
+ RSAPublicKey pubKey = null;
+ try {
+ privKey = RSAKeyReader.getPrivateKey("file://src/test/resources/jwtRS512.key");
+ pubKey = RSAKeyReader.getPublicKey("file://src/test/resources/jwtRS512.key.pub");
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ verifyAlg(Algorithm.RSA512(pubKey, privKey));
+ }
+
+ /**
+ * private and public key were generated in ubuntu 20.04 with
+ * $ openssl genrsa 2048 -out rsa-2048bit-jwtRS256.key
+ * $ openssl rsa -in jwtRS256.key -pubout > jwtRS256.key.pub
+ */
+ @Test
+ public void testRSA256() {
+ RSAPrivateKey privKey = null;
+ RSAPublicKey pubKey = null;
+ try {
+ privKey = RSAKeyReader.getPrivateKey("file://src/test/resources/jwtRS256.key");
+ pubKey = RSAKeyReader.getPublicKey("file://src/test/resources/jwtRS256.key.pub");
+ } catch (IOException e) {
+ e.printStackTrace();
+ fail(e.getMessage());
+ }
+ verifyAlg(Algorithm.RSA512(pubKey, privKey));
+ }
+
+ private static void verifyAlg(Algorithm a) {
+ long now = new Date().getTime();
+ final String token = JWT.create().withIssuer(ISSUER).withExpiresAt(new Date(now+10000))
+ .withIssuedAt(new Date(now))
+ .withSubject(SUBJECT)
+ .sign(a);
+ try {
+ JWTVerifier verifier = JWT.require(a).withIssuer(ISSUER).build();
+ verifier.verify(token);
+
+ } catch (JWTVerificationException e) {
+ fail(e.getMessage());
+ }
+ }
+}
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRealm.java b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRealm.java
new file mode 100644
index 000000000..ebf01a1ba
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestRealm.java
@@ -0,0 +1,219 @@
+/*
+ * ============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.BearerToken;
+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.AuthService;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
+import org.opendaylight.aaa.api.Authentication;
+import org.opendaylight.aaa.api.TokenStore;
+import org.opendaylight.aaa.api.shiro.principal.ODLPrincipal;
+import org.opendaylight.aaa.shiro.realm.TokenAuthRealm;
+import org.opendaylight.aaa.tokenauthrealm.auth.AuthenticationManager;
+import org.opendaylight.aaa.tokenauthrealm.auth.TokenAuthenticators;
+
+public class TestRealm {
+
+ private static OAuth2RealmToTest realm;
+ private static TokenCreator tokenCreator;
+
+ @BeforeClass
+ public static void init() throws IllegalArgumentException, Exception {
+
+ try {
+ Config config = Config.getInstance(TestConfig.TEST_CONFIG_FILENAME);
+ tokenCreator = TokenCreator.getInstance(config);
+ TokenAuthRealm.prepareForLoad(new AuthenticationManager(), new TokenAuthenticators(), new TokenStore() {
+ @Override
+ public void put(String token, Authentication auth) {
+
+ }
+
+ @Override
+ public Authentication get(String token) {
+ return null;
+ }
+
+ @Override
+ public boolean delete(String token) {
+ return false;
+ }
+
+ @Override
+ public long tokenExpiration() {
+ return 0;
+ }
+ });
+ 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 testUrlTrimming(){
+ final String internalUrl="https://test.identity.onap:49333";
+ final String externalUrl="https://test.identity.onap:49333";
+ final String testUrl1 = "/my/token/endpoint";
+ final String testUrl2 = internalUrl+testUrl1;
+ final String testUrl3 = externalUrl+testUrl1;
+
+ assertEquals(testUrl1, AuthService.trimUrl(internalUrl, testUrl1));
+ assertEquals(testUrl1, AuthService.trimUrl(internalUrl, testUrl2));
+ assertEquals(testUrl1, AuthService.trimUrl(externalUrl, testUrl3));
+
+ assertEquals(testUrl2, AuthService.extendUrl(internalUrl, testUrl3));
+
+
+
+ }
+ @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
+ ai=null;
+ 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 IllegalArgumentException, Exception {
+ 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/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlJsonMapper.java b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlJsonMapper.java
new file mode 100644
index 000000000..7d51b2fe8
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlJsonMapper.java
@@ -0,0 +1,65 @@
+/*
+ * ============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.yang.mapper.mapperextensions.YangToolsBuilderAnnotationIntrospector;
+import org.onap.ccsdk.features.sdnr.wt.yang.mapper.mapperextensions.YangToolsModule;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.aaa.rev161214.http.permission.Permissions;
+
+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/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlXmlMapper.java b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlXmlMapper.java
new file mode 100644
index 000000000..b965878e8
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/helper/OdlXmlMapper.java
@@ -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.yang.mapper.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/oauth-core/src/test/resources/aaa-app-config.test.xml b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/aaa-app-config.test.xml
new file mode 100644
index 000000000..e46508d68
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/aaa-app-config.test.xml
@@ -0,0 +1,77 @@
+<?xml version="1.0" ?>
+
+
+<shiro-configuration xmlns="urn:opendaylight:aaa:app:config">
+
+
+ <main>
+ <pair-key>tokenAuthRealm</pair-key>
+ <pair-value>org.onap.ccsdk.features.sdnr.wt.oauthprovider.OAuth2Realm</pair-value>
+ </main>
+
+ <main>
+ <pair-key>securityManager.realms</pair-key>
+ <pair-value>$tokenAuthRealm</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>
+
+ <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>
+
+ <main>
+ <pair-key>dynamicAuthorization</pair-key>
+ <pair-value>org.opendaylight.aaa.shiro.realm.MDSALDynamicAuthorizationFilter</pair-value>
+ </main>
+
+ <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/oauth-core/src/test/resources/jwtRS256.key b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS256.key
new file mode 100644
index 000000000..c0c15e014
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS256.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAyzd6BwZLS1UKchZENYyVycHZWp9iRTtLx31dZHfG8h0PLawG
+y+dXPEW8W/zVB13/Rdci9HXCnskBhzkFu9Ep+nI7X5C+lO3vxxNnGQ1CrRyHxHbb
+BYlm6J55l6tQox5qVcWe4iMbLm7F2eNKFPqEUu8OInjmLFZvS9C0qtfpqdeoyt4G
+XucUHcGZ/0E6yeq882+zYyb4pWN5PogAsP2KYeT1T6P0VCw4tda9GtokD3zOSaOg
+IvhIqe9jLAVcqWkxpuhV+IQdULBOxcJziW3AdQcB5IFQ7/SfZ9SnO5OpDTe02R5q
+bjH9k0iihrpI9HnlVrHqIEtFwDjuoPSeAOBjjwIDAQABAoIBAQCOfNeTFVa1+2rX
+k8U/xtNAJCvC3v6IjIsV1VEmoNVd7gI2g+hAEHWaTUtFNIIqKD5VOgPIZMmRjF8F
+8XWTu5UzheUbnOIEitEVRQWFC0c1GkwX9T6dIzqE4JlhPz3LIghtG6PL69GjPQh9
+PmEzVHRzsiq3AQ5jCDgBcNU89SdhbhPsfNpDq9+GaWUaVJ4MmJw52qLeSW0nh4NZ
+fMSINAfGZ/3Q2Nfe55zIk4KICyatKYLUMdcwynMwWYdZzg1e/4gxemdWdgFVUdPl
+rE6y404m+FrHl/nntL153u0C24jtEU0CJvLasu7hLjzAoANBzohcXxLY46jeNqk9
+yS4juMgBAoGBAPxn9hRH5vMxFCfT23/s1RnUB9Sal6OL8/hZ8OpwrnLaLmWDvvr5
+FBcDThhrHnJTLj0pOAxFX8kLjKgQdWB0ZqrEsG1R9AAVHxM4hXc92kDsAk4QJgCG
+tKDtzk9PKy8Jt1LnOF9n6NDLZuZim9Sv7qim6tt0L7K/mGrlCN4Gq6E3AoGBAM4c
+N2r0vObiSboryfY4xNSUZ1qLWAEJz4gyUQljSrlu2Gj5DK4rrTEd8Qyk9ehUdjuR
+giejpdjIvmjQ7NNPUogJbIoSbtKmx+k8qF7ieRulJjVBiJZLwNtGhiB4e6oZdhNl
+fJETn8MhkbOt8Sa1eEiR9u2O7IAYVwZLU/khkNxpAoGARxqKSgBPYSbsRKP767et
++I6wfgXmvd3JJqc/pOuFWTl5ZIOOo2jTbgAyWdKjSxV/qx8XeO16JEqqnxWz2y4v
+Vd/+y20QzY0lqeZ8QrEb8LoLlC4cZn2MGOGlAtaMlb2o9SPJz6aYAWmrXS9eMrY1
+BzGua4/5d+Ndbo+CxfkfFFUCgYEAjFimW8w+/TDFZ2H96g2J6f8LyZns2PgnOuSY
+Tb4w2cfi0MgVnFvdWP68bxG86PDqeXGBoSBMBCvdjF4HhXQUDNHt+K7Ii+RJaEaH
+l+S69tokBEuViFIZBrclCeNAwfkIb/jBM8CbHzIylpkxBly3hSLvc5/I5wir6XtN
+uOzkSVECgYEAy2oGf68OkNL74/WKDmQvnRxWkn78rCTzVAe0iJmJ3rAdak/Jb2Lj
+iihXn0XPsedZOZStbZYCG6GtcZCRypPi9HjO6DRRYFv3+aicjS7tVuJ3u39e5nIR
+K6eMAgFn1TAToc3gt/hUCnmreZ4ZUfQfuFK21Lqmn1FYJtck9ZHx0sw=
+-----END RSA PRIVATE KEY-----
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS256.key.pub b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS256.key.pub
new file mode 100644
index 000000000..add863aef
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS256.key.pub
@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyzd6BwZLS1UKchZENYyV
+ycHZWp9iRTtLx31dZHfG8h0PLawGy+dXPEW8W/zVB13/Rdci9HXCnskBhzkFu9Ep
++nI7X5C+lO3vxxNnGQ1CrRyHxHbbBYlm6J55l6tQox5qVcWe4iMbLm7F2eNKFPqE
+Uu8OInjmLFZvS9C0qtfpqdeoyt4GXucUHcGZ/0E6yeq882+zYyb4pWN5PogAsP2K
+YeT1T6P0VCw4tda9GtokD3zOSaOgIvhIqe9jLAVcqWkxpuhV+IQdULBOxcJziW3A
+dQcB5IFQ7/SfZ9SnO5OpDTe02R5qbjH9k0iihrpI9HnlVrHqIEtFwDjuoPSeAOBj
+jwIDAQAB
+-----END PUBLIC KEY-----
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS512.key b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS512.key
new file mode 100644
index 000000000..6b4e8c7bc
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS512.key
@@ -0,0 +1,51 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIJKQIBAAKCAgEA5vZBjfLjlUPK0b/F8FbGAyT1jXNVv2vjl+ZGUlThDX1jn0Wh
+XER5CL9CfkHKjJE47r8pQsO6nX9s5y+XzmAU9+QggtaDA+g0Px+cvCJQzJbtDbh0
+94m3uC50S+SSnYvr7vY1zy+jdswf/pXg1z059FokRxGso36SkSv81NYbN/WQrTKo
+gY6jkZXfPP8/sn8KV8uf7jYy2ZyHtakM9c9oCopWH78mhf9ioUNbgJsAxZmiohQU
+N5a3GbLS/nsTBOcVxUezvjvfb732iChKoARj3NiNN7HFHpXEXfiZ10OjrtAb9Y1K
+9RZsu/MKcFxBhDZusXjee6/x+NluQwT3RybgkCyV/i97Sroc37wOqimxtoSJ+MZY
+ZXNAUGNbNySkjvIGL8jWMj6w/zvyiHVbQg+DqY2Qds7Tdk29swYsMQQlz9v0FS/p
+GFVWo+5HTm+3MMlaMjSofw6j5/sE4OvJ4RCcnX8Cj1Zq9PrsMLLSF5MBOCSiclpI
+C1EYQ9Oi6XrcL3bbyyKGwB/u1X1HHnUmhRdKdVwKpSHR54XlfBDDoYtVnb1HTTxX
+MuiGU0XQRLvdnytJX1Lk6NJg/UUUKhrVXiH05CZsxlPFjDlhEhp4Jh+f/mdf6llX
+vsXn8k9ujBZBBD6PI4X7GkKB45H9zicbwt65f/MjhEohkbL5oZAKySzaUuMCAwEA
+AQKCAgBF7uLCnH0UwUY0ZKEGuP+UDCjd/8JDB+QOJoe8fj722rTDkU3epk0PvPnh
+SQKPtZlLkU5pDOMAtYjAJ8ULlERFGypM868QC8tmIahPvwRALqLwuJ2SJn0eo9JK
++Jb8ZVW3MY3xgjc4zW4SpEdEZSGbP4AklNF1X+n5UxxnRb1QIGcCSoiDUjFs77h8
+u70JyzXSh7GRa4/SHHdrJhjqhTa3mlOhoTuE72Np+P9H3adKLc70zKeifVxLx73j
+mFiV73LEHYXrYC2zpA12BN0zvqCOSnPYHVfWfvrKiW/romt5j0IoA/Riabva3SiY
+BRdBdUnnKvYS9Z+K/itI18QYI0lzSuLiaCTCo/3N/2MkuRMwS3Mvae7kK43/6c3w
+sXobp8KBRMnpnT+AHENIHVJ35XKkWfTY9xMg/JkKbAXY06TitKW53ds03vb9Y9n2
+3SKBUcpbTkJJbJ50E/BiglLVxlllzVJiUIMNDGUmZO7eYQx9fs16cz4JkhzKcN+F
+zYg4BVXL8blWU6AjXzexjTNuic/IxkqJruG05tCFwVxHjhajb9xQ1ANDMcXnwPmt
+VKpU4KxrGqFgsVdZ5SE9gdu1g+zf96DdhXjHhZCfq6fsf2TYXD2SsUhx4kk9zOE/
+I4tXwf7Q7Ol24qlV9W8enc3gr1nk+buutl+I55LSM4bG4M3uQQKCAQEA/rkulfhl
+wxStbVIICRl6iuC1nhqlxOBZAbc45pRgEDyTO5IfxnVA6kVCa5DkQ5cWZOoshKg9
+MNfHbo9JIYZzElnM/XxpmqIsHpQ+ZXe5XVaaYz9DogNnH2iLtQGVVLPphtxJxTqW
+A6944GuhmZ9DmRwn0nN2nU0nUqBtLFio9+b7nChDaJj5aIkLHjx3p9ytjzzJP5nM
+0lKSo9BD97+AhCaIT7NxjKSRWRs7ftf7Bv5vxPXrpgUN8ltkg4YVIzGX7UMXT+ga
+H2kf+QkAJX1+9kbNMjkqhOH7zkv1DVqCVup9XewA2GltxoJZIVH04+QmgNWcS+XP
+cbxe0r95tuMTqQKCAQEA6B6WYpC9UxXLPfOJdWDzSO3oh13RgQo1uEHdU9rc9vfi
+vYZZsSL06uR7v6fuiuyAAayZgCTS1xr69MCAJR2056E3RthktAzOkfCJrcIyEHmy
+b9yekRyL+R8P4HxV76AYqY52PhdgDntGoXb7hcGKt6hvkmcR41cnRHRjrb7zkEVy
+55JY1woEVtt6otxHKZSnx5nlQct73Lv65QDfosfkESOmbE2W4G87XBk36I2YBywU
+kNEr49tnI09qyEPJLjTTGxFdMeqXbnCgzSwqlBlrQE8NYJBsy2GBL0EWOYeRXkuz
+RFug3o89uAOircy2virMhl6EOA0EKakWR4ZQCKlJqwKCAQEA40aBnYhL6/sIHtGh
+n9Te9Qk4o4AtRnPSluhPWdUrvXD/AZkIxv+Z0y3G7MkUEoa9kX8sB5VBO9Jb/HbW
+jpYzGD2N3OLkKvfmG8azwb9IYlLCYClzhBw7J9gVR4TJJBF/HThyjgsPDOzFEqCW
+SMbE/tkTYwBo5kOQAXZo0res07yB5bw7IRnU94PHqsvTC7CoH3TiL+Bf042fj5Bl
+BKoW1lK3Lz3x48Z2daYJuMynC398ZKX0A2bhIcyP65Z4R7WZVDaXl1GF9V7MC10P
+h2PpI37a2aQOHxCvp0s4tBh80WZaQ7Iusumm7Acj1coVkjzgafWuhj3fkSC9DpeP
+1zHXOQKCAQBCiVIOWvMKN/sUfRTwAqR6SUgYVXpShPy1Hpw1B03DtXbXYQWg0yZl
+lq0qWRb116kx0aoGo4eUhXVeZzfUa9mJdBsGQc1MF0e3ab3tgvca5eeSTSle61Hs
+TU0dykZP9BJduCqIzeaJAClU62haBQqgbrXcv5LPGhJ1eu9/xHbI6j9vxfGVYpev
+1iYnPQFhF+2oN6MR4yRUN8ZJkqCIZsgnaZKxBOS03O2lDs2J6dykYaxbfroYDLJZ
+2s//K/8lMZs57RZL0rUpwTs21Ow3m7m0q3RoM74b5o1DYGLghs3Su9xdQe6xHVpR
+vykIrN/NTzNlaP55mrGQx5lNU2Dpuq0VAoIBAQDVCfAJlu+wkZmeXm1zUOFjOMvq
+el3t55RCQ/SuhIpaNf2CWD6SOZfHfTxJ8nuYE+FJmjL6r9Z4a8ND0VPttuyBG6gY
+siuZUE31+2OBvdKBhi4stqGZWMKJqYsDFH7QIfu7wSS1kuJ/vA7MB9f7IsrHJb2z
+QBJoVMZoXhh4tqyFVatEp6yYSE4uKLvlKQSJ6W8DEuPggoiNPbhxQq2ctFUyup/S
+9MsfJ9tj99mjlPSelMUXsHcsprIZBuhskfeidTe+gy43TBm0G8l7xeAGWkBlWQMR
+L843JjebD6QCnPIS4nrW7kCRM8lv1ZId6D5Jq1Coc8b1ZrezfII7/eNgZZCv
+-----END RSA PRIVATE KEY-----
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS512.key.pub b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS512.key.pub
new file mode 100644
index 000000000..7191c95f8
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/jwtRS512.key.pub
@@ -0,0 +1,14 @@
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA5vZBjfLjlUPK0b/F8FbG
+AyT1jXNVv2vjl+ZGUlThDX1jn0WhXER5CL9CfkHKjJE47r8pQsO6nX9s5y+XzmAU
+9+QggtaDA+g0Px+cvCJQzJbtDbh094m3uC50S+SSnYvr7vY1zy+jdswf/pXg1z05
+9FokRxGso36SkSv81NYbN/WQrTKogY6jkZXfPP8/sn8KV8uf7jYy2ZyHtakM9c9o
+CopWH78mhf9ioUNbgJsAxZmiohQUN5a3GbLS/nsTBOcVxUezvjvfb732iChKoARj
+3NiNN7HFHpXEXfiZ10OjrtAb9Y1K9RZsu/MKcFxBhDZusXjee6/x+NluQwT3Rybg
+kCyV/i97Sroc37wOqimxtoSJ+MZYZXNAUGNbNySkjvIGL8jWMj6w/zvyiHVbQg+D
+qY2Qds7Tdk29swYsMQQlz9v0FS/pGFVWo+5HTm+3MMlaMjSofw6j5/sE4OvJ4RCc
+nX8Cj1Zq9PrsMLLSF5MBOCSiclpIC1EYQ9Oi6XrcL3bbyyKGwB/u1X1HHnUmhRdK
+dVwKpSHR54XlfBDDoYtVnb1HTTxXMuiGU0XQRLvdnytJX1Lk6NJg/UUUKhrVXiH0
+5CZsxlPFjDlhEhp4Jh+f/mdf6llXvsXn8k9ujBZBBD6PI4X7GkKB45H9zicbwt65
+f/MjhEohkbL5oZAKySzaUuMCAwEAAQ==
+-----END PUBLIC KEY-----
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/resources/mdsalDynAuthData.json b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/mdsalDynAuthData.json
new file mode 100644
index 000000000..a1627682b
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/mdsalDynAuthData.json
@@ -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/oauth-core/src/test/resources/oauth/gitlab-groups-response.json b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/oauth/gitlab-groups-response.json
new file mode 100644
index 000000000..85fc37cc8
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/oauth/gitlab-groups-response.json
@@ -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/oauth-core/src/test/resources/oauth/gitlab-token-response.json b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/oauth/gitlab-token-response.json
new file mode 100644
index 000000000..0a6bd7231
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/oauth/gitlab-token-response.json
@@ -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/oauth-core/src/test/resources/oauth/gitlab-user-response.json b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/oauth/gitlab-user-response.json
new file mode 100644
index 000000000..b08332b41
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/oauth/gitlab-user-response.json
@@ -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/oauth-core/src/test/resources/oauth/keycloak-token-response.json b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/oauth/keycloak-token-response.json
new file mode 100644
index 000000000..c62ed9458
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/oauth/keycloak-token-response.json
@@ -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/oauth-core/src/test/resources/oom.test.config.json b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/oom.test.config.json
new file mode 100644
index 000000000..4e5707fa1
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/oom.test.config.json
@@ -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
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.config.json b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.config.json
new file mode 100644
index 000000000..a55576b9e
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.config.json
@@ -0,0 +1,20 @@
+{
+ "tokenSecret": "secret2134",
+ "tokenIssuer": "ONAP SDNC",
+ "publicUrl": "http://nasp.diasf.de",
+ "redirectUri": "/index.html#redirect=",
+ "supportOdlUsers": "true",
+ "tokenLifetime":3600,
+ "providers": [
+ {
+ "id": "keycloak",
+ "type": "KEYCLOAK",
+ "url": "http://10.20.11.160:8080",
+ "clientId": "odlux.app",
+ "secret": "5da4ea3d-8cc9-4669-bd7e-3ecb91d120cd",
+ "scope": "openid",
+ "title": "OSNL Keycloak Provider",
+ "realmName":"onap"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.configRS256-invalid.json b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.configRS256-invalid.json
new file mode 100644
index 000000000..30b80c45a
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.configRS256-invalid.json
@@ -0,0 +1,24 @@
+{
+ "tokenSecret": "",
+ "tokenPubKey": "file:///src/test/resources/jwtRS256.key.pub",
+ "algorithm":"RS256",
+ "tokenIssuer": "ONAP SDNC",
+ "publicUrl": "http://nasp.diasf.de",
+ "redirectUri": "/index.html#redirect=",
+ "supportOdlUsers": "true",
+ "tokenLifetime":3600,
+ "providers": [
+ {
+ "id": "keycloak",
+ "type": "KEYCLOAK",
+ "url": "http://10.20.11.160:8080",
+ "clientId": "odlux.app",
+ "secret": "5da4ea3d-8cc9-4669-bd7e-3ecb91d120cd",
+ "publickey": "",
+ "algorithm":"RS256",
+ "scope": "openid",
+ "title": "OSNL Keycloak Provider",
+ "realmName":"onap"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.configRS256.json b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.configRS256.json
new file mode 100644
index 000000000..02a4e8f5f
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.configRS256.json
@@ -0,0 +1,22 @@
+{
+ "tokenSecret": "file:///src/test/resources/jwtRS256.key",
+ "tokenPubKey": "file:///src/test/resources/jwtRS256.key.pub",
+ "algorithm":"RS256",
+ "tokenIssuer": "ONAP SDNC",
+ "publicUrl": "http://nasp.diasf.de",
+ "redirectUri": "/index.html#redirect=",
+ "supportOdlUsers": "true",
+ "tokenLifetime":3600,
+ "providers": [
+ {
+ "id": "keycloak",
+ "type": "KEYCLOAK",
+ "url": "http://10.20.11.160:8080",
+ "clientId": "odlux.app",
+ "secret": "5da4ea3d-8cc9-4669-bd7e-3ecb91d120cd",
+ "scope": "openid",
+ "title": "OSNL Keycloak Provider",
+ "realmName":"onap"
+ }
+ ]
+} \ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.configRS512.json b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.configRS512.json
new file mode 100644
index 000000000..eddc6c362
--- /dev/null
+++ b/sdnr/wt/oauth-provider/oauth-core/src/test/resources/test.configRS512.json
@@ -0,0 +1,22 @@
+{
+ "tokenSecret": "file:///src/test/resources/jwtRS512.key",
+ "tokenPubKey": "file:///src/test/resources/jwtRS512.key.pub",
+ "algorithm":"RS512",
+ "tokenIssuer": "ONAP SDNC",
+ "publicUrl": "http://nasp.diasf.de",
+ "redirectUri": "/index.html#redirect=",
+ "supportOdlUsers": "true",
+ "tokenLifetime":3600,
+ "providers": [
+ {
+ "id": "keycloak",
+ "type": "KEYCLOAK",
+ "url": "http://10.20.11.160:8080",
+ "clientId": "odlux.app",
+ "secret": "5da4ea3d-8cc9-4669-bd7e-3ecb91d120cd",
+ "scope": "openid",
+ "title": "OSNL Keycloak Provider",
+ "realmName":"onap"
+ }
+ ]
+} \ No newline at end of file