add oauth-provider 20/117620/5
authorMichael DÜrre <michael.duerre@highstreet-technologies.com>
Tue, 9 Feb 2021 07:14:07 +0000 (08:14 +0100)
committerKAPIL SINGAL <ks220y@att.com>
Tue, 9 Feb 2021 20:32:06 +0000 (20:32 +0000)
new feature for more login security and external logins

Issue-ID: CCSDK-3142
Signed-off-by: Michael DÜrre <michael.duerre@highstreet-technologies.com>
Change-Id: I6a564a0d1dca44b69bfea2e692fec1f4315cab83
Signed-off-by: Michael DÜrre <michael.duerre@highstreet-technologies.com>
33 files changed:
sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/http/BaseHTTPClient.java
sdnr/wt/common/src/main/java/org/onap/ccsdk/features/sdnr/wt/common/util/Environment.java
sdnr/wt/featureaggregator/feature-oauth/pom.xml [new file with mode: 0644]
sdnr/wt/featureaggregator/pom.xml
sdnr/wt/oauth-provider/pom.xml [new file with mode: 0755]
sdnr/wt/oauth-provider/provider-jar/pom.xml [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/OAuth2Realm.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/CustomObjectMapper.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakRole.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakUserTokenPayload.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/NoDefinitionFoundException.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthProviderConfig.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthResponseData.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthToken.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlPolicy.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/UserTokenPayload.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/AuthHttpServlet.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/HeadersOnlyHttpServletRequest.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappedBaseHttpResponse.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappingBaseHttpClient.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/AuthService.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/KeycloakProviderService.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/NextcloudProviderService.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/OAuthProviderFactory.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/TokenCreator.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestConfig.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestDeserializer.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestProperty.java [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-jar/src/test/resources/test.config.json [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-osgi/pom.xml [new file with mode: 0644]
sdnr/wt/oauth-provider/provider-osgi/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml [new file with mode: 0644]
sdnr/wt/pom.xml

index 198fb92..937e2d8 100644 (file)
@@ -71,7 +71,7 @@ public class BaseHTTPClient {
     private static final int SSLCERT_PCKS = 0;
     private static final int SSLCERT_PEM = 1;
     private static final int BUFSIZE = 1024;
-    private static final Charset CHARSET = StandardCharsets.UTF_8;
+    public static final Charset CHARSET = StandardCharsets.UTF_8;
     private static final String SSLCONTEXT = "TLSv1.2";
     private static final int DEFAULT_HTTP_TIMEOUT_MS = 30000; // in ms
 
index 050152f..89e9266 100644 (file)
@@ -28,6 +28,9 @@ import java.util.Map;
 public class Environment {
 
     public static String getVar(String v) {
+        return getVar(v, null);
+    }
+    public static String getVar(String v, String defaultValue) {
         if (v.equals("$HOSTNAME")) {
             String s = null;
             try {
@@ -43,6 +46,6 @@ public class Environment {
             if (envName != null && envName.equals(v))
                 return env.get(envName);
         }
-        return null;
+        return defaultValue;
     }
 }
diff --git a/sdnr/wt/featureaggregator/feature-oauth/pom.xml b/sdnr/wt/featureaggregator/feature-oauth/pom.xml
new file mode 100644 (file)
index 0000000..e03c6a0
--- /dev/null
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ ============LICENSE_START=======================================================
+  ~ ONAP : ccsdk features
+  ~ ================================================================================
+  ~ Copyright (C) 2018 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>single-feature-parent</artifactId>
+        <version>2.1.1-SNAPSHOT</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+    <artifactId>sdnr-wt-feature-aggregator-oauth</artifactId>
+    <version>1.1.1-SNAPSHOT</version>
+    <packaging>feature</packaging>
+
+    <name>ccsdk-features :: ${project.artifactId}</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>sdnr-wt-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>sdnr-wt-oauth-provider</artifactId>
+            <version>${project.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>${project.groupId}</groupId>
+                    <artifactId>sdnr-wt-oauth-provider-jar</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+</project>
index 6edd34c..88df224 100755 (executable)
@@ -44,6 +44,7 @@
         <module>feature</module>
         <module>feature-devicemanager</module>
         <module>feature-devicemanager-base</module>
+        <module>feature-oauth</module>
         <module>installer</module>
     </modules>
 </project>
diff --git a/sdnr/wt/oauth-provider/pom.xml b/sdnr/wt/oauth-provider/pom.xml
new file mode 100755 (executable)
index 0000000..d8fe6c9
--- /dev/null
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ ============LICENSE_START=======================================================
+  ~ ONAP : ccsdk features
+  ~ ================================================================================
+  ~ Copyright (C) 2018 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>odlparent-lite</artifactId>
+        <version>2.1.1-SNAPSHOT</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+    <artifactId>sdnr-wt-oauth-provider-top</artifactId>
+    <version>1.1.1-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <name>ccsdk-features :: ${project.artifactId}</name>
+
+    <modules>
+        <module>provider-jar</module>
+        <module>provider-osgi</module>
+    </modules>
+
+    <properties>
+        <feature-name>sdnr-wt-oauth-provider</feature-name>
+    </properties>
+</project>
diff --git a/sdnr/wt/oauth-provider/provider-jar/pom.xml b/sdnr/wt/oauth-provider/provider-jar/pom.xml
new file mode 100644 (file)
index 0000000..3ee21b2
--- /dev/null
@@ -0,0 +1,178 @@
+<?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.1.1-SNAPSHOT</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+    <artifactId>sdnr-wt-oauth-provider-jar</artifactId>
+    <version>1.1.1-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>
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.apache.shiro</groupId>
+                <artifactId>shiro-core</artifactId>
+                <version>1.3.2</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+    <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>
+            <version>3.11.0</version>
+             <exclusions>
+                <exclusion>
+                    <groupId>com.fasterxml.jackson.core</groupId>
+                    <artifactId>jackson-databind</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>commons-codec</groupId>
+                    <artifactId>commons-codec</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.highstreet-technologies.aaa</groupId>
+            <artifactId>aaa-shiro</artifactId>
+            <version>0.12.1</version>
+            <exclusions>
+<!--                 <exclusion> -->
+<!--                     <groupId>org.opendaylight.aaa</groupId> -->
+<!--                     <artifactId>aaa-shiro-api</artifactId> -->
+<!--                 </exclusion> -->
+                <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>
+<!--                 <exclusion> -->
+<!--                     <groupId>org.jolokia</groupId> -->
+<!--                     <artifactId>jolokia-osgi</artifactId> -->
+<!--                 </exclusion> -->
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.opendaylight.mdsal</groupId>
+            <artifactId>yang-binding</artifactId>
+            <scope>provided</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>
+    </dependencies>
+</project>
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/OAuth2Realm.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/OAuth2Realm.java
new file mode 100644 (file)
index 0000000..a3e4bcc
--- /dev/null
@@ -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.providers.TokenCreator;
+import org.opendaylight.aaa.api.shiro.principal.ODLPrincipal;
+import org.opendaylight.aaa.shiro.filters.backport.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 IOException {
+        super();
+        super.setName(REALM_NAME);
+        this.config = Config.getInstance();
+        this.tokenCreator = TokenCreator.getInstance();
+        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/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/Config.java
new file mode 100644 (file)
index 0000000..ba26106
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * ============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.JsonIgnore;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.util.List;
+import java.util.Random;
+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";
+    private static Config _instance;
+
+
+    private List<OAuthProviderConfig> providers;
+    private String host;
+    private String redirectUri;
+    private String supportOdlUsers;
+    private String tokenSecret;
+    private String tokenIssuer;
+
+
+    @Override
+    public String toString() {
+        return "Config [providers=" + providers + ", host=" + host + ", redirectUri=" + redirectUri
+                + ", supportOdlUsers=" + supportOdlUsers + ", tokenSecret=" + tokenSecret + ", tokenIssuer="
+                + tokenIssuer + "]";
+    }
+
+
+
+    public List<OAuthProviderConfig> getProviders() {
+        return providers;
+    }
+
+    public void setProviders(List<OAuthProviderConfig> providers) {
+        this.providers = providers;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    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 getTokenIssuer() {
+        return tokenIssuer;
+    }
+
+    public void setTokenIssuer(String tokenIssuer) {
+        this.tokenIssuer = tokenIssuer;
+    }
+
+    @JsonIgnore
+    private void handleEnvironmentVars() {
+        if (isEnvExpression(tokenIssuer)) {
+            this.tokenIssuer = getProperty(tokenIssuer, null);
+        }
+        if (isEnvExpression(tokenSecret)) {
+            this.tokenSecret = getProperty(tokenSecret, null);
+        }
+        if (isEnvExpression(host)) {
+            this.host = getProperty(host, null);
+        }
+        if (isEnvExpression(redirectUri)) {
+            this.redirectUri = getProperty(redirectUri, null);
+        }
+        if (isEnvExpression(supportOdlUsers)) {
+            this.supportOdlUsers = getProperty(supportOdlUsers, null);
+        }
+    }
+
+    @JsonIgnore
+    private void handleDefaultValues() {
+        if (tokenIssuer == null || tokenIssuer.isEmpty()) {
+            this.tokenIssuer = DEFAULT_TOKENISSUER;
+        }
+        if (tokenSecret == null || tokenSecret.isEmpty()) {
+            this.tokenSecret = DEFAULT_TOKENSECRET;
+        }
+        if (redirectUri == null || redirectUri.isEmpty()) {
+            this.redirectUri = DEFAULT_REDIRECTURI;
+        }
+        if (supportOdlUsers == null || supportOdlUsers.isEmpty()) {
+            this.supportOdlUsers = DEFAULT_SUPPORTODLUSERS;
+        }
+    }
+
+    static boolean isEnvExpression(String key) {
+        return key != null && key.contains(ENVVARIABLE);
+    }
+
+    private static String generateSecret() {
+        int leftLimit = 48; // numeral '0'
+        int rightLimit = 122; // letter 'z'
+        int targetStringLength = 30;
+        Random random = new Random();
+
+        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 != "") {
+                            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 {
+        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();
+        return cfg;
+    }
+
+
+    @JsonIgnore
+    public boolean doSupportOdlUsers() {
+        return "true".equals(this.supportOdlUsers);
+    }
+
+
+
+    public static Config getInstance() throws IOException {
+        if(_instance==null) {
+            _instance = load(DEFAULT_CONFIGFILENAME);
+        }
+        return _instance;
+    }
+
+
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/CustomObjectMapper.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/CustomObjectMapper.java
new file mode 100644 (file)
index 0000000..aa23d4d
--- /dev/null
@@ -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/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakRole.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakRole.java
new file mode 100644 (file)
index 0000000..67186ba
--- /dev/null
@@ -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/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakUserTokenPayload.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/KeycloakUserTokenPayload.java
new file mode 100644 (file)
index 0000000..c99ec0d
--- /dev/null
@@ -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/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/NoDefinitionFoundException.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/NoDefinitionFoundException.java
new file mode 100644 (file)
index 0000000..d13be96
--- /dev/null
@@ -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/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthProviderConfig.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthProviderConfig.java
new file mode 100644 (file)
index 0000000..e4d6743
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * ============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 org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.OAuthProviderFactory.OAuthProvider;
+
+public class OAuthProviderConfig {
+
+    private String host;
+    private String clientId;
+    private String secret;
+    private String id;
+    private String title;
+    private String scope;
+    private OAuthProvider type;
+
+    public OAuthProvider getType() {
+        return type;
+    }
+
+    public OAuthProviderConfig(String id, String host, String clientId, String secret, String scope,
+            String title) {
+        this.id = id;
+        this.host = host;
+        this.clientId = clientId;
+        this.secret = secret;
+        this.scope = scope;
+        this.title = title;
+    }
+
+    @Override
+    public String toString() {
+        return "OAuthProviderConfig [host=" + host + ", clientId=" + clientId + ", secret=" + secret + ", id=" + id
+                + ", title=" + title + ", scope=" + scope + ", type=" + type + "]";
+    }
+
+    public void setType(OAuthProvider type) {
+        this.type = type;
+    }
+
+    public OAuthProviderConfig() {
+        this(null, null, null, null, null, null);
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    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 getHost() {
+        return this.host;
+    }
+
+    public String getClientId() {
+        return this.clientId;
+    }
+
+    public String getSecret() {
+        return this.secret;
+    }
+
+    public String getTitle() {
+        return this.title;
+    }
+
+    public String getScope() {
+        return this.scope;
+    }
+
+    @JsonIgnore
+    public void handleEnvironmentVars() {
+        if (Config.isEnvExpression(id)) {
+            this.id = Config.getProperty(id, null);
+        }
+        if (Config.isEnvExpression(host)) {
+            this.host = Config.getProperty(host, null);
+        }
+        if (Config.isEnvExpression(clientId)) {
+            this.clientId = Config.getProperty(clientId, null);
+        }
+        if (Config.isEnvExpression(secret)) {
+            this.secret = Config.getProperty(secret, null);
+        }
+        if (Config.isEnvExpression(scope)) {
+            this.scope = Config.getProperty(scope, null);
+        }
+        if (Config.isEnvExpression(title)) {
+            this.title = Config.getProperty(title, null);
+        }
+    }
+
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthResponseData.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthResponseData.java
new file mode 100644 (file)
index 0000000..806a620
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * ============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;
+
+    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;
+    }
+
+    @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/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthToken.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OAuthToken.java
new file mode 100644 (file)
index 0000000..1a695f2
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * ============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.opendaylight.aaa.shiro.filters.backport.BearerToken;
+
+public class OAuthToken {
+    private final String access_token;
+    private final String token_type;
+    private final long expires_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;
+    }
+
+    public String getAccess_token() {
+        return access_token;
+    }
+
+    public String getToken_type() {
+        return token_type;
+    }
+
+    public long getExpires_at() {
+        return expires_at;
+    }
+
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlPolicy.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/OdlPolicy.java
new file mode 100644 (file)
index 0000000..28ef3b3
--- /dev/null
@@ -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() {
+
+        }
+
+        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/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/UserTokenPayload.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/data/UserTokenPayload.java
new file mode 100644 (file)
index 0000000..229cdbf
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * ============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 {
+
+    private List<String> roles;
+    private String preferredUsername;
+    private String givenName;
+    private String familyName;
+    private long exp;
+
+    public long getExp() {
+        return exp;
+    }
+
+    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 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 static UserTokenPayload create(String username, List<String> roles) {
+        UserTokenPayload data = new UserTokenPayload();
+        data.setPreferredUsername(username);
+        data.setRoles(roles);
+        return data;
+    }
+
+
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/AuthHttpServlet.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/AuthHttpServlet.java
new file mode 100644 (file)
index 0000000..f5d344d
--- /dev/null
@@ -0,0 +1,452 @@
+/*
+ * ============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.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.codec.Base64;
+import org.jolokia.osgi.security.Authenticator;
+import org.onap.ccsdk.features.sdnr.wt.common.http.BaseHTTPClient;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.NoDefinitionFoundException;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthProviderConfig;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthToken;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OdlPolicy;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.AuthService;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.AuthService.PublicOAuthProviderConfig;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.OAuthProviderFactory;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers.TokenCreator;
+import org.opendaylight.aaa.api.IDMStoreException;
+import org.opendaylight.aaa.api.IdMService;
+import org.opendaylight.aaa.shiro.filters.backport.BearerToken;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfiguration;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.shiro.configuration.Main;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.shiro.configuration.Urls;
+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 POLICIESURI = BASEURI + "/policies";
+    //private static final String PROVIDERID_REGEX = "^\\" + BASEURI + "\\/providers\\/([^\\/]+)$";
+    private static final String REDIRECTID_REGEX = "^\\" + BASEURI + "\\/redirect\\/([^\\/]+)$";
+    //private static final Pattern PROVIDERID_PATTERN = Pattern.compile(PROVIDERID_REGEX);
+    private static final Pattern REDIRECTID_PATTERN = Pattern.compile(REDIRECTID_REGEX);
+
+    private static final String DEFAULT_DOMAIN = "sdn";
+    private static final String HEAEDER_AUTHORIZATION = "Authorization";
+
+    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";
+
+    private final ObjectMapper mapper;
+    /* state <=> AuthProviderService> */
+    private final Map<String, AuthService> providerStore;
+    private Authenticator odlAuthenticator;
+    private IdMService odlIdentityService;
+    private final TokenCreator tokenCreator;
+    private final Config config;
+    private ShiroConfiguration shiroConfiguration;
+
+    public AuthHttpServlet() throws IOException {
+        this.tokenCreator = TokenCreator.getInstance();
+        this.config = Config.getInstance();
+        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()));
+        }
+
+    }
+
+    public void setOdlAuthenticator(Authenticator odlAuthenticator) {
+        this.odlAuthenticator = odlAuthenticator;
+    }
+
+    public void setOdlIdentityService(IdMService odlIdentityService) {
+        this.odlIdentityService = odlIdentityService;
+    }
+
+    public void setShiroConfiguration(ShiroConfiguration shiroConfiguration) {
+        this.shiroConfiguration = shiroConfiguration;
+    }
+
+    @Override
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        LOG.debug("GET request for {}", req.getRequestURI());
+        fillHost(req);
+        if (PROVIDERSURI.equals(req.getRequestURI())) {
+            this.sendResponse(resp, HttpServletResponse.SC_OK, getConfigs(this.providerStore.values()));
+        } 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);
+        }
+
+    }
+
+    /**
+     * find out what urls can be accessed by user and which are forbidden
+     *
+     * 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<Urls> urlRules = this.shiroConfiguration.getUrls();
+        UserTokenPayload data = this.getUserInfo(req);
+        List<OdlPolicy> policies = new ArrayList<>();
+        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 (Urls urlRule : urlRules) {
+                matcher = pattern.matcher(urlRule.getPairValue());
+                if (matcher.find()) {
+                    try {
+                        final String authClass = getAuthClass(matcher.group(1));
+                        Optional<OdlPolicy> policy = Optional.empty();
+                        if (authClass.equals(CLASSNAME_ODLBASICAUTH)
+                                || authClass.equals(CLASSNAME_ODLBEARERANDBASICAUTH)) {
+                            policy = this.getTokenBasedPolicy(urlRule, matcher, data);
+                        } else if (authClass.equals(CLASSNAME_ODLMDSALAUTH)) {
+                            policy = this.getMdSalBasedPolicy(urlRule, matcher, data);
+                        }
+                        if (policy.isPresent()) {
+                            policies.add(policy.get());
+                        } else {
+                            LOG.warn("unable to get policy for authClass {} for entry {}", authClass,
+                                    urlRule.getPairValue());
+                        }
+                    } 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 matcher
+     * @param data
+     * @return
+     */
+    private Optional<OdlPolicy> getMdSalBasedPolicy(Urls urlRule, Matcher matcher, UserTokenPayload data) {
+
+        return Optional.empty();
+    }
+
+    /**
+     * extract policy rule for user from url rules of config
+     * @param urlRule
+     * @param matcher
+     * @param data
+     * @return
+     */
+    private Optional<OdlPolicy> getTokenBasedPolicy(Urls urlRule, Matcher matcher, UserTokenPayload data) {
+        final String url = urlRule.getPairKey();
+        if (!urlRule.getPairValue().contains(",")) {
+            LOG.debug("found rule without roles for '{}'", matcher.group(1));
+            //not important if anon or authcXXX
+            if (data != null || "anon".equals(matcher.group(1))) {
+                return Optional.of(OdlPolicy.allowAll(url));
+            }
+        } else if (data != null) {
+            LOG.debug("found rule with roles '{}'", matcher.group(4));
+            if ("roles".equals(matcher.group(2))) {
+                if (this.rolesMatch(data.getRoles(), Arrays.asList(matcher.group(4).split(",")), false)) {
+                    Optional.of(OdlPolicy.allowAll(url));
+                } else {
+                    Optional.of(OdlPolicy.denyAll(url));
+                }
+            } else if ("anyroles".equals(matcher.group(2))) {
+                if (this.rolesMatch(data.getRoles(), Arrays.asList(matcher.group(4).split(",")), true)) {
+                    Optional.of(OdlPolicy.allowAll(url));
+                } else {
+                    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;
+        }
+        Optional<Main> main =
+                this.shiroConfiguration.getMain().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 = TokenCreator.getInstance().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 = this.odlIdentityService.listRoles(username, domain);
+                return UserTokenPayload.create(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 ? false : header.startsWith("Basic");
+    }
+
+    private static boolean isBearer(HttpServletRequest req) {
+        final String header = req.getHeader(HEAEDER_AUTHORIZATION);
+        return header == null ? false : 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;
+        }
+
+    }
+
+    private void fillHost(HttpServletRequest req) {
+        String hostUrl = this.config.getHost();
+        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);
+                this.config.setHost(hostUrl);
+            }
+        }
+
+    }
+
+    private List<PublicOAuthProviderConfig> getConfigs(Collection<AuthService> values) {
+        List<PublicOAuthProviderConfig> configs = new ArrayList<>();
+        for (AuthService svc : values) {
+            configs.add(svc.getConfig(this.config.getHost()));
+        }
+        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(this.config.getHost());
+                provider.handleRedirect(req, resp);
+                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.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_NOT_FOUND);
+    }
+
+    @Override
+    protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        //        final String uri = req.getRequestURI();
+        //        final Matcher matcher = PROVIDERID_PATTERN.matcher(uri);
+        //        if (matcher.find()) {
+        //            final String id = matcher.group(1);
+        //            final OAuthProviderConfig config = this.mapper.readValue(req.getInputStream(), OAuthProviderConfig.class);
+        //            //this.providerStore.put(id, config);
+        //            sendResponse(resp, HttpServletResponse.SC_OK, "");
+        //            return;
+        //        }
+        resp.sendError(HttpServletResponse.SC_NOT_FOUND);
+    }
+
+    @Override
+    protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        //        final String uri = req.getRequestURI();
+        //        final Matcher matcher = PROVIDERID_PATTERN.matcher(uri);
+        //        if (matcher.find()) {
+        //            final String id = matcher.group(1);
+        //            this.providerStore.remove(id);
+        //            sendResponse(resp, HttpServletResponse.SC_OK, "");
+        //            return;
+        //        }
+        resp.sendError(HttpServletResponse.SC_NOT_FOUND);
+    }
+
+    private BearerToken doLogin(String username, String password, String domain) {
+        if (!username.contains("@")) {
+            username = String.format("%s@%s", username, domain);
+        }
+        HttpServletRequest req = new HeadersOnlyHttpServletRequest(
+                Map.of("Authorization", BaseHTTPClient.getAuthorizationHeaderValue(username, password)));
+        if (this.odlAuthenticator.authenticate(req)) {
+            try {
+                LOG.info("userids={}", this.odlIdentityService.listUserIDs());
+                LOG.info("domains={}", this.odlIdentityService.listDomains(username));
+            } catch (IDMStoreException e) {
+
+            }
+            List<String> roles = this.odlIdentityService.listRoles(username, domain);
+            UserTokenPayload data = new UserTokenPayload();
+            data.setPreferredUsername(username);
+            data.setFamilyName("");
+            data.setGivenName(username);
+            data.setExp(this.tokenCreator.getDefaultExp());
+            data.setRoles(roles);
+            return this.tokenCreator.createNewJWT(data);
+
+        }
+        return 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 = null;
+        os = resp.getOutputStream();
+        os.write(output);
+
+    }
+
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/HeadersOnlyHttpServletRequest.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/HeadersOnlyHttpServletRequest.java
new file mode 100644 (file)
index 0000000..31b6d69
--- /dev/null
@@ -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/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappedBaseHttpResponse.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappedBaseHttpResponse.java
new file mode 100644 (file)
index 0000000..6b1a8ed
--- /dev/null
@@ -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/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappingBaseHttpClient.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/http/client/MappingBaseHttpClient.java
new file mode 100644 (file)
index 0000000..ca455dc
--- /dev/null
@@ -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/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/AuthService.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/AuthService.java
new file mode 100644 (file)
index 0000000..ec685a0
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * ============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.Map;
+import java.util.Map.Entry;
+import java.util.Optional;
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthProviderConfig;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthResponseData;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.UserTokenPayload;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.AuthHttpServlet;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.client.MappedBaseHttpResponse;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.client.MappingBaseHttpClient;
+import org.opendaylight.aaa.shiro.filters.backport.BearerToken;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class AuthService {
+
+
+    private static final Logger LOG = LoggerFactory.getLogger(AuthService.class.getName());
+    private final MappingBaseHttpClient httpClient;
+    protected final ObjectMapper mapper;
+    protected final OAuthProviderConfig config;
+    protected final TokenCreator tokenCreator;
+    private final String redirectUri;
+    private String localHostUrl;
+    public void setLocalHostUrl(String url) {
+        this.localHostUrl = url;
+    }
+    protected abstract String getTokenVerifierUri();
+
+    protected abstract Map<String, String> getAdditionalTokenVerifierParams();
+
+    protected abstract ResponseType getResponseType();
+
+    protected abstract boolean doSeperateRolesRequest();
+
+    protected abstract UserTokenPayload mapAccessToken(String spayload)
+            throws JsonMappingException, JsonProcessingException;
+
+    protected abstract String getLoginUrl(String callbackUrl);
+
+    public AuthService(OAuthProviderConfig config, String redirectUri, TokenCreator tokenCreator) {
+        this.config = config;
+        this.tokenCreator = tokenCreator;
+        this.redirectUri = redirectUri;
+        this.mapper = new ObjectMapper();
+        this.mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
+        this.httpClient = new MappingBaseHttpClient(this.config.getHost());
+    }
+
+    public PublicOAuthProviderConfig getConfig(String host) {
+        return new PublicOAuthProviderConfig(this, host);
+    }
+
+    public void handleRedirect(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        switch (this.getResponseType()) {
+            case CODE:
+                this.handleRedirectCode(req, resp);
+                break;
+            case TOKEN:
+                sendErrorResponse(resp, "not yet implemented");
+                break;
+            case SESSION_STATE:
+                break;
+        }
+
+    }
+
+    private static void sendErrorResponse(HttpServletResponse resp, String message) throws IOException {
+        resp.sendError(HttpServletResponse.SC_NOT_FOUND, message);
+
+    }
+
+    private void handleRedirectCode(HttpServletRequest req, HttpServletResponse resp) throws IOException {
+        final String code = req.getParameter("code");
+        OAuthResponseData response = this.getTokenForUser(code);
+        if (response != null) {
+            if (this.doSeperateRolesRequest()) {
+
+            } else {
+                this.handleUserInfoToken(response.getAccess_token(), resp);
+            }
+        } else {
+            sendErrorResponse(resp, "unable to verify code");
+        }
+
+    }
+
+    private void handleUserInfoToken(String accessToken, HttpServletResponse resp) throws IOException {
+        try {
+            DecodedJWT jwt = JWT.decode(accessToken);
+
+            String spayload = base64Decode(jwt.getPayload());
+            LOG.debug("payload in jwt from keycload='{}'", spayload);
+
+            UserTokenPayload data = this.mapAccessToken(spayload);
+            BearerToken onapToken = this.tokenCreator.createNewJWT(data);
+            sendTokenResponse(resp, onapToken);
+        } catch (JWTDecodeException | JsonProcessingException e) {
+            LOG.warn("unable to decode jwt token {}: ", accessToken, e);
+            sendErrorResponse(resp, e.getMessage());
+        }
+    }
+
+
+    private void sendTokenResponse(HttpServletResponse resp, BearerToken data) 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");
+            ServletOutputStream os = null;
+            os = resp.getOutputStream();
+            os.write(output);
+        } else {
+            resp.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
+            resp.setHeader("Location", assembleUrl(this.localHostUrl, this.redirectUri, data.getToken()));
+        }
+    }
+
+
+
+    private static String base64Decode(String data) {
+        return new String(Base64.getDecoder().decode(data), StandardCharsets.UTF_8);
+    }
+
+    private OAuthResponseData getTokenForUser(String code) {
+
+        Map<String, String> headers = new HashMap<>();
+        headers.put("Content-Type", "application/x-www-form-urlencoded");
+        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())));
+        }
+
+        Optional<MappedBaseHttpResponse<OAuthResponseData>> response = this.httpClient.sendMappedRequest(this.getTokenVerifierUri(),
+                "POST", body.substring(0, body.length() - 1), headers, OAuthResponseData.class);
+        if (response.isPresent() && response.get().isSuccess()) {
+            return response.get().body;
+        }
+        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, String host) {
+            this.id = authService.config.getId();
+            this.title = authService.config.getTitle();
+            this.loginUrl = authService.getLoginUrl(
+                    assembleRedirectUrl(host, AuthHttpServlet.REDIRECTURI, this.id));
+        }
+
+    }
+
+
+
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/KeycloakProviderService.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/KeycloakProviderService.java
new file mode 100644 (file)
index 0000000..3bfbb3b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * ============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.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) {
+        super(config, redirectUri, tokenCreator);
+        this.additionalTokenVerifierParams = new HashMap<>();
+        this.additionalTokenVerifierParams.put("grant_type", "authorization_code");
+    }
+
+    @Override
+    protected String getTokenVerifierUri() {
+        return "/auth/realms/onap/protocol/openid-connect/token";
+    }
+
+    @Override
+    protected String getLoginUrl(String callbackUrl) {
+        return String.format(
+                "%s/auth/realms/onap/protocol/openid-connect/auth?client_id=%s&response_type=code&scope=%s&redirect_uri=%s",
+                this.config.getHost(), urlEncode(this.config.getClientId()), this.config.getScope(),
+                urlEncode(callbackUrl));
+    }
+
+
+
+    private List<String> mapRoles(List<String> data) {
+
+        List<String> filteredRoles =
+                data.stream().filter(role -> !role.equals("uma_authorization") && !role.equals("offline_access"))
+                        .map(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.setExp(payload.getExp() * 1000L);
+        data.setFamilyName(payload.getFamilyName());
+        data.setGivenName(payload.getGivenName());
+        data.setPreferredUsername(payload.getPreferredUsername());
+        data.setRoles(this.mapRoles(payload.getRealmAccess().getRoles()));
+        return data;
+    }
+
+
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/NextcloudProviderService.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/NextcloudProviderService.java
new file mode 100644 (file)
index 0000000..ad1da68
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * ============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.UserTokenPayload;
+
+public class NextcloudProviderService extends AuthService {
+
+    public NextcloudProviderService(OAuthProviderConfig config, String redirectUri, TokenCreator tokenCreator) {
+        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;
+    }
+
+}
\ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/OAuthProviderFactory.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/OAuthProviderFactory.java
new file mode 100644 (file)
index 0000000..a09f150
--- /dev/null
@@ -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.providers;
+
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.OAuthProviderConfig;
+
+public class OAuthProviderFactory {
+
+
+    public static AuthService create(OAuthProvider key, OAuthProviderConfig config, String redirectUri,
+            TokenCreator tokenCreator) {
+        switch (key) {
+            case KEYCLOAK:
+                return new KeycloakProviderService(config, redirectUri, tokenCreator);
+            case NEXTCLOUD:
+                return new NextcloudProviderService(config, redirectUri, tokenCreator);
+        }
+        return null;
+    }
+
+    public static enum OAuthProvider {
+        KEYCLOAK, NEXTCLOUD
+    }
+
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/TokenCreator.java b/sdnr/wt/oauth-provider/provider-jar/src/main/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/providers/TokenCreator.java
new file mode 100644 (file)
index 0000000..3244f90
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : ccsdk features
+ * ================================================================================
+ * Copyright (C) 2021 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ *
+ */
+package org.onap.ccsdk.features.sdnr.wt.oauthprovider.providers;
+
+import 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.util.Arrays;
+import java.util.Date;
+import javax.servlet.http.HttpServletRequest;
+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.opendaylight.aaa.shiro.filters.backport.BearerToken;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class TokenCreator {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AuthHttpServlet.class.getName());
+    private static final long DEFAULT_TOKEN_LIFETIME_MS = 30 * 60 * 1000;
+    private static final String TOKEN_ISSUER = Config.getProperty("${TOKEN_ISSUER}", "ONAP SDNC");
+    private static TokenCreator _instance;
+    private static final String SECRET = Config.getProperty("${TOKEN_SECRET}", "secret");
+
+    private static final String ROLES_CLAIM = "roles";
+    private static final String FAMILYNAME_CLAIM = "family_name";
+    private static final String NAME_CLAIM = "name";
+
+    public static TokenCreator getInstance() {
+        if (_instance == null) {
+            _instance = new TokenCreator();
+        }
+        return _instance;
+    }
+
+    private TokenCreator() {
+
+    }
+
+    public BearerToken createNewJWT(UserTokenPayload data) {
+        Algorithm algorithm = Algorithm.HMAC256(SECRET);
+        final String token = JWT.create().withIssuer(TOKEN_ISSUER).withExpiresAt(new Date(data.getExp()))
+                .withSubject(data.getPreferredUsername()).withClaim(NAME_CLAIM, data.getGivenName())
+                .withClaim(FAMILYNAME_CLAIM, data.getFamilyName())
+                .withArrayClaim(ROLES_CLAIM, data.getRoles().toArray(new String[data.getRoles().size()]))
+                .sign(algorithm);
+        return new BearerToken(token);
+    }
+
+    public DecodedJWT verify(String token) {
+        DecodedJWT jwt = null;
+        LOG.debug("try to verify token {}", token);
+        try {
+            Algorithm algorithm = Algorithm.HMAC256(SECRET);
+            JWTVerifier verifier = JWT.require(algorithm).withIssuer(TOKEN_ISSUER).build();
+            jwt = verifier.verify(token);
+
+        } catch (JWTVerificationException e) {
+            LOG.warn("unable to verify token {}:", token, e);
+        }
+        return jwt;
+    }
+
+    public long getDefaultExp() {
+        return new Date().getTime() + DEFAULT_TOKEN_LIFETIME_MS;
+    }
+
+    public UserTokenPayload decode(HttpServletRequest req) throws JWTDecodeException {
+        final String authHeader = req.getHeader("Authorization");
+        if (authHeader == null || !authHeader.startsWith("Bearer")) {
+            return null;
+        }
+        DecodedJWT jwt = JWT.decode(authHeader.substring(7));
+        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());
+
+        return data;
+    }
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestConfig.java b/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestConfig.java
new file mode 100644 (file)
index 0000000..2b88141
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * ============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.io.IOException;
+import org.junit.Test;
+import org.onap.ccsdk.features.sdnr.wt.oauthprovider.data.Config;
+
+public class TestConfig {
+
+    @Test
+    public void test() throws IOException {
+
+        Config config = Config.load("src/test/resources/test.config.json");
+        System.out.println("config="+config);
+    }
+}
diff --git a/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestDeserializer.java b/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestDeserializer.java
new file mode 100644 (file)
index 0000000..236c0ff
--- /dev/null
@@ -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.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 token2 = "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ1OHNXaTF4QWxjT1pyelY4X0l2VjliMlJTaFdZUWV4aXZYUXNYLTFTMERNIn0."
+                + "eyJleHAiOjE2MTAzNzA3MDcsImlhdCI6MTYxMDM3MDQwNywianRpIjoiMTczMmI0YzQtNDJlYS00ZWM4LTlhNjMtMTY2YTg4ZTk5ZjQ0IiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjE4MzhjNGYyLTVmZTMtNGYwYy1iMmQyLWQzNjRiMjdhNDk5NyIsInR5cCI6IkJlYXJlciIsImF6cCI6ImFkbWluLWNsaSIsInNlc3Npb25fc3RhdGUiOiJhZjVkYTk2NS1jYmIzLTQzOTYtYmNjNi1kZTBkMDUyOWMyNDgiLCJhY3IiOiIxIiwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJhZG1pbiJ9.G_1ByqQlPuJ6_5nuIECfY1VqGufzWQpnFKuOy8YPOOug_jJsIwhVo-JQJiKAxYbHbmDNLrpRJTFlSub0K-1AFyxMw0k_W_YLV0dOTqIakVMTKk9obHFAYtthvhdbt5zb9-33OdCRMMKjA-arj8UeOLEAeFkaeYYBARCD4mEnMFG0vzEiovCCD-jXsfISiS-lOYnCd3hWK8e0brk_bvauxS9W4Z6nptE2564wshe9N_j9-3bQRRAHiAt6f755PhbYgJAu87GdA0bLh_TDe6fie-03goIFMssHoq4n67i-8501UoIG_LccijnfexCS-YwxkfTLbz5d8PvsNadqvFlvig";
+        final String response =
+                "{\"access_token\":\"eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJ1OHNXaTF4QWxjT1pyelY4X0l2VjliMlJTaFdZUWV4aXZYUXNYLTFTME"
+                        + "RNIn0.eyJleHAiOjE2MTAzNjE2OTQsImlhdCI6MTYxMDM2MTM5NCwianRpIjoiOWRhOThmMTYtOTEyOS00N2NmLTgzOGQtNWQzYmVkYzYyZTJjIiwiaXNzIjoiaHR0cDovLzEwLjIwLjExLjE2MDo4MDgwL2F1dGgvcmVhbG1zL21hc3RlciIsInN1YiI6IjE4MzhjNGYyLTVmZTMtNGYwYy1iMmQyLWQzNjRiMjdhNDk5NyIsInR5cCI6IkJlYXJlciIsImF6cCI6I"
+                        + "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\"} ";
+
+        OAuthResponseData data = new MappedBaseHttpResponse<>(200,response,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/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestProperty.java b/sdnr/wt/oauth-provider/provider-jar/src/test/java/org/onap/ccsdk/features/sdnr/wt/oauthprovider/test/TestProperty.java
new file mode 100644 (file)
index 0000000..2d03bab
--- /dev/null
@@ -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/provider-jar/src/test/resources/test.config.json b/sdnr/wt/oauth-provider/provider-jar/src/test/resources/test.config.json
new file mode 100644 (file)
index 0000000..88137fd
--- /dev/null
@@ -0,0 +1,18 @@
+{
+    "tokenSecret": "${OAUTH_TOKEN_SECRET}",
+    "tokenIssuer": "${OAUTH_TOKEN_ISSUER}",
+    "host": "",
+    "redirectUri": "${OAUTH_ODLUX_REDIRECT_URI}",
+    "supportOdlUsers": "${OAUTH_SUPPORT_ODLUSERS}",
+    "providers": [
+        {
+            "id": "keycloak",
+            "type": "KEYCLOAK",
+            "host": "http://10.20.11.160:8080",
+            "clientId": "odlux.app",
+            "secret": "5da4ea3d-8cc9-4669-bd7e-3ecb91d120cd",
+            "scope": "openid",
+            "title": "OSNL Keycloak Provider"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/sdnr/wt/oauth-provider/provider-osgi/pom.xml b/sdnr/wt/oauth-provider/provider-osgi/pom.xml
new file mode 100644 (file)
index 0000000..3d17baf
--- /dev/null
@@ -0,0 +1,141 @@
+<?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.1.1-SNAPSHOT</version>
+        <relativePath/>
+    </parent>
+
+    <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+    <artifactId>sdnr-wt-oauth-provider</artifactId>
+    <version>1.1.1-SNAPSHOT</version>
+    <packaging>bundle</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-oauth-provider-jar</artifactId>
+            <version>${project.version}</version>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.opendaylight.aaa</groupId>
+                    <artifactId>aaa-shiro</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>com.highstreet-technologies.aaa</groupId>
+                    <artifactId>aaa-shiro</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>org.apache.shiro</groupId>
+                    <artifactId>shiro-web</artifactId>
+                </exclusion>
+                <exclusion>
+                    <groupId>${project.groupId}</groupId>
+                    <artifactId>sdnr-wt-common</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+                        <Bundle-Version>${project.version}</Bundle-Version>
+                        <Export-Package>
+                            org.onap.ccsdk.features.sdnr.wt.oauthprovider;version=${project.version},
+                            org.onap.ccsdk.features.sdnr.wt.oauthprovider.http;version=${project.version},
+                            org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.client;version=${project.version},
+                            org.onap.ccsdk.features.sdnr.wt.oauthprovider.data;version=${project.version},
+                            org.onap.ccsdk.features.sdnr.wt.oauthprovider.services;version=${project.version}
+                        </Export-Package>
+                        <Import-Package>
+                            javax.servlet,
+                            javax.servlet.http,
+                            javax.net.ssl,
+                            javax.crypto,
+                            javax.crypto.spec,
+                            javax.xml.transform,
+                            javax.xml.datatype,
+                            javax.management,
+                            javax.security.auth,
+                            javax.security.auth.login,
+                            javax.security.auth.callback,
+                            javax.xml.parsers,
+                            javax.xml.namespace,
+                            javax.xml.transform.stream,
+                            org.apache.shiro.authc,
+                            org.apache.shiro.authz,
+                            org.apache.shiro.realm,
+                            org.apache.shiro.subject,
+                            org.jolokia.osgi.security,
+                            org.onap.ccsdk.features.sdnr.wt.common.http,
+                            org.opendaylight.aaa.api,
+                            org.opendaylight.aaa.api.shiro.principal,
+                            org.opendaylight.aaa.shiro.realm,
+                            org.opendaylight.aaa.shiro.filters.backport,
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619,
+                            org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.shiro.configuration,
+                            com.fasterxml.jackson.databind,
+                            com.fasterxml.jackson.databind.deser.std,
+                            com.fasterxml.jackson.databind.ser.std,
+                            com.fasterxml.jackson.databind.module,
+                            com.fasterxml.jackson.annotation,
+                            com.fasterxml.jackson.core.type,
+                            com.fasterxml.jackson.core,
+                            org.apache.commons.codec.binary
+                        </Import-Package>
+                        <Embed-Dependency>*;scope=compile|runtime;inline=false</Embed-Dependency>
+                        <Embed-Dependency>*;scope=compile|runtime;artifactId=!shiro-core;inline=false</Embed-Dependency>
+                        <Embed-Transitive>true</Embed-Transitive>
+                        <Fragment-Host>org.apache.shiro.core</Fragment-Host>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+</project>
diff --git a/sdnr/wt/oauth-provider/provider-osgi/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml b/sdnr/wt/oauth-provider/provider-osgi/src/main/resources/org/opendaylight/blueprint/impl-blueprint.xml
new file mode 100644 (file)
index 0000000..f7dd467
--- /dev/null
@@ -0,0 +1,50 @@
+<?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=======================================================
+  ~
+  -->
+
+<blueprint xmlns:odl="http://opendaylight.org/xmlns/blueprint/v1.0.0"
+           xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0" odl:use-default-for-reference-types="true">
+
+    <reference id="odlAuthenticator" interface="org.jolokia.osgi.security.Authenticator" />
+
+    <reference id="odlIdentityService" interface="org.opendaylight.aaa.api.IdMService" />
+
+    <odl:clustered-app-config
+          binding-class="org.opendaylight.yang.gen.v1.urn.opendaylight.aaa.app.config.rev170619.ShiroConfiguration"
+          id="shiroConfiguration" default-config-file-name="aaa-app-config.xml" />
+          
+    <bean id="authServlet"
+          class="org.onap.ccsdk.features.sdnr.wt.oauthprovider.http.AuthHttpServlet">
+          <property ref="odlAuthenticator" name="odlAuthenticator" />
+          <property ref="odlIdentityService" name="odlIdentityService" />
+          <property ref="shiroConfiguration" name="shiroConfiguration" />
+    </bean>
+
+    <service interface="javax.servlet.http.HttpServlet" ref="authServlet">
+        <service-properties>
+            <entry key="alias" value="/oauth"/>
+        </service-properties>
+    </service>
+
+</blueprint>
index 43a540e..6b0dfdf 100644 (file)
@@ -58,6 +58,7 @@
         <module>devicemanager-adapter-manager</module>
         <module>mountpoint-registrar</module>
         <module>odlux</module>
+        <module>oauth-provider</module>
         <module>featureaggregator</module>
     </modules>
 </project>