diff --git a/.travis.yml b/.travis.yml index 8bc14a93..f1078b3f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,9 @@ language: java - cache: - directories: - - $HOME/.m2 - + directories: + - $HOME/.m2 jdk: - - oraclejdk8 + - oraclejdk8 +branches: + only: + - master diff --git a/README.md b/README.md index e7cf98eb..3fc69bd4 100644 --- a/README.md +++ b/README.md @@ -7,12 +7,19 @@ built on top of light-4j and light-rest-4j frameworks. [![Build Status](https://travis-ci.org/networknt/light-oauth2.svg?branch=master)](https://travis-ci.org/networknt/light-oauth2) +Light platform follows security first design and we have provided an OAuth 2.0 provider +light-oauth2 which is based on light-4j and light-rest-4j frameworks with 7 microservices. +Some of the services implement the OAuth 2.0 specifications and others implement some +extensions to make OAuth more suitable to protect service to service communication, other +styles of services like GraphQL, RPC and Event Driven, Key management and distribution, +service registration, token scope calculation and token exchange. + ## Why this OAuth 2.0 Authorization Server ### Fast and small memory footprint to lower production cost. -The authorization code service can support 60000 user login and get authorization code redirected in a second on a Mac Book Pro. -The token service can generate 700 JWT access tokens signed by PKI per second on a Mac Book Pro. +It can support 60000 user login and get authorization code redirect and can generate +700 access tokens per second on my laptop. It has 7 microservices connected with in-memory data grid and each service can be scaled individually. @@ -24,29 +31,36 @@ OAuth 2.0 is just a specification and a lot of details are in the individual implementation. Our implementation has a lot of extensions and enhancements for additional security and prevent users making mistakes. For example, we have added an additional client type called "trusted" and only this type of -client can issue resource owner password credentials grant type and any custom -grant types. Also, when expose your OAuth 2.0 services the Internet, you only -need to expose authorization code service for user login and token service for -client to get access token. Other services can only be accessed internal. +client can issue resource owner password credentials grant type. + +### More deployment options + +You can deploy all services or just deploy the services for your use cases. You can +deploy token and code service to DMZ and all others internal for maximum security. +You can have several token services or deploy token service as sidecar pattern in +each node. You can start more instance of key service on the day that your public +key certificate for signature verification is changed and shutdown all of the but +one the next day. You can take the full advantages of microservices deployment. ### Seamlessly integration with Light-Java framework * Built on top of light-4j and light-rest-4j -* light-4j client and security modules manages all the communication with OAuth2 -* Support service on-boarding from Light-Portal -* Support client on-boarding from Light-Portal -* Support user management from Light-Portal +* Light-4j Client and Security modules manages most of the communications with OAuth2 +* Support service on-boarding from light-portal +* Support client on-boarding from light-portal +* Support user management from light-portal * Open sourced OpenAPI specifications for all microserivces ### Easy to integrate with your APIs or services -The OAuth2 services can be started in a docker compose for your local development -and can be managed by Kubernetes on official environment. +The OAuth2 services can be started in a docker-compose for your local development and +can be managed by Kubernetes on official test and production environment. It exposes +RESTful APIs and can be access from all languages and applications. ### Support multiple databases and can be extended and customized easily Out of the box, it supports Mysql, Postgres and Oracle XE and H2 for unit tests. Other -databases can be easily added with configuration change in service.yml config file. +databases can be easily added with configuration change in service.yml. ### Public key certificate distribution @@ -55,16 +69,42 @@ With distributed security verification, JWT signature public key certificates mu but distributed to all resource servers. The traditional push approach is not working with microservices architecture and pull approach is adopted. There is a key service with endpoint to retrieve public key certificate from microservices -during runtime based on the key_id from JWT header. For more details on key service, -please refer to [key distribution][] +during runtime based on the key_id from JWT header. + +### Two tokens to support microservices architecture + +Each service in a microservices application needs a subject token which identifies the +original caller (the person who logged in the original client) and an access token +which identifies the immediate caller (might be another microservices). Both tokens +will be verified with scopes to the API endpoint level. Additional claims in these +tokens will be used for fine-grained authorization which happens within the business +context. -### Additional documents +### Token exchange for high security -Along with the documentation on each [light-oauth2 service][], there are -[light-oauth2 tutorial][] to help user to get started. +Even with two tokens, we can only verify who is the original calller and which client is +the immediate caller. For some highly protected service like payment or fund transfer, +we need to ensure that the call is routed through some known services. light-oauth2 +token service support token exchange and chaining so that a service can verify the +entire call tree to authorize if the call is authorized or not. +### Service registration for scope calculation -### OAuth2 server, portal and light Java to form ecosystem +light-oauth2 has a service registration to allow all service to be registered with service +id and all endpoints as well as scopes for the endpoint. During client registration, you +can link a client to services/endpoints and the scope of the client can be calculated +and updated in client table. This avoids developers to pass in scopes when getting +access token as there might be hundreds of them for a client that accesses dozens of +microservices. + +### All activities are audited + +A database audit handler has been wired into all light-oauth2 services to log each +activity across services with sensitive info masked. In the future we will put these +logs into AI stream processing to identify abnormal behaviors just like normal service +log processing. + +### OAuth2 server, portal and light-4j to form ecosystem [light-java](https://github.com/networknt/light-java) to build API @@ -72,6 +112,30 @@ Along with the documentation on each [light-oauth2 service][], there are [light-portal](https://github.com/networknt/light-portal) to manage clients and APIs -[key distribution]: https://doc.networknt.com/service/oauth/service/key/ -[light-oauth2 service]: https://doc.networknt.com/service/oauth/service/ -[light-oauth2 tutorial]: https://doc.networknt.com/tutorial/oauth/ +## Introduction + +This [introduction](https://doc.networknt.com/service/oauth/introduction/) document contains all the basic concept of OAuth 2.0 specification and how it work in general. + +## Getting started + +The easiest way to start using light-oauth2 in your development environment is through +docker-compose in light-docker repository. Please refer to [getting started](https://doc.networknt.com/getting-started/light-oauth2/) for more information. + +## Architecture + +There are some key decision points that are documented in [architecture](https://doc.networknt.com/service/oauth/architecture/) section. + +## Documentation + +The detailed [service document](https://doc.networknt.com/service/oauth/service/) help users to understand how each individual service +works and the specification for each services. It also contains information on which scenarios will trigger what kind of errors. + +## Tutorial + +There are [tutorials](https://doc.networknt.com/tutorial/oauth/) for each service that shows how to use the most common use cases with examples. + +## Reference + +There are vast amount of information about OAuth 2.0 specifications and implementations. +Here are some important [references](https://doc.networknt.com/service/oauth/reference/) that can help you to understand OAuth 2.0 Authorization. + diff --git a/authorize/docker/Dockerfile b/authorize/Dockerfile similarity index 100% rename from authorize/docker/Dockerfile rename to authorize/Dockerfile diff --git a/authorize/build.sh b/authorize/build.sh index 8080f575..1a2e4be9 100755 --- a/authorize/build.sh +++ b/authorize/build.sh @@ -42,7 +42,7 @@ cleanup() { publish() { echo "Building Docker image with version $VERSION" - docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./docker/Dockerfile . --no-cache=true + docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./Dockerfile . --no-cache=true docker build -t $IMAGE_NAME:$VERSION-redhat -f ./docker/Dockerfile-Redhat . --no-cache=true echo "Images built with version $VERSION" echo "Pushing image to DockerHub" diff --git a/authorize/docker/Dockerfile-Redhat b/authorize/docker/Dockerfile-Redhat index 2dc605ba..ea3668b7 100644 --- a/authorize/docker/Dockerfile-Redhat +++ b/authorize/docker/Dockerfile-Redhat @@ -2,27 +2,30 @@ FROM registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift USER root -ENV APP_DIR=/app \ +ENV APP_DIR=app \ GROUP_NAME=networknt \ GROUP_ID=1000 \ USER_NAME=networknt \ USER_UID=1000 RUN groupadd -g ${GROUP_ID} -r ${GROUP_NAME} && \ - useradd -u ${USER_UID} -g ${GROUP_NAME} -d "${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} + useradd -u ${USER_UID} -g ${GROUP_NAME} -d "/${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} # Add the jar file into the container at /app -ADD target/oauth2-authorize.jar ${APP_DIR}/server.jar +ADD target/oauth2-authorize.jar ./${APP_DIR}/server.jar # change permissions of app directory -RUN chown -R ${USER_NAME}:${GROUP_NAME} "${APP_DIR}" +RUN mkdir -p ./${APP_DIR}/config && \ + chown -R ${USER_NAME}:0 "./${APP_DIR}/config" && \ + find "./${APP_DIR}/config" -type d -exec chmod 750 {} \; && \ + find "./${APP_DIR}/config" -type f -exec chmod 640 {} \; # Port available to the world outside of this container -EXPOSE 6881 +EXPOSE 8080 USER ${USER_UID} # Set the working directory to /app -WORKDIR ${APP_DIR} +WORKDIR ./${APP_DIR} -CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] +CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] \ No newline at end of file diff --git a/authorize/src/main/resources/logback.xml b/authorize/src/main/resources/logback.xml index 6e58aff8..455f137d 100644 --- a/authorize/src/main/resources/logback.xml +++ b/authorize/src/main/resources/logback.xml @@ -28,7 +28,7 @@ - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n @@ -36,7 +36,7 @@ target/test.log false - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %class{36}:%L %M - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n diff --git a/authorize/src/test/resources/create_h2.sql b/authorize/src/test/resources/create_h2.sql index ad8e3dea..52c37cdf 100644 --- a/authorize/src/test/resources/create_h2.sql +++ b/authorize/src/test/resources/create_h2.sql @@ -1,8 +1,8 @@ -DROP table IF EXISTS users; -DROP table IF EXISTS clients; -DROP table IF EXISTS services; +DROP table IF EXISTS user_profile; +DROP table IF EXISTS client; +DROP table IF EXISTS service; -create table users ( +create table user_profile ( user_id varchar PRIMARY KEY, user_type varchar, -- admin, customer, employee, partner first_name varchar, @@ -13,13 +13,13 @@ create table users ( update_dt DATE ); -CREATE UNIQUE INDEX email_idx ON users(email); +CREATE UNIQUE INDEX email_idx ON user_profile(email); -create table clients ( +create table client ( client_id VARCHAR PRIMARY KEY, - client_type VARCHAR, client_secret VARCHAR, - client_profile VARCHAR, + client_type VARCHAR, -- public, confidential, trusted + client_profile VARCHAR, -- server, mobile, service, batch, browser client_name VARCHAR, client_desc VARCHAR, scope VARCHAR, @@ -30,7 +30,7 @@ create table clients ( update_dt DATE ); -create table services ( +create table service ( service_id VARCHAR PRIMARY KEY, service_type VARCHAR, -- api, ms service_name VARCHAR, @@ -41,10 +41,10 @@ create table services ( update_dt DATE ); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); -INSERT INTO services (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); +INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); diff --git a/cache/src/main/java/com/networknt/oauth/cache/CacheStartupHookProvider.java b/cache/src/main/java/com/networknt/oauth/cache/CacheStartupHookProvider.java index aa770942..51731ad2 100644 --- a/cache/src/main/java/com/networknt/oauth/cache/CacheStartupHookProvider.java +++ b/cache/src/main/java/com/networknt/oauth/cache/CacheStartupHookProvider.java @@ -3,10 +3,7 @@ import com.hazelcast.config.*; import com.hazelcast.core.Hazelcast; import com.hazelcast.core.HazelcastInstance; -import com.networknt.oauth.cache.model.ClientDataSerializableFactory; -import com.networknt.oauth.cache.model.RefreshTokenDataSerializableFactory; -import com.networknt.oauth.cache.model.ServiceDataSerializableFactory; -import com.networknt.oauth.cache.model.UserDataSerializableFactory; +import com.networknt.oauth.cache.model.*; import com.networknt.server.StartupHookProvider; /** @@ -25,6 +22,7 @@ public void onStartup() { config.getSerializationConfig().addDataSerializableFactory(2, new ClientDataSerializableFactory()); config.getSerializationConfig().addDataSerializableFactory(3, new ServiceDataSerializableFactory()); config.getSerializationConfig().addDataSerializableFactory(4, new RefreshTokenDataSerializableFactory()); + config.getSerializationConfig().addDataSerializableFactory(5, new ServiceEndpointDataSerializableFactory()); // service map with near cache. MapConfig serviceConfig = new MapConfig(); @@ -41,6 +39,21 @@ public void onStartup() { config.addMapConfig(serviceConfig); + // service endpoint map with near cache. + MapConfig serviceEndpointConfig = new MapConfig(); + serviceEndpointConfig.setName("serviceEndpoints"); + NearCacheConfig serviceEndpointCacheConfig = new NearCacheConfig(); + serviceEndpointCacheConfig.setEvictionPolicy("NONE"); + serviceEndpointCacheConfig.setInMemoryFormat(InMemoryFormat.OBJECT); + serviceEndpointCacheConfig.setCacheLocalEntries(true); // this enables the local caching + serviceEndpointConfig.setNearCacheConfig(serviceEndpointCacheConfig); + + serviceEndpointConfig.getMapStoreConfig() + .setEnabled(true) + .setClassName("com.networknt.oauth.cache.ServiceEndpointMapStore"); + + config.addMapConfig(serviceEndpointConfig); + // client map with near cache. MapConfig clientConfig = new MapConfig(); clientConfig.setName("clients"); diff --git a/cache/src/main/java/com/networknt/oauth/cache/ClientMapStore.java b/cache/src/main/java/com/networknt/oauth/cache/ClientMapStore.java index 5106c97d..384ad5e3 100644 --- a/cache/src/main/java/com/networknt/oauth/cache/ClientMapStore.java +++ b/cache/src/main/java/com/networknt/oauth/cache/ClientMapStore.java @@ -19,11 +19,11 @@ public class ClientMapStore implements MapStore { private static final Logger logger = LoggerFactory.getLogger(ClientMapStore.class); private static final DataSource ds = (DataSource) SingletonServiceFactory.getBean(DataSource.class); - private static final String insert = "INSERT INTO clients (client_id, client_secret, client_type, client_profile, client_name, client_desc, scope, redirect_uri, owner_id, create_dt) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; - private static final String delete = "DELETE FROM clients WHERE client_id = ?"; - private static final String select = "SELECT * FROM clients WHERE client_id = ?"; - private static final String update = "UPDATE clients SET client_type=?, client_profile=?, client_name=?, client_desc=?, scope=?, redirect_uri=?, owner_id=?, update_dt=? WHERE client_id=?"; - private static final String loadall = "SELECT client_id FROM clients"; + private static final String insert = "INSERT INTO client (client_id, client_secret, client_type, client_profile, client_name, client_desc, scope, redirect_uri, owner_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)"; + private static final String delete = "DELETE FROM client WHERE client_id = ?"; + private static final String select = "SELECT * FROM client WHERE client_id = ?"; + private static final String update = "UPDATE client SET client_type=?, client_profile=?, client_name=?, client_desc=?, scope=?, redirect_uri=?, owner_id=? WHERE client_id=?"; + private static final String loadall = "SELECT client_id FROM client"; @Override public synchronized void delete(String key) { @@ -50,7 +50,6 @@ public synchronized void store(String key, Client client) { stmt.setString(7, client.getScope()); stmt.setString(8, client.getRedirectUri()); stmt.setString(9, client.getOwnerId()); - stmt.setDate(10, client.getCreateDt()); stmt.executeUpdate(); } catch (SQLException e) { logger.error("Exception:", e); @@ -65,8 +64,7 @@ public synchronized void store(String key, Client client) { stmt.setString(5, client.getScope()); stmt.setString(6, client.getRedirectUri()); stmt.setString(7, client.getOwnerId()); - stmt.setDate(8, client.getUpdateDt()); - stmt.setString(9, client.getClientId()); + stmt.setString(8, client.getClientId()); stmt.executeUpdate(); } catch (SQLException e) { logger.error("Exception:", e); @@ -101,8 +99,6 @@ public synchronized Client load(String key) { client.setScope(rs.getString("scope")); client.setRedirectUri(rs.getString("redirect_uri")); client.setOwnerId(rs.getString("owner_id")); - client.setCreateDt(rs.getDate("create_dt")); - client.setUpdateDt(rs.getDate("update_dt")); } } } catch (SQLException e) { diff --git a/cache/src/main/java/com/networknt/oauth/cache/ServiceEndpointMapStore.java b/cache/src/main/java/com/networknt/oauth/cache/ServiceEndpointMapStore.java new file mode 100644 index 00000000..cacccf8b --- /dev/null +++ b/cache/src/main/java/com/networknt/oauth/cache/ServiceEndpointMapStore.java @@ -0,0 +1,130 @@ +package com.networknt.oauth.cache; + +import com.hazelcast.core.MapStore; +import com.networknt.oauth.cache.model.Service; +import com.networknt.oauth.cache.model.ServiceEndpoint; +import com.networknt.service.SingletonServiceFactory; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; + +public class ServiceEndpointMapStore implements MapStore> { + private static final Logger logger = LoggerFactory.getLogger(ServiceEndpointMapStore.class); + private static final DataSource ds = (DataSource) SingletonServiceFactory.getBean(DataSource.class); + private static final String insert = "INSERT INTO service_endpoint (service_id, endpoint, operation, scope) VALUES (?, ?, ?, ?)"; + private static final String delete = "DELETE FROM service_endpoint WHERE service_id = ?"; + private static final String select = "SELECT * FROM service_endpoint WHERE service_id = ?"; + private static final String loadall = "SELECT service_id FROM service_endpoint"; + + @Override + public synchronized void store(String key, List serviceEndpoints) { + if(logger.isDebugEnabled()) logger.debug("Store:" + key); + try (Connection connection = ds.getConnection()) { + connection.setAutoCommit(false); + if(load(key) != null) { + // delete all endpoints for this serviceId first + try (PreparedStatement stmt = connection.prepareStatement(delete)) { + stmt.setString(1, key); + stmt.executeUpdate(); + } catch (SQLException e) { + logger.error("Exception:", e); + connection.rollback(); + throw new RuntimeException(e); + } + } + try (PreparedStatement stmt = connection.prepareStatement(insert)) { + for (ServiceEndpoint serviceEndpoint : serviceEndpoints) { + stmt.setString(1, key); + stmt.setString(2, serviceEndpoint.getEndpoint()); + stmt.setString(3, serviceEndpoint.getOperation()); + stmt.setString(4, serviceEndpoint.getScope()); + stmt.addBatch(); + } + stmt.executeBatch(); + } catch (SQLException e) { + logger.error("Exception:", e); + connection.rollback(); + throw new RuntimeException(e); + } + connection.commit(); + } catch (SQLException e) { + logger.error("SQLException:", e); + throw new RuntimeException(e); + } + } + + @Override + public synchronized void storeAll(Map> map) { + for (Map.Entry> entry : map.entrySet()) + store(entry.getKey(), entry.getValue()); + } + + @Override + public synchronized void delete(String key) { + if(logger.isDebugEnabled()) logger.debug("Delete:" + key); + try (Connection connection = ds.getConnection(); PreparedStatement stmt = connection.prepareStatement(delete)) { + stmt.setString(1, key); + stmt.executeUpdate(); + } catch (SQLException e) { + logger.error("Exception:", e); + throw new RuntimeException(e); + } + } + + @Override + public synchronized void deleteAll(Collection keys) { + keys.forEach(this::delete); + } + + @Override + public synchronized List load(String key) { + if(logger.isDebugEnabled()) logger.debug("Load:" + key); + List serviceEndpoints = new ArrayList<>(); + try (Connection connection = ds.getConnection(); PreparedStatement stmt = connection.prepareStatement(select)) { + stmt.setString(1, key); + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + ServiceEndpoint serviceEndpoint = new ServiceEndpoint(); + serviceEndpoint.setEndpoint(rs.getString("endpoint")); + serviceEndpoint.setOperation(rs.getString("operation")); + serviceEndpoint.setScope(rs.getString("scope")); + serviceEndpoints.add(serviceEndpoint); + } + } + } catch (SQLException e) { + logger.error("Exception:", e); + throw new RuntimeException(e); + } + return serviceEndpoints; + } + + @Override + public synchronized Map> loadAll(Collection keys) { + Map> result = new HashMap<>(); + for (String key : keys) result.put(key, load(key)); + return result; + } + + @Override + public Iterable loadAllKeys() { + if(logger.isDebugEnabled()) logger.debug("loadAllKeys is called"); + List keys = new ArrayList<>(); + try (Connection connection = ds.getConnection(); PreparedStatement stmt = connection.prepareStatement(loadall)) { + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + keys.add(rs.getString("service_id")); + } + } + } catch (SQLException e) { + logger.error("Exception:", e); + throw new RuntimeException(e); + } + return keys; + } +} diff --git a/cache/src/main/java/com/networknt/oauth/cache/ServiceMapStore.java b/cache/src/main/java/com/networknt/oauth/cache/ServiceMapStore.java index 735d63f5..7eff5857 100644 --- a/cache/src/main/java/com/networknt/oauth/cache/ServiceMapStore.java +++ b/cache/src/main/java/com/networknt/oauth/cache/ServiceMapStore.java @@ -19,11 +19,11 @@ public class ServiceMapStore implements MapStore { private static final Logger logger = LoggerFactory.getLogger(ServiceMapStore.class); private static final DataSource ds = (DataSource) SingletonServiceFactory.getBean(DataSource.class); - private static final String insert = "INSERT INTO services (service_id, service_type, service_name, service_desc, scope, owner_id, create_dt) VALUES (?, ?, ?, ?, ?, ?, ?)"; - private static final String delete = "DELETE FROM services WHERE service_id = ?"; - private static final String select = "SELECT * FROM services WHERE service_id = ?"; - private static final String update = "UPDATE services SET service_type = ?, service_name=?, service_desc=?, scope=?, owner_id=?, update_dt=? WHERE service_id=?"; - private static final String loadall = "SELECT service_id FROM services"; + private static final String insert = "INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES (?, ?, ?, ?, ?, ?)"; + private static final String delete = "DELETE FROM service WHERE service_id = ?"; + private static final String select = "SELECT * FROM service WHERE service_id = ?"; + private static final String update = "UPDATE service SET service_type = ?, service_name=?, service_desc=?, scope=?, owner_id=? WHERE service_id=?"; + private static final String loadall = "SELECT service_id FROM service"; @Override public synchronized void delete(String key) { @@ -47,7 +47,6 @@ public synchronized void store(String key, Service service) { stmt.setString(4, service.getServiceDesc()); stmt.setString(5, service.getScope()); stmt.setString(6, service.getOwnerId()); - stmt.setDate(7, service.getCreateDt()); stmt.executeUpdate(); } catch (SQLException e) { logger.error("Exception:", e); @@ -60,8 +59,7 @@ public synchronized void store(String key, Service service) { stmt.setString(3, service.getServiceDesc()); stmt.setString(4, service.getScope()); stmt.setString(5, service.getOwnerId()); - stmt.setDate(6, service.getUpdateDt()); - stmt.setString(7, service.getServiceId()); + stmt.setString(6, service.getServiceId()); stmt.executeUpdate(); } catch (SQLException e) { logger.error("Exception:", e); @@ -93,8 +91,6 @@ public synchronized Service load(String key) { service.setServiceDesc(rs.getString("service_desc")); service.setScope(rs.getString("scope")); service.setOwnerId(rs.getString("owner_id")); - service.setCreateDt(rs.getDate("create_dt")); - service.setUpdateDt(rs.getDate("update_dt")); } } } catch (SQLException e) { diff --git a/cache/src/main/java/com/networknt/oauth/cache/UserMapStore.java b/cache/src/main/java/com/networknt/oauth/cache/UserMapStore.java index d624f063..2524a427 100644 --- a/cache/src/main/java/com/networknt/oauth/cache/UserMapStore.java +++ b/cache/src/main/java/com/networknt/oauth/cache/UserMapStore.java @@ -17,13 +17,13 @@ * Created by stevehu on 2016-12-27. */ public class UserMapStore implements MapStore { - static final Logger logger = LoggerFactory.getLogger(ServiceMapStore.class); + static final Logger logger = LoggerFactory.getLogger(UserMapStore.class); static final DataSource ds = (DataSource) SingletonServiceFactory.getBean(DataSource.class); - private static final String insert = "INSERT INTO users (user_id, user_type, first_name, last_name, email, password, create_dt) VALUES (?, ?, ?, ?, ?, ?, ?)"; - private static final String delete = "DELETE FROM users WHERE user_id = ?"; - private static final String select = "SELECT * FROM users WHERE user_id = ?"; - private static final String update = "UPDATE users SET user_type=?, first_name=?, last_name=?, email=?, password=?, update_dt=? WHERE user_id = ?"; - private static final String loadall = "SELECT user_id FROM users"; + private static final String insert = "INSERT INTO user_profile (user_id, user_type, first_name, last_name, email, password) VALUES (?, ?, ?, ?, ?, ?)"; + private static final String delete = "DELETE FROM user_profile WHERE user_id = ?"; + private static final String select = "SELECT * FROM user_profile WHERE user_id = ?"; + private static final String update = "UPDATE user_profile SET user_type=?, first_name=?, last_name=?, email=?, password=? WHERE user_id = ?"; + private static final String loadall = "SELECT user_id FROM user_profile"; @Override public synchronized void delete(String key) { @@ -47,7 +47,6 @@ public synchronized void store(String key, User user) { stmt.setString(4, user.getLastName()); stmt.setString(5, user.getEmail()); stmt.setString(6, user.getPassword()); - stmt.setDate(7, user.getCreateDt()); stmt.executeUpdate(); } catch (SQLException e) { logger.error("Exception:", e); @@ -60,8 +59,7 @@ public synchronized void store(String key, User user) { stmt.setString(3, user.getLastName()); stmt.setString(4, user.getEmail()); stmt.setString(5, user.getPassword()); - stmt.setDate(6, user.getUpdateDt()); - stmt.setString(7, user.getUserId()); + stmt.setString(6, user.getUserId()); stmt.executeUpdate(); } catch (SQLException e) { logger.error("Exception:", e); @@ -93,8 +91,6 @@ public synchronized User load(String key) { user.setLastName(rs.getString("last_name")); user.setEmail(rs.getString("email")); user.setPassword(rs.getString("password")); - user.setCreateDt(rs.getDate("create_dt")); - user.setUpdateDt(rs.getDate("update_dt")); } } } catch (SQLException e) { diff --git a/cache/src/main/java/com/networknt/oauth/cache/model/Service.java b/cache/src/main/java/com/networknt/oauth/cache/model/Service.java index a96953ab..57399687 100644 --- a/cache/src/main/java/com/networknt/oauth/cache/model/Service.java +++ b/cache/src/main/java/com/networknt/oauth/cache/model/Service.java @@ -10,7 +10,6 @@ import io.swagger.annotations.ApiModelProperty; import java.io.IOException; -import java.sql.Date; import java.util.Objects; public class Service implements IdentifiedDataSerializable { @@ -20,9 +19,10 @@ public class Service implements IdentifiedDataSerializable { * service type */ public enum ServiceTypeEnum { - MS("ms"), - - API("api"); + SWAGGER("swagger"), + GRAPHQL("graphql"), + HYBRID("hybrid"), + OPENAPI("openapi"); private final String value; @@ -57,10 +57,6 @@ public static ServiceTypeEnum fromValue(String text) { private String scope = null; - private Date createDt = null; - - private Date updateDt = null; - public Service serviceId(String serviceId) { this.serviceId = serviceId; return this; @@ -151,37 +147,6 @@ public void setScope(String scope) { this.scope = scope; } - public Service createDt(Date createDt) { - this.createDt = createDt; - return this; - } - - - @ApiModelProperty(example = "null", value = "create date time") - @JsonProperty("createDt") - public Date getCreateDt() { - return createDt; - } - public void setCreateDt(Date createDt) { - this.createDt = createDt; - } - - public Service updateDt(Date updateDt) { - this.updateDt = updateDt; - return this; - } - - - @ApiModelProperty(example = "null", value = "update date time") - @JsonProperty("updateDt") - public Date getUpdateDt() { - return updateDt; - } - public void setUpdateDt(Date updateDt) { - this.updateDt = updateDt; - } - - @Override public boolean equals(Object o) { if (this == o) { @@ -196,14 +161,12 @@ public boolean equals(Object o) { Objects.equals(serviceName, service.serviceName) && Objects.equals(serviceDesc, service.serviceDesc) && Objects.equals(ownerId, service.ownerId) && - Objects.equals(scope, service.scope) && - Objects.equals(createDt, service.createDt) && - Objects.equals(updateDt, service.updateDt); + Objects.equals(scope, service.scope); } @Override public int hashCode() { - return Objects.hash(serviceId, serviceType, serviceName, serviceDesc, ownerId, scope, createDt, updateDt); + return Objects.hash(serviceId, serviceType, serviceName, serviceDesc, ownerId, scope); } @Override @@ -217,8 +180,6 @@ public String toString() { sb.append(" serviceDesc: ").append(toIndentedString(serviceDesc)).append("\n"); sb.append(" ownerId: ").append(toIndentedString(ownerId)).append("\n"); sb.append(" scope: ").append(toIndentedString(scope)).append("\n"); - sb.append(" createDt: ").append(toIndentedString(createDt)).append("\n"); - sb.append(" updateDt: ").append(toIndentedString(updateDt)).append("\n"); sb.append("}"); return sb.toString(); } @@ -246,8 +207,6 @@ public void readData(ObjectDataInput in) throws IOException { this.serviceDesc = in.readUTF(); this.ownerId = in.readUTF(); this.scope = in.readUTF(); - this.createDt = in.readObject(); - this.updateDt = in.readObject(); } @Override @@ -258,8 +217,6 @@ public void writeData(ObjectDataOutput out) throws IOException { out.writeUTF(this.serviceDesc); out.writeUTF(this.ownerId); out.writeUTF(this.scope); - out.writeObject(this.createDt); - out.writeObject(this.updateDt); } @JsonIgnore diff --git a/cache/src/main/java/com/networknt/oauth/cache/model/ServiceEndpoint.java b/cache/src/main/java/com/networknt/oauth/cache/model/ServiceEndpoint.java new file mode 100644 index 00000000..7f795828 --- /dev/null +++ b/cache/src/main/java/com/networknt/oauth/cache/model/ServiceEndpoint.java @@ -0,0 +1,124 @@ +package com.networknt.oauth.cache.model; +import java.io.IOException; +import java.util.Objects; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.hazelcast.nio.ObjectDataInput; +import com.hazelcast.nio.ObjectDataOutput; +import com.hazelcast.nio.serialization.IdentifiedDataSerializable; + +public class ServiceEndpoint implements IdentifiedDataSerializable { + + + private String operation; + + private String endpoint; + + private String scope; + + + public ServiceEndpoint () { + } + + + + @JsonProperty("operation") + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + + + @JsonProperty("endpoint") + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + + + @JsonProperty("scope") + public String getScope() { + return scope; + } + + public void setScope(String scope) { + this.scope = scope; + } + + + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + ServiceEndpoint ServiceEndpoint = (ServiceEndpoint) o; + + return Objects.equals(operation, ServiceEndpoint.operation) && + Objects.equals(endpoint, ServiceEndpoint.endpoint) && + + Objects.equals(scope, ServiceEndpoint.scope); + } + + @Override + public int hashCode() { + return Objects.hash(operation, endpoint, scope); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("class ServiceEndpoint {\n"); + + sb.append(" operation: ").append(toIndentedString(operation)).append("\n"); + sb.append(" endpoint: ").append(toIndentedString(endpoint)).append("\n"); + sb.append(" scope: ").append(toIndentedString(scope)).append("\n"); + sb.append("}"); + return sb.toString(); + } + + /** + * Convert the given object to string with each line indented by 4 spaces + * (except the first line). + */ + private String toIndentedString(Object o) { + if (o == null) { + return "null"; + } + return o.toString().replace("\n", "\n "); + } + + @Override + public int getFactoryId() { + return ServiceEndpointDataSerializableFactory.ID; + } + + @Override + public int getId() { + return ServiceEndpointDataSerializableFactory.SERVICE_ENDPOINT_TYPE; + } + + @Override + public void writeData(ObjectDataOutput objectDataOutput) throws IOException { + objectDataOutput.writeUTF(this.endpoint); + objectDataOutput.writeUTF(this.operation); + objectDataOutput.writeUTF(this.scope); + } + + @Override + public void readData(ObjectDataInput objectDataInput) throws IOException { + this.endpoint = objectDataInput.readUTF(); + this.operation = objectDataInput.readUTF(); + this.scope = objectDataInput.readUTF(); + } +} diff --git a/cache/src/main/java/com/networknt/oauth/cache/model/ServiceEndpointComparator.java b/cache/src/main/java/com/networknt/oauth/cache/model/ServiceEndpointComparator.java new file mode 100644 index 00000000..f1e292a8 --- /dev/null +++ b/cache/src/main/java/com/networknt/oauth/cache/model/ServiceEndpointComparator.java @@ -0,0 +1,14 @@ +package com.networknt.oauth.cache.model; + +import java.io.Serializable; +import java.util.Comparator; +import java.util.Map; + +public class ServiceEndpointComparator implements Comparator, Serializable { + @Override + public int compare(Map.Entry o1, Map.Entry o2) { + ServiceEndpoint c1 = (ServiceEndpoint) o1.getValue(); + ServiceEndpoint c2 = (ServiceEndpoint) o2.getValue(); + return c1.getEndpoint().compareTo(c2.getEndpoint()); + } +} diff --git a/cache/src/main/java/com/networknt/oauth/cache/model/ServiceEndpointDataSerializableFactory.java b/cache/src/main/java/com/networknt/oauth/cache/model/ServiceEndpointDataSerializableFactory.java new file mode 100644 index 00000000..32c4a1b3 --- /dev/null +++ b/cache/src/main/java/com/networknt/oauth/cache/model/ServiceEndpointDataSerializableFactory.java @@ -0,0 +1,19 @@ +package com.networknt.oauth.cache.model; + +import com.hazelcast.nio.serialization.DataSerializableFactory; +import com.hazelcast.nio.serialization.IdentifiedDataSerializable; + +public class ServiceEndpointDataSerializableFactory implements DataSerializableFactory { + + static final int ID = 5; + static final int SERVICE_ENDPOINT_TYPE = 5; + + @Override + public IdentifiedDataSerializable create(int typeId) { + if (typeId == SERVICE_ENDPOINT_TYPE) { + return new ServiceEndpoint(); + } else { + return null; + } + } +} diff --git a/cache/src/main/resources/logback.xml b/cache/src/main/resources/logback.xml index 6e58aff8..455f137d 100644 --- a/cache/src/main/resources/logback.xml +++ b/cache/src/main/resources/logback.xml @@ -28,7 +28,7 @@ - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n @@ -36,7 +36,7 @@ target/test.log false - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %class{36}:%L %M - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n diff --git a/cache/src/test/java/com/networknt/oauth/cache/CacheStartupHookProviderTest.java b/cache/src/test/java/com/networknt/oauth/cache/CacheStartupHookProviderTest.java index 9d187cd7..7d7ac879 100644 --- a/cache/src/test/java/com/networknt/oauth/cache/CacheStartupHookProviderTest.java +++ b/cache/src/test/java/com/networknt/oauth/cache/CacheStartupHookProviderTest.java @@ -5,6 +5,7 @@ import com.hazelcast.query.SqlPredicate; import com.networknt.oauth.cache.model.Client; import com.networknt.oauth.cache.model.Service; +import com.networknt.oauth.cache.model.ServiceEndpoint; import com.networknt.oauth.cache.model.User; import com.networknt.service.SingletonServiceFactory; import org.h2.tools.RunScript; @@ -18,6 +19,7 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; @@ -89,7 +91,7 @@ public void testServiceCache() { Service service = services.get("AACT0001"); System.out.println("service = " + service); - service.setServiceType(Service.ServiceTypeEnum.fromValue("api")); + service.setServiceType(Service.ServiceTypeEnum.fromValue("swagger")); services.replace("AACT0001", service); @@ -183,4 +185,25 @@ public void testRefreshTokenCache() { } + + @SuppressWarnings("unchecked") + @Test + public void testServiceEndpointCache() { + CacheStartupHookProvider start = new CacheStartupHookProvider(); + start.onStartup(); + + final IMap> serviceEndpoints = CacheStartupHookProvider.hz.getMap("serviceEndpoints"); + + List list = serviceEndpoints.get("AACT0001"); + System.out.println("list size = " + list.size()); + + serviceEndpoints.delete("AACT0001"); + + System.out.println("list size = " + serviceEndpoints.size()); + + CacheShutdownHookProvider shutdown = new CacheShutdownHookProvider(); + shutdown.onShutdown(); + + } + } diff --git a/cache/src/test/resources/create_h2.sql b/cache/src/test/resources/create_h2.sql index db248a09..c763a579 100644 --- a/cache/src/test/resources/create_h2.sql +++ b/cache/src/test/resources/create_h2.sql @@ -1,21 +1,22 @@ -DROP table IF EXISTS users; -DROP table IF EXISTS clients; -DROP table IF EXISTS services; +DROP table IF EXISTS user_profile; +DROP table IF EXISTS client; +DROP table IF EXISTS service; +DROP table IF EXISTS service_endpoint; +DROP table IF EXISTS client_service; +DROP table IF EXISTS audit_log; -create table users ( +create table user_profile ( user_id varchar PRIMARY KEY, user_type varchar, -- admin, customer, employee, partner first_name varchar, last_name varchar, email varchar, - password varchar, - create_dt DATE, - update_dt DATE + password varchar ); -CREATE UNIQUE INDEX email_idx ON users(email); +CREATE UNIQUE INDEX email_idx ON user_profile(email); -create table clients ( +create table client ( client_id VARCHAR PRIMARY KEY, client_secret VARCHAR, client_type VARCHAR, -- public, confidential, trusted @@ -25,26 +26,56 @@ create table clients ( scope VARCHAR, redirect_uri VARCHAR, authenticate_class VARCHAR, - owner_id VARCHAR, - create_dt DATE, - update_dt DATE + owner_id VARCHAR ); -create table services ( +create table service ( service_id VARCHAR PRIMARY KEY, - service_type VARCHAR, -- api, ms + service_type VARCHAR, -- swagger, openapi, graphql, hybrid service_name VARCHAR, service_desc VARCHAR, scope VARCHAR, - owner_id VARCHAR, - create_dt DATE, - update_dt DATE + owner_id VARCHAR ); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +create table service_endpoint ( + service_id VARCHAR, + endpoint VARCHAR, -- different framework will have different endpoint format. + operation VARCHAR, + scope VARCHAR, + PRIMARY KEY (service_id, endpoint), + FOREIGN KEY (service_id) REFERENCES service(service_id) +); + +create table client_service ( + client_id VARCHAR NOT NULL, + service_id VARCHAR NOT NULL, + endpoint VARCHAR NOT NULL, -- different framework will have different endpoint format. + PRIMARY KEY (client_id, service_id, endpoint), + FOREIGN KEY (service_id, endpoint) REFERENCES service_endpoint(service_id, endpoint), + FOREIGN KEY (client_id) REFERENCES client(client_id) +); + +create table audit_log ( + log_id VARCHAR NOT NULL, + action_dt DATE, + service_id VARCHAR NOT NULL, + path VARCHAR NOT NULL, + method VARCHAR NOT NULL, + request_header VARCHAR NOT NULL, + request_body VARCHAR, + response_code INT, + response_header VARCHAR NOT NULL, + response_body VARCHAR, + PRIMARY KEY (log_id) +); + + +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); -INSERT INTO services (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); +INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'openapi', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); +INSERT INTO service_endpoint(service_id, endpoint, operation, scope) VALUES ('AACT0001', '/v1/data@get', 'retrieveData', 'data.r'); \ No newline at end of file diff --git a/client/.gitignore b/client/.gitignore index 3901d721..7883fdc0 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -13,6 +13,7 @@ dist/ *.tmp *.zip *.bak +dependency-reduced-pom.xml # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* diff --git a/client/docker/Dockerfile b/client/Dockerfile similarity index 100% rename from client/docker/Dockerfile rename to client/Dockerfile diff --git a/client/build.sh b/client/build.sh index b5d44c2b..1b59e8b3 100755 --- a/client/build.sh +++ b/client/build.sh @@ -42,7 +42,7 @@ cleanup() { publish() { echo "Building Docker image with version $VERSION" - docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./docker/Dockerfile . --no-cache=true + docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./Dockerfile . --no-cache=true docker build -t $IMAGE_NAME:$VERSION-redhat -f ./docker/Dockerfile-Redhat . --no-cache=true echo "Images built with version $VERSION" echo "Pushing image to DockerHub" diff --git a/client/docker/Dockerfile-Redhat b/client/docker/Dockerfile-Redhat index c883b8ac..fb17c7cb 100644 --- a/client/docker/Dockerfile-Redhat +++ b/client/docker/Dockerfile-Redhat @@ -2,27 +2,30 @@ FROM registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift USER root -ENV APP_DIR=/app \ +ENV APP_DIR=app \ GROUP_NAME=networknt \ GROUP_ID=1000 \ USER_NAME=networknt \ USER_UID=1000 RUN groupadd -g ${GROUP_ID} -r ${GROUP_NAME} && \ - useradd -u ${USER_UID} -g ${GROUP_NAME} -d "${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} + useradd -u ${USER_UID} -g ${GROUP_NAME} -d "/${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} # Add the jar file into the container at /app -ADD target/oauth2-client.jar ${APP_DIR}/server.jar +ADD target/oauth2-client.jar ./${APP_DIR}/server.jar # change permissions of app directory -RUN chown -R ${USER_NAME}:${GROUP_NAME} "${APP_DIR}" +RUN mkdir -p ./${APP_DIR}/config && \ + chown -R ${USER_NAME}:0 "./${APP_DIR}/config" && \ + find "./${APP_DIR}/config" -type d -exec chmod 750 {} \; && \ + find "./${APP_DIR}/config" -type f -exec chmod 640 {} \; # Port available to the world outside of this container -EXPOSE 6884 +EXPOSE 8080 USER ${USER_UID} # Set the working directory to /app -WORKDIR ${APP_DIR} +WORKDIR ./${APP_DIR} -CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] +CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] \ No newline at end of file diff --git a/client/src/main/java/com/networknt/oauth/client/PathHandlerProvider.java b/client/src/main/java/com/networknt/oauth/client/PathHandlerProvider.java index 471a0b2a..c6a4badf 100644 --- a/client/src/main/java/com/networknt/oauth/client/PathHandlerProvider.java +++ b/client/src/main/java/com/networknt/oauth/client/PathHandlerProvider.java @@ -1,26 +1,45 @@ + package com.networknt.oauth.client; -import com.networknt.health.HealthGetHandler; -import com.networknt.info.ServerInfoGetHandler; -import com.networknt.oauth.client.handler.*; +import com.networknt.config.Config; import com.networknt.server.HandlerProvider; import io.undertow.Handlers; import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; import io.undertow.util.Methods; +import com.networknt.info.ServerInfoGetHandler; +import com.networknt.health.HealthGetHandler; +import com.networknt.oauth.client.handler.*; public class PathHandlerProvider implements HandlerProvider { @Override public HttpHandler getHandler() { - HttpHandler handler = Handlers.routing() + return Handlers.routing() + + .add(Methods.DELETE, "/oauth2/client/{clientId}/service", new Oauth2ClientClientIdServiceDeleteHandler()) + + .add(Methods.GET, "/oauth2/client/{clientId}/service", new Oauth2ClientClientIdServiceGetHandler()) + .add(Methods.GET, "/health", new HealthGetHandler()) - .add(Methods.GET, "/server/info", new ServerInfoGetHandler()) - .add(Methods.DELETE, "/oauth2/client/{clientId}", new Oauth2ClientClientIdDeleteHandler()) - .add(Methods.GET, "/oauth2/client/{clientId}", new Oauth2ClientClientIdGetHandler()) - .add(Methods.GET, "/oauth2/client", new Oauth2ClientGetHandler()) + .add(Methods.POST, "/oauth2/client", new Oauth2ClientPostHandler()) + .add(Methods.PUT, "/oauth2/client", new Oauth2ClientPutHandler()) + + .add(Methods.GET, "/oauth2/client", new Oauth2ClientGetHandler()) + + .add(Methods.DELETE, "/oauth2/client/{clientId}", new Oauth2ClientClientIdDeleteHandler()) + + .add(Methods.GET, "/oauth2/client/{clientId}", new Oauth2ClientClientIdGetHandler()) + + .add(Methods.POST, "/oauth2/client/{clientId}/service/{serviceId}", new Oauth2ClientClientIdServiceServiceIdPostHandler()) + + .add(Methods.DELETE, "/oauth2/client/{clientId}/service/{serviceId}", new Oauth2ClientClientIdServiceServiceIdDeleteHandler()) + + .add(Methods.GET, "/oauth2/client/{clientId}/service/{serviceId}", new Oauth2ClientClientIdServiceServiceIdGetHandler()) + + .add(Methods.GET, "/server/info", new ServerInfoGetHandler()) + ; - return handler; } } - diff --git a/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceDeleteHandler.java b/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceDeleteHandler.java new file mode 100644 index 00000000..81de86de --- /dev/null +++ b/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceDeleteHandler.java @@ -0,0 +1,94 @@ + +package com.networknt.oauth.client.handler; + +import com.hazelcast.core.IMap; +import com.networknt.config.Config; +import com.networknt.oauth.cache.CacheStartupHookProvider; +import com.networknt.oauth.cache.model.Client; +import com.networknt.service.SingletonServiceFactory; +import com.networknt.status.Status; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.StringJoiner; +import java.util.stream.Collectors; + +/** + * delete all services and endpoints for a client. It is a very dangerous API + * and be careful. It is supposed to be used only when a client is retired. + * + * @author Steve Hu + */ +public class Oauth2ClientClientIdServiceDeleteHandler implements HttpHandler { + private static final Logger logger = LoggerFactory.getLogger(Oauth2ClientClientIdServiceServiceIdGetHandler.class); + private static final DataSource ds = (DataSource) SingletonServiceFactory.getBean(DataSource.class); + private static final String delete = "DELETE FROM client_service WHERE client_id = ?"; + private static final String scope = "SELECT DISTINCT scope FROM client_service s, service_endpoint e WHERE s.service_id = e.service_id AND s.endpoint = e.endpoint AND client_id = ?"; + private static final String CLIENT_NOT_FOUND = "ERR12014"; + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + // ensure that both clientId and serviceId exist. + String clientId = exchange.getQueryParameters().get("clientId").getFirst(); + IMap clients = CacheStartupHookProvider.hz.getMap("clients"); + Client client = clients.get(clientId); + if(client == null) { + Status status = new Status(CLIENT_NOT_FOUND, clientId); + exchange.setStatusCode(status.getStatusCode()); + exchange.getResponseSender().send(status.toString()); + return; + } + + Map result = new HashMap<>(); + try (Connection connection = ds.getConnection()) { + connection.setAutoCommit(false); + try (PreparedStatement stmt = connection.prepareStatement(delete)) { + stmt.setString(1, clientId); + stmt.executeUpdate(); + } catch (SQLException e) { + logger.error("Exception:", e); + connection.rollback(); + throw new RuntimeException(e); + } + + StringJoiner joiner = new StringJoiner(" "); + try (PreparedStatement stmt = connection.prepareStatement(scope)) { + stmt.setString(1, clientId); + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + joiner.add(rs.getString("scope")); + } + } + } + + String s = Arrays.stream(joiner.toString().split(" ")) + .distinct() + .filter(st -> !st.isEmpty()) + .collect(Collectors.joining(" ")); + + result.put("old_scope", client.getScope()); + // update client scope in cache and db + client.setScope(s); + result.put("new_scope", s); + + connection.commit(); + } catch (SQLException e) { + logger.error("Exception:", e); + throw new RuntimeException(e); + } + exchange.getResponseHeaders().add(new HttpString("Content-Type"), "application/json"); + exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(result)); + + } +} diff --git a/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceGetHandler.java b/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceGetHandler.java new file mode 100644 index 00000000..bd11b86e --- /dev/null +++ b/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceGetHandler.java @@ -0,0 +1,74 @@ + +package com.networknt.oauth.client.handler; + +import com.hazelcast.core.IMap; +import com.networknt.config.Config; +import com.networknt.oauth.cache.CacheStartupHookProvider; +import com.networknt.oauth.cache.model.Client; +import com.networknt.service.SingletonServiceFactory; +import com.networknt.status.Status; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * get all the linked services and endpoints for a client + * + * @author Steve Hu + */ +public class Oauth2ClientClientIdServiceGetHandler implements HttpHandler { + private static final Logger logger = LoggerFactory.getLogger(Oauth2ClientClientIdServiceGetHandler.class); + private static final DataSource ds = (DataSource) SingletonServiceFactory.getBean(DataSource.class); + private static final String select = "SELECT * FROM client_service WHERE client_id = ? ORDER BY service_id"; + private static final String CLIENT_NOT_FOUND = "ERR12014"; + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + // ensure that clientId exists. + String clientId = exchange.getQueryParameters().get("clientId").getFirst(); + IMap clients = CacheStartupHookProvider.hz.getMap("clients"); + Client client = clients.get(clientId); + if(client == null) { + Status status = new Status(CLIENT_NOT_FOUND, clientId); + exchange.setStatusCode(status.getStatusCode()); + exchange.getResponseSender().send(status.toString()); + return; + } + + Map> serviceEndpoints = new HashMap<>(); + + try (Connection connection = ds.getConnection(); PreparedStatement stmt = connection.prepareStatement(select)) { + stmt.setString(1, clientId); + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + String serviceId = rs.getString("service_id"); + String endpoint = rs.getString("endpoint"); + List endpoints = serviceEndpoints.get(serviceId); + if(endpoints == null) { + endpoints = new ArrayList<>(); + serviceEndpoints.put(serviceId, endpoints); + } + endpoints.add(endpoint); + } + } + } catch (SQLException e) { + logger.error("Exception:", e); + throw new RuntimeException(e); + } + + exchange.getResponseHeaders().add(new HttpString("Content-Type"), "application/json"); + exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(serviceEndpoints)); + } +} diff --git a/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdDeleteHandler.java b/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdDeleteHandler.java new file mode 100644 index 00000000..4ca26a5c --- /dev/null +++ b/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdDeleteHandler.java @@ -0,0 +1,103 @@ + +package com.networknt.oauth.client.handler; + +import com.hazelcast.core.IMap; +import com.networknt.config.Config; +import com.networknt.oauth.cache.CacheStartupHookProvider; +import com.networknt.oauth.cache.model.Client; +import com.networknt.oauth.cache.model.Service; +import com.networknt.service.SingletonServiceFactory; +import com.networknt.status.Status; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.StringJoiner; +import java.util.stream.Collectors; + +/** + * delete endpoints for a service that is linked to a client. + * + * @author Steve Hu + */ +public class Oauth2ClientClientIdServiceServiceIdDeleteHandler implements HttpHandler { + private static final Logger logger = LoggerFactory.getLogger(Oauth2ClientClientIdServiceServiceIdGetHandler.class); + private static final DataSource ds = (DataSource) SingletonServiceFactory.getBean(DataSource.class); + private static final String delete = "DELETE FROM client_service WHERE client_id = ? AND service_id = ?"; + private static final String scope = "SELECT DISTINCT scope FROM client_service s, service_endpoint e WHERE s.service_id = e.service_id AND s.endpoint = e.endpoint AND client_id = ?"; + private static final String CLIENT_NOT_FOUND = "ERR12014"; + private static final String SERVICE_NOT_FOUND = "ERR12015"; + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + // ensure that both clientId and serviceId exist. + String clientId = exchange.getQueryParameters().get("clientId").getFirst(); + IMap clients = CacheStartupHookProvider.hz.getMap("clients"); + Client client = clients.get(clientId); + if(client == null) { + Status status = new Status(CLIENT_NOT_FOUND, clientId); + exchange.setStatusCode(status.getStatusCode()); + exchange.getResponseSender().send(status.toString()); + return; + } + + String serviceId = exchange.getQueryParameters().get("serviceId").getFirst(); + IMap services = CacheStartupHookProvider.hz.getMap("services"); + if(services.get(serviceId) == null) { + Status status = new Status(SERVICE_NOT_FOUND, serviceId); + exchange.setStatusCode(status.getStatusCode()); + exchange.getResponseSender().send(status.toString()); + return; + } + + Map result = new HashMap<>(); + try (Connection connection = ds.getConnection()) { + connection.setAutoCommit(false); + try (PreparedStatement stmt = connection.prepareStatement(delete)) { + stmt.setString(1, clientId); + stmt.setString(2, serviceId); + stmt.executeUpdate(); + } catch (SQLException e) { + logger.error("Exception:", e); + connection.rollback(); + throw new RuntimeException(e); + } + + StringJoiner joiner = new StringJoiner(" "); + try (PreparedStatement stmt = connection.prepareStatement(scope)) { + stmt.setString(1, clientId); + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + joiner.add(rs.getString("scope")); + } + } + } + + String s = Arrays.stream(joiner.toString().split(" ")) + .distinct() + .filter(st -> !st.isEmpty()) + .collect(Collectors.joining(" ")); + + result.put("old_scope", client.getScope()); + client.setScope(s); + result.put("new_scope", s); + + connection.commit(); + } catch (SQLException e) { + logger.error("Exception:", e); + throw new RuntimeException(e); + } + exchange.getResponseHeaders().add(new HttpString("Content-Type"), "application/json"); + exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(result)); + } +} diff --git a/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdGetHandler.java b/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdGetHandler.java new file mode 100644 index 00000000..bc8385ed --- /dev/null +++ b/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdGetHandler.java @@ -0,0 +1,78 @@ + +package com.networknt.oauth.client.handler; + +import com.hazelcast.core.IMap; +import com.networknt.config.Config; +import com.networknt.oauth.cache.CacheStartupHookProvider; +import com.networknt.oauth.cache.model.Client; +import com.networknt.oauth.cache.model.Service; +import com.networknt.service.SingletonServiceFactory; +import com.networknt.status.Status; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * get a list of endpoints of a service linked to a client + * + * @author Steve Hu + */ +public class Oauth2ClientClientIdServiceServiceIdGetHandler implements HttpHandler { + private static final Logger logger = LoggerFactory.getLogger(Oauth2ClientClientIdServiceServiceIdGetHandler.class); + private static final DataSource ds = (DataSource) SingletonServiceFactory.getBean(DataSource.class); + private static final String select = "SELECT * FROM client_service WHERE client_id = ? AND service_id = ?"; + private static final String CLIENT_NOT_FOUND = "ERR12014"; + private static final String SERVICE_NOT_FOUND = "ERR12015"; + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + // ensure that both clientId and serviceId exist. + String clientId = exchange.getQueryParameters().get("clientId").getFirst(); + IMap clients = CacheStartupHookProvider.hz.getMap("clients"); + Client client = clients.get(clientId); + if(client == null) { + Status status = new Status(CLIENT_NOT_FOUND, clientId); + exchange.setStatusCode(status.getStatusCode()); + exchange.getResponseSender().send(status.toString()); + return; + } + + String serviceId = exchange.getQueryParameters().get("serviceId").getFirst(); + IMap services = CacheStartupHookProvider.hz.getMap("services"); + if(services.get(serviceId) == null) { + Status status = new Status(SERVICE_NOT_FOUND, serviceId); + exchange.setStatusCode(status.getStatusCode()); + exchange.getResponseSender().send(status.toString()); + return; + } + + List endpoints = new ArrayList<>(); + try (Connection connection = ds.getConnection(); PreparedStatement stmt = connection.prepareStatement(select)) { + stmt.setString(1, clientId); + stmt.setString(2, serviceId); + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + endpoints.add(rs.getString("endpoint")); + } + } + } catch (SQLException e) { + logger.error("Exception:", e); + throw new RuntimeException(e); + } + + exchange.getResponseHeaders().add(new HttpString("Content-Type"), "application/json"); + exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(endpoints)); + } +} diff --git a/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdPostHandler.java b/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdPostHandler.java new file mode 100644 index 00000000..10d463e8 --- /dev/null +++ b/client/src/main/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdPostHandler.java @@ -0,0 +1,121 @@ + +package com.networknt.oauth.client.handler; + +import com.hazelcast.core.IMap; +import com.networknt.body.BodyHandler; +import com.networknt.config.Config; +import com.networknt.oauth.cache.CacheStartupHookProvider; +import com.networknt.oauth.cache.model.Client; +import com.networknt.oauth.cache.model.Service; +import com.networknt.oauth.cache.model.ServiceEndpoint; +import com.networknt.service.SingletonServiceFactory; +import com.networknt.status.Status; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.*; +import java.util.stream.Collectors; + +/** + * Add one or more endpoints of a service to a client + * + * @author Steve Hu + */ +public class Oauth2ClientClientIdServiceServiceIdPostHandler implements HttpHandler { + private static final Logger logger = LoggerFactory.getLogger(Oauth2ClientClientIdServiceServiceIdPostHandler.class); + private static final DataSource ds = (DataSource) SingletonServiceFactory.getBean(DataSource.class); + private static final String insert = "INSERT INTO client_service (client_id, service_id, endpoint) VALUES (?, ?, ?)"; + private static final String delete = "DELETE FROM client_service WHERE client_id = ? AND service_id = ?"; + private static final String scope = "SELECT DISTINCT scope FROM client_service s, service_endpoint e WHERE s.service_id = e.service_id AND s.endpoint = e.endpoint AND client_id = ?"; + private static final String CLIENT_NOT_FOUND = "ERR12014"; + private static final String SERVICE_NOT_FOUND = "ERR12015"; + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + // ensure that both clientId and serviceId exist. + String clientId = exchange.getQueryParameters().get("clientId").getFirst(); + IMap clients = CacheStartupHookProvider.hz.getMap("clients"); + Client client = clients.get(clientId); + if(client == null) { + Status status = new Status(CLIENT_NOT_FOUND, clientId); + exchange.setStatusCode(status.getStatusCode()); + exchange.getResponseSender().send(status.toString()); + if(logger.isDebugEnabled()) logger.debug("Could not find clientId " + clientId); + return; + } + + String serviceId = exchange.getQueryParameters().get("serviceId").getFirst(); + IMap services = CacheStartupHookProvider.hz.getMap("services"); + if(services.get(serviceId) == null) { + Status status = new Status(SERVICE_NOT_FOUND, serviceId); + exchange.setStatusCode(status.getStatusCode()); + exchange.getResponseSender().send(status.toString()); + if(logger.isDebugEnabled()) logger.debug("Could not find serviceId " + serviceId); + return; + } + List endpoints = (List)exchange.getAttachment(BodyHandler.REQUEST_BODY); + if(logger.isDebugEnabled()) logger.debug("Create endpoints {} for clientId {}, serviceId {}", endpoints, clientId, serviceId); + Map result = new HashMap<>(); + if(endpoints != null && endpoints.size() > 0) { + try (Connection connection = ds.getConnection()) { + connection.setAutoCommit(false); + // remove existing endpoints and add new ones. + try (PreparedStatement stmt = connection.prepareStatement(delete)) { + stmt.setString(1, clientId); + stmt.setString(2, serviceId); + stmt.executeUpdate(); + } catch (SQLException e) { + logger.error("Exception:", e); + connection.rollback(); + throw new RuntimeException(e); + } + try (PreparedStatement stmt = connection.prepareStatement(insert)) { + for (String endpoint : endpoints) { + stmt.setString(1, clientId); + stmt.setString(2, serviceId); + stmt.setString(3, endpoint); + stmt.addBatch(); + } + stmt.executeBatch(); + } catch (SQLException e) { + logger.error("Exception:", e); + connection.rollback(); + throw new RuntimeException(e); + } + + StringJoiner joiner = new StringJoiner(" "); + try (PreparedStatement stmt = connection.prepareStatement(scope)) { + stmt.setString(1, clientId); + try (ResultSet rs = stmt.executeQuery()) { + while (rs.next()) { + joiner.add(rs.getString("scope")); + } + } + } + + String s = Arrays.stream(joiner.toString().split(" ")) + .distinct() + .filter(st -> !st.isEmpty()) + .collect(Collectors.joining(" ")); + // update client scope in cache and db + result.put("old_scope", client.getScope()); + client.setScope(s); + result.put("new_scope", s); + connection.commit(); + } catch (SQLException e) { + logger.error("SQLException:", e); + throw new RuntimeException(e); + } + } + exchange.getResponseHeaders().add(new HttpString("Content-Type"), "application/json"); + exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(result)); + } +} diff --git a/client/src/main/resources/logback.xml b/client/src/main/resources/logback.xml index 6e58aff8..49df2a1c 100644 --- a/client/src/main/resources/logback.xml +++ b/client/src/main/resources/logback.xml @@ -28,7 +28,7 @@ - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n @@ -36,7 +36,7 @@ target/test.log false - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %class{36}:%L %M - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n @@ -44,7 +44,7 @@ target/audit.log - %-5level [%thread] %date{ISO8601} %F:%L - %msg%n + %-5level [%thread] %date{ISO8601} %X{sId} %X{cId} %F:%L - %msg%n true diff --git a/client/src/test/java/com/networknt/oauth/client/handler/HealthGetHandlerTest.java b/client/src/test/java/com/networknt/oauth/client/handler/HealthGetHandlerTest.java new file mode 100644 index 00000000..2e22d273 --- /dev/null +++ b/client/src/test/java/com/networknt/oauth/client/handler/HealthGetHandlerTest.java @@ -0,0 +1,68 @@ + +package com.networknt.oauth.client.handler; + +import com.networknt.client.Http2Client; +import com.networknt.exception.ApiException; +import com.networknt.exception.ClientException; +import io.undertow.UndertowOptions; +import io.undertow.client.ClientConnection; +import io.undertow.client.ClientRequest; +import io.undertow.client.ClientResponse; +import io.undertow.util.Headers; +import io.undertow.util.Methods; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import java.io.IOException; + + +public class HealthGetHandlerTest { + @ClassRule + public static TestServer server = TestServer.getInstance(); + + static final Logger logger = LoggerFactory.getLogger(HealthGetHandlerTest.class); + static final boolean enableHttp2 = server.getServerConfig().isEnableHttp2(); + static final boolean enableHttps = server.getServerConfig().isEnableHttps(); + static final int httpPort = server.getServerConfig().getHttpPort(); + static final int httpsPort = server.getServerConfig().getHttpsPort(); + static final String url = enableHttp2 || enableHttps ? "https://localhost:" + httpsPort : "http://localhost:" + httpPort; + + @Test + public void testHealthGetHandlerTest() throws ClientException, ApiException { + /* + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/health").setMethod(Methods.GET); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(200, statusCode); + Assert.assertNotNull(body); + */ + } +} diff --git a/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdDeleteHandlerTest.java b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdDeleteHandlerTest.java index 84eada76..cf0c05f4 100644 --- a/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdDeleteHandlerTest.java +++ b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdDeleteHandlerTest.java @@ -43,7 +43,7 @@ public void testOauth2ClientClientIdDeleteHandler() throws ClientException, ApiE } final AtomicReference reference = new AtomicReference<>(); try { - ClientRequest request = new ClientRequest().setMethod(Methods.DELETE).setPath("/oauth2/client/59f347a0-c92d-11e6-9d9d-cec0c932ce01"); + ClientRequest request = new ClientRequest().setMethod(Methods.DELETE).setPath("/oauth2/client/f7d42348-c647-4efb-a52d-4c5787421e72"); connection.sendRequest(request, client.createClientCallback(reference, latch)); latch.await(); } catch (Exception e) { diff --git a/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceDeleteHandlerTest.java b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceDeleteHandlerTest.java new file mode 100644 index 00000000..f3768ed9 --- /dev/null +++ b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceDeleteHandlerTest.java @@ -0,0 +1,106 @@ + +package com.networknt.oauth.client.handler; + +import com.networknt.client.Http2Client; +import com.networknt.config.Config; +import com.networknt.exception.ApiException; +import com.networknt.exception.ClientException; +import com.networknt.status.Status; +import io.undertow.UndertowOptions; +import io.undertow.client.ClientConnection; +import io.undertow.client.ClientRequest; +import io.undertow.client.ClientResponse; +import io.undertow.util.Headers; +import io.undertow.util.Methods; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import java.io.IOException; + + +public class Oauth2ClientClientIdServiceDeleteHandlerTest { + @ClassRule + public static TestServer server = TestServer.getInstance(); + + static final Logger logger = LoggerFactory.getLogger(Oauth2ClientClientIdServiceDeleteHandlerTest.class); + static final boolean enableHttp2 = server.getServerConfig().isEnableHttp2(); + static final boolean enableHttps = server.getServerConfig().isEnableHttps(); + static final int httpPort = server.getServerConfig().getHttpPort(); + static final int httpsPort = server.getServerConfig().getHttpsPort(); + static final String url = enableHttp2 || enableHttps ? "https://localhost:" + httpsPort : "http://localhost:" + httpPort; + + @Test + public void testOauth2ClientClientIdServiceDeleteHandlerTest() throws ClientException, ApiException { + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/client/59f347a0-c92d-11e6-9d9d-cec0c932ce01/service").setMethod(Methods.DELETE); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(200, statusCode); + Assert.assertNotNull(body); + Assert.assertTrue(body.indexOf("new_scope") > 0); + Assert.assertTrue(body.indexOf("old_scope") > 0); + + } + + @Test + public void testClientNotFound() throws ClientException, IOException { + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/client/fake/service").setMethod(Methods.DELETE); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(404, statusCode); + if(statusCode == 404) { + Status status = Config.getInstance().getMapper().readValue(body, Status.class); + Assert.assertNotNull(status); + Assert.assertEquals("ERR12014", status.getCode()); + Assert.assertEquals("CLIENT_NOT_FOUND", status.getMessage()); + } + } + +} diff --git a/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceGetHandlerTest.java b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceGetHandlerTest.java new file mode 100644 index 00000000..9698ff34 --- /dev/null +++ b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceGetHandlerTest.java @@ -0,0 +1,107 @@ + +package com.networknt.oauth.client.handler; + +import com.networknt.client.Http2Client; +import com.networknt.config.Config; +import com.networknt.exception.ApiException; +import com.networknt.exception.ClientException; +import com.networknt.status.Status; +import io.undertow.UndertowOptions; +import io.undertow.client.ClientConnection; +import io.undertow.client.ClientRequest; +import io.undertow.client.ClientResponse; +import io.undertow.util.Headers; +import io.undertow.util.Methods; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import java.io.IOException; + + +public class Oauth2ClientClientIdServiceGetHandlerTest { + @ClassRule + public static TestServer server = TestServer.getInstance(); + + static final Logger logger = LoggerFactory.getLogger(Oauth2ClientClientIdServiceGetHandlerTest.class); + static final boolean enableHttp2 = server.getServerConfig().isEnableHttp2(); + static final boolean enableHttps = server.getServerConfig().isEnableHttps(); + static final int httpPort = server.getServerConfig().getHttpPort(); + static final int httpsPort = server.getServerConfig().getHttpsPort(); + static final String url = enableHttp2 || enableHttps ? "https://localhost:" + httpsPort : "http://localhost:" + httpPort; + + @Test + public void testOauth2ClientClientIdServiceGetHandlerTest() throws ClientException, ApiException { + + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/client/59f347a0-c92d-11e6-9d9d-cec0c932ce01/service").setMethod(Methods.GET); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(200, statusCode); + Assert.assertNotNull(body); + + } + + @Test + public void testClientNotFound() throws ClientException, IOException { + + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/client/fake/service").setMethod(Methods.GET); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(404, statusCode); + if(statusCode == 404) { + Status status = Config.getInstance().getMapper().readValue(body, Status.class); + Assert.assertNotNull(status); + Assert.assertEquals("ERR12014", status.getCode()); + Assert.assertEquals("CLIENT_NOT_FOUND", status.getMessage()); + } + + } + +} diff --git a/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdDeleteHandlerTest.java b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdDeleteHandlerTest.java new file mode 100644 index 00000000..3424abf5 --- /dev/null +++ b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdDeleteHandlerTest.java @@ -0,0 +1,142 @@ + +package com.networknt.oauth.client.handler; + +import com.networknt.client.Http2Client; +import com.networknt.config.Config; +import com.networknt.exception.ApiException; +import com.networknt.exception.ClientException; +import com.networknt.status.Status; +import io.undertow.UndertowOptions; +import io.undertow.client.ClientConnection; +import io.undertow.client.ClientRequest; +import io.undertow.client.ClientResponse; +import io.undertow.util.Headers; +import io.undertow.util.Methods; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import java.io.IOException; + + +public class Oauth2ClientClientIdServiceServiceIdDeleteHandlerTest { + @ClassRule + public static TestServer server = TestServer.getInstance(); + + static final Logger logger = LoggerFactory.getLogger(Oauth2ClientClientIdServiceServiceIdDeleteHandlerTest.class); + static final boolean enableHttp2 = server.getServerConfig().isEnableHttp2(); + static final boolean enableHttps = server.getServerConfig().isEnableHttps(); + static final int httpPort = server.getServerConfig().getHttpPort(); + static final int httpsPort = server.getServerConfig().getHttpsPort(); + static final String url = enableHttp2 || enableHttps ? "https://localhost:" + httpsPort : "http://localhost:" + httpPort; + + @Test + public void testOauth2ClientClientIdServiceServiceIdDeleteHandlerTest() throws ClientException, ApiException { + + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/client/f7d42348-c647-4efb-a52d-4c5787421e72/service/AACT0001").setMethod(Methods.DELETE); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(200, statusCode); + Assert.assertNotNull(body); + Assert.assertTrue(body.indexOf("new_scope") > 0); + Assert.assertTrue(body.indexOf("old_scope") > 0); + } + + @Test + public void testClientNotFound() throws ClientException, IOException { + + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/client/fake/service/AACT0001").setMethod(Methods.DELETE); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(404, statusCode); + if(statusCode == 404) { + Status status = Config.getInstance().getMapper().readValue(body, Status.class); + Assert.assertNotNull(status); + Assert.assertEquals("ERR12014", status.getCode()); + Assert.assertEquals("CLIENT_NOT_FOUND", status.getMessage()); + } + } + + @Test + public void testServiceNotFound() throws ClientException, IOException { + + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/client/f7d42348-c647-4efb-a52d-4c5787421e72/service/fake").setMethod(Methods.DELETE); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(404, statusCode); + if(statusCode == 404) { + Status status = Config.getInstance().getMapper().readValue(body, Status.class); + Assert.assertNotNull(status); + Assert.assertEquals("ERR12015", status.getCode()); + Assert.assertEquals("SERVICE_NOT_FOUND", status.getMessage()); + } + } + +} diff --git a/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdGetHandlerTest.java b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdGetHandlerTest.java new file mode 100644 index 00000000..10001d82 --- /dev/null +++ b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdGetHandlerTest.java @@ -0,0 +1,137 @@ + +package com.networknt.oauth.client.handler; + +import com.networknt.client.Http2Client; +import com.networknt.config.Config; +import com.networknt.exception.ApiException; +import com.networknt.exception.ClientException; +import com.networknt.status.Status; +import io.undertow.UndertowOptions; +import io.undertow.client.ClientConnection; +import io.undertow.client.ClientRequest; +import io.undertow.client.ClientResponse; +import io.undertow.util.Headers; +import io.undertow.util.Methods; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import java.io.IOException; + + +public class Oauth2ClientClientIdServiceServiceIdGetHandlerTest { + @ClassRule + public static TestServer server = TestServer.getInstance(); + + static final Logger logger = LoggerFactory.getLogger(Oauth2ClientClientIdServiceServiceIdGetHandlerTest.class); + static final boolean enableHttp2 = server.getServerConfig().isEnableHttp2(); + static final boolean enableHttps = server.getServerConfig().isEnableHttps(); + static final int httpPort = server.getServerConfig().getHttpPort(); + static final int httpsPort = server.getServerConfig().getHttpsPort(); + static final String url = enableHttp2 || enableHttps ? "https://localhost:" + httpsPort : "http://localhost:" + httpPort; + + @Test + public void testOauth2ClientClientIdServiceServiceIdGetHandlerTest() throws ClientException, ApiException { + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/client/59f347a0-c92d-11e6-9d9d-cec0c932ce01/service/AACT0001").setMethod(Methods.GET); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(200, statusCode); + Assert.assertNotNull(body); + } + + @Test + public void testClientNotFound() throws ClientException, IOException { + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/client/fake/service/AACT0001").setMethod(Methods.GET); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(404, statusCode); + if(statusCode == 404) { + Status status = Config.getInstance().getMapper().readValue(body, Status.class); + Assert.assertNotNull(status); + Assert.assertEquals("ERR12014", status.getCode()); + Assert.assertEquals("CLIENT_NOT_FOUND", status.getMessage()); + } + } + + @Test + public void testServiceNotFound() throws ClientException, IOException { + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/client/f7d42348-c647-4efb-a52d-4c5787421e72/service/fake").setMethod(Methods.GET); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(404, statusCode); + if(statusCode == 404) { + Status status = Config.getInstance().getMapper().readValue(body, Status.class); + Assert.assertNotNull(status); + Assert.assertEquals("ERR12015", status.getCode()); + Assert.assertEquals("SERVICE_NOT_FOUND", status.getMessage()); + } + } + +} diff --git a/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdPostHandlerTest.java b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdPostHandlerTest.java new file mode 100644 index 00000000..94ce4397 --- /dev/null +++ b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientClientIdServiceServiceIdPostHandlerTest.java @@ -0,0 +1,158 @@ + +package com.networknt.oauth.client.handler; + +import com.networknt.client.Http2Client; +import com.networknt.config.Config; +import com.networknt.exception.ApiException; +import com.networknt.exception.ClientException; +import com.networknt.status.Status; +import io.undertow.UndertowOptions; +import io.undertow.client.ClientConnection; +import io.undertow.client.ClientRequest; +import io.undertow.client.ClientResponse; +import io.undertow.util.Headers; +import io.undertow.util.Methods; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import java.io.IOException; + + +public class Oauth2ClientClientIdServiceServiceIdPostHandlerTest { + private static final Logger logger = LoggerFactory.getLogger(Oauth2ClientClientIdServiceServiceIdPostHandlerTest.class); + + @ClassRule + public static TestServer server = TestServer.getInstance(); + static final boolean enableHttp2 = server.getServerConfig().isEnableHttp2(); + static final boolean enableHttps = server.getServerConfig().isEnableHttps(); + static final int httpPort = server.getServerConfig().getHttpPort(); + static final int httpsPort = server.getServerConfig().getHttpsPort(); + static final String url = enableHttp2 || enableHttps ? "https://localhost:" + httpsPort : "http://localhost:" + httpPort; + + @Test + public void testOauth2ClientClientIdServiceServiceIdPostHandlerTest() throws ClientException, ApiException { + logger.debug("Successful test"); + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + String requestBody = "[\"/v1/data@post\",\"/v1/data@put\",\"/v1/data@get\",\"/v1/data@delete\"]"; + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/client/59f347a0-c92d-11e6-9d9d-cec0c932ce01/service/AACT0001").setMethod(Methods.POST); + + request.getRequestHeaders().put(Headers.CONTENT_TYPE, "application/json"); + request.getRequestHeaders().put(Headers.TRANSFER_ENCODING, "chunked"); + connection.sendRequest(request, client.createClientCallback(reference, latch, requestBody)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + logger.debug("statusCode = " + statusCode + " body = " + body); + System.out.println("********************statusCode = " + statusCode + " body = " + body); + Assert.assertEquals(200, statusCode); + Assert.assertNotNull(body); + Assert.assertTrue(body.indexOf("new_scope") > 0); + Assert.assertTrue(body.indexOf("old_scope") > 0); + } + + + @Test + public void testClientNotFound() throws ClientException, IOException { + logger.debug("Client not found test"); + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + String requestBody = "[\"/v1/data@post\",\"/v1/data@put\",\"/v1/data@get\",\"/v1/data@delete\"]"; + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/client/fake/service/AACT0001").setMethod(Methods.POST); + + request.getRequestHeaders().put(Headers.CONTENT_TYPE, "application/json"); + request.getRequestHeaders().put(Headers.TRANSFER_ENCODING, "chunked"); + connection.sendRequest(request, client.createClientCallback(reference, latch, requestBody)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + logger.debug("statusCode = " + statusCode + " body = " + body); + System.out.println("********************statusCode = " + statusCode + " body = " + body); + Assert.assertEquals(404, statusCode); + if(statusCode == 404) { + Status status = Config.getInstance().getMapper().readValue(body, Status.class); + Assert.assertNotNull(status); + Assert.assertEquals("ERR12014", status.getCode()); + Assert.assertEquals("CLIENT_NOT_FOUND", status.getMessage()); + } + } + + @Test + public void testSerivceNotFound() throws ClientException, IOException { + logger.debug("Service not found test"); + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + String requestBody = "[\"/v1/data@post\",\"/v1/data@put\",\"/v1/data@get\",\"/v1/data@delete\"]"; + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/client/59f347a0-c92d-11e6-9d9d-cec0c932ce01/service/fake").setMethod(Methods.POST); + + request.getRequestHeaders().put(Headers.CONTENT_TYPE, "application/json"); + request.getRequestHeaders().put(Headers.TRANSFER_ENCODING, "chunked"); + connection.sendRequest(request, client.createClientCallback(reference, latch, requestBody)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + logger.debug("statusCode = " + statusCode + " body = " + body); + System.out.println("********************statusCode = " + statusCode + " body = " + body); + Assert.assertEquals(404, statusCode); + if(statusCode == 404) { + Status status = Config.getInstance().getMapper().readValue(body, Status.class); + Assert.assertNotNull(status); + Assert.assertEquals("ERR12015", status.getCode()); + Assert.assertEquals("SERVICE_NOT_FOUND", status.getMessage()); + } + } + +} diff --git a/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientPutHandlerTest.java b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientPutHandlerTest.java index 607bb7a1..07b294de 100644 --- a/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientPutHandlerTest.java +++ b/client/src/test/java/com/networknt/oauth/client/handler/Oauth2ClientPutHandlerTest.java @@ -36,7 +36,7 @@ public class Oauth2ClientPutHandlerTest { @Test public void testOauth2ClientPutHandler() throws ClientException, ApiException, UnsupportedEncodingException { - String s = "{\"clientId\":\"f7d42348-c647-4efb-a52d-4c5787421e72\",\"clientType\":\"trusted\",\"clientProfile\":\"webserver\",\"clientName\":\"Retail Account\",\"clientDesc\":\"Microservices for Retail Account\",\"scope\":\"act.r act.w\", \"redirectUri\": \"http://localhost:8080/authorization\", \"ownerId\":\"admin\"}"; + String s = "{\"clientId\":\"59f347a0-c92d-11e6-9d9d-cec0c932ce01\",\"clientType\":\"trusted\",\"clientProfile\":\"webserver\",\"clientName\":\"Retail Account\",\"clientDesc\":\"Microservices for Retail Account\",\"scope\":\"act.r act.w\", \"redirectUri\": \"http://localhost:8080/authorization\", \"ownerId\":\"admin\"}"; final AtomicReference reference = new AtomicReference<>(); final Http2Client client = Http2Client.getInstance(); final CountDownLatch latch = new CountDownLatch(1); @@ -75,7 +75,7 @@ public void run() { @Test public void testOwnerNotFound() throws ClientException, ApiException, UnsupportedEncodingException { - String s = "{\"clientId\":\"f7d42348-c647-4efb-a52d-4c5787421e72\",\"clientType\":\"trusted\",\"clientProfile\":\"webserver\",\"clientName\":\"Retail Account\",\"clientDesc\":\"Microservices for Retail Account\",\"scope\":\"act.r act.w\", \"redirectUri\": \"http://localhost:8080/authorization\", \"ownerId\":\"fake\"}"; + String s = "{\"clientId\":\"59f347a0-c92d-11e6-9d9d-cec0c932ce01\",\"clientType\":\"trusted\",\"clientProfile\":\"webserver\",\"clientName\":\"Retail Account\",\"clientDesc\":\"Microservices for Retail Account\",\"scope\":\"act.r act.w\", \"redirectUri\": \"http://localhost:8080/authorization\", \"ownerId\":\"fake\"}"; final AtomicReference reference = new AtomicReference<>(); final Http2Client client = Http2Client.getInstance(); final CountDownLatch latch = new CountDownLatch(1); diff --git a/client/src/test/java/com/networknt/oauth/client/handler/ServerInfoGetHandlerTest.java b/client/src/test/java/com/networknt/oauth/client/handler/ServerInfoGetHandlerTest.java new file mode 100644 index 00000000..975947c5 --- /dev/null +++ b/client/src/test/java/com/networknt/oauth/client/handler/ServerInfoGetHandlerTest.java @@ -0,0 +1,68 @@ + +package com.networknt.oauth.client.handler; + +import com.networknt.client.Http2Client; +import com.networknt.exception.ApiException; +import com.networknt.exception.ClientException; +import io.undertow.UndertowOptions; +import io.undertow.client.ClientConnection; +import io.undertow.client.ClientRequest; +import io.undertow.client.ClientResponse; +import io.undertow.util.Headers; +import io.undertow.util.Methods; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import java.io.IOException; + + +public class ServerInfoGetHandlerTest { + @ClassRule + public static TestServer server = TestServer.getInstance(); + + static final Logger logger = LoggerFactory.getLogger(ServerInfoGetHandlerTest.class); + static final boolean enableHttp2 = server.getServerConfig().isEnableHttp2(); + static final boolean enableHttps = server.getServerConfig().isEnableHttps(); + static final int httpPort = server.getServerConfig().getHttpPort(); + static final int httpsPort = server.getServerConfig().getHttpsPort(); + static final String url = enableHttp2 || enableHttps ? "https://localhost:" + httpsPort : "http://localhost:" + httpPort; + + @Test + public void testServerInfoGetHandlerTest() throws ClientException, ApiException { + /* + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/server/info").setMethod(Methods.GET); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(200, statusCode); + Assert.assertNotNull(body); + */ + } +} diff --git a/client/src/test/java/com/networknt/oauth/client/handler/TestServer.java b/client/src/test/java/com/networknt/oauth/client/handler/TestServer.java index 1011c0a5..9e841ad0 100644 --- a/client/src/test/java/com/networknt/oauth/client/handler/TestServer.java +++ b/client/src/test/java/com/networknt/oauth/client/handler/TestServer.java @@ -1,6 +1,7 @@ package com.networknt.oauth.client.handler; import com.networknt.server.Server; +import com.networknt.server.ServerConfig; import com.networknt.service.SingletonServiceFactory; import org.h2.tools.RunScript; import org.junit.rules.ExternalResource; @@ -46,6 +47,10 @@ private TestServer() { } + public ServerConfig getServerConfig() { + return Server.config; + } + @Override protected void before() { try { diff --git a/client/src/test/resources/config/swagger.json b/client/src/test/resources/config/swagger.json index 5b1dc0de..1c42a623 100644 --- a/client/src/test/resources/config/swagger.json +++ b/client/src/test/resources/config/swagger.json @@ -198,31 +198,183 @@ ] } }, - "/server/info": { - "get": { + "/oauth2/client/{clientId}/service": { + "delete": { + "description": "Delete all associated services for a client by clientId", + "operationId": "deleteAllClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client not found" + } + }, "security": [ { "client_auth": [ - "server.info.r" + "oauth.client.w" ] } + ] + }, + "get": { + "description": "Get all associated services and endpoints by clientId", + "operationId": "getAllClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } ], "responses": { "200": { - "description": "successful operation" + "description": "Successful response" + }, + "404": { + "description": "Client not found" } }, - "parameters": [] + "security": [ + { + "client_auth": [ + "oauth.client.r", + "oauth.client.w" + ] + } + ] } }, - "/health": { + "/oauth2/client/{clientId}/service/{serviceId}": { + "post": { + "description": "Link a service and its endpoints to a client", + "operationId": "linkClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "description": "A list of endpoints that needs to be linked to the client", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client or service not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "delete": { + "description": "Delete all endpoints of a service for a client", + "operationId": "deleteClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client or service not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, "get": { + "description": "Get linked endpoints of a service from a client", + "operationId": "getClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], "responses": { "200": { - "description": "successful operation" + "description": "Successful response" + }, + "404": { + "description": "Client or service not found" } }, - "parameters": [] + "security": [ + { + "client_auth": [ + "oauth.client.r", + "oauth.client.w" + ] + } + ] } } }, @@ -233,8 +385,7 @@ "flow": "implicit", "scopes": { "oauth.client.w": "write oauth client", - "oauth.client.r": "read oauth client", - "server.info.r": "read server info" + "oauth.client.r": "read oauth client" } } }, @@ -297,16 +448,6 @@ "redirectUri": { "type": "string", "description": "redirect uri" - }, - "createDt": { - "type": "string", - "format": "date-time", - "description": "create date time" - }, - "updateDt": { - "type": "string", - "format": "date-time", - "description": "update date time" } } } diff --git a/client/src/test/resources/create_h2.sql b/client/src/test/resources/create_h2.sql index 35b11b97..6723afc7 100644 --- a/client/src/test/resources/create_h2.sql +++ b/client/src/test/resources/create_h2.sql @@ -1,50 +1,86 @@ -DROP table IF EXISTS users; -DROP table IF EXISTS clients; -DROP table IF EXISTS services; +DROP table IF EXISTS user_profile; +DROP table IF EXISTS client; +DROP table IF EXISTS service; +DROP table IF EXISTS service_endpoint; +DROP table IF EXISTS client_service; +DROP table IF EXISTS audit_log; -create table users ( +create table user_profile ( user_id varchar PRIMARY KEY, user_type varchar, -- admin, customer, employee, partner first_name varchar, last_name varchar, email varchar, - password varchar, - create_dt DATE, - update_dt DATE + password varchar ); -CREATE UNIQUE INDEX email_idx ON users(email); +CREATE UNIQUE INDEX email_idx ON user_profile(email); -create table clients ( +create table client ( client_id VARCHAR PRIMARY KEY, client_secret VARCHAR, client_type VARCHAR, -- public, confidential, trusted - client_profile VARCHAR, -- webserver, browser, mobile, service, batch + client_profile VARCHAR, -- server, mobile, service, batch, browser client_name VARCHAR, client_desc VARCHAR, scope VARCHAR, redirect_uri VARCHAR, authenticate_class VARCHAR, - owner_id VARCHAR, - create_dt DATE, - update_dt DATE + owner_id VARCHAR ); -create table services ( +create table service ( service_id VARCHAR PRIMARY KEY, - service_type VARCHAR, -- api, ms + service_type VARCHAR, -- swagger, openapi, graphql, hybrid service_name VARCHAR, service_desc VARCHAR, scope VARCHAR, - owner_id VARCHAR, - create_dt DATE, - update_dt DATE + owner_id VARCHAR ); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +create table service_endpoint ( + service_id VARCHAR, + endpoint VARCHAR, -- different framework will have different endpoint format. + operation VARCHAR, + scope VARCHAR, + PRIMARY KEY (service_id, endpoint), + FOREIGN KEY (service_id) REFERENCES service(service_id) +); + +create table client_service ( + client_id VARCHAR NOT NULL, + service_id VARCHAR NOT NULL, + endpoint VARCHAR NOT NULL, -- different framework will have different endpoint format. + PRIMARY KEY (client_id, service_id, endpoint), + FOREIGN KEY (service_id, endpoint) REFERENCES service_endpoint(service_id, endpoint), + FOREIGN KEY (client_id) REFERENCES client(client_id) +); + +create table audit_log ( + log_id VARCHAR NOT NULL, + action_dt DATE, + service_id VARCHAR NOT NULL, + path VARCHAR NOT NULL, + method VARCHAR NOT NULL, + request_header VARCHAR NOT NULL, + request_body VARCHAR, + response_code INT, + response_header VARCHAR NOT NULL, + response_body VARCHAR, + PRIMARY KEY (log_id) +); + +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); + +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); + +INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'swagger', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO service_endpoint(service_id, endpoint, operation, scope) VALUES ('AACT0001', '/v1/data@post', 'post', 'data.w'); +INSERT INTO service_endpoint(service_id, endpoint, operation, scope) VALUES ('AACT0001', '/v1/data@put', 'put', 'data.w'); +INSERT INTO service_endpoint(service_id, endpoint, operation, scope) VALUES ('AACT0001', '/v1/data@delete', 'delete', 'data.w'); +INSERT INTO service_endpoint(service_id, endpoint, operation, scope) VALUES ('AACT0001', '/v1/data@get', 'get', 'data.w data.r'); -INSERT INTO services (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); +INSERT INTO client_service(client_id, service_id, endpoint) VALUES ('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'AACT0001', '/v1/data@get'); \ No newline at end of file diff --git a/code/docker/Dockerfile b/code/Dockerfile similarity index 100% rename from code/docker/Dockerfile rename to code/Dockerfile diff --git a/code/build.sh b/code/build.sh index a4e45344..faf205cc 100755 --- a/code/build.sh +++ b/code/build.sh @@ -42,7 +42,7 @@ cleanup() { publish() { echo "Building Docker image with version $VERSION" - docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./docker/Dockerfile . --no-cache=true + docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./Dockerfile . --no-cache=true docker build -t $IMAGE_NAME:$VERSION-redhat -f ./docker/Dockerfile-Redhat . --no-cache=true echo "Images built with version $VERSION" echo "Pushing image to DockerHub" diff --git a/code/docker/Dockerfile-Redhat b/code/docker/Dockerfile-Redhat index 77c75e0e..25ef3f53 100644 --- a/code/docker/Dockerfile-Redhat +++ b/code/docker/Dockerfile-Redhat @@ -2,27 +2,30 @@ FROM registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift USER root -ENV APP_DIR=/app \ +ENV APP_DIR=app \ GROUP_NAME=networknt \ GROUP_ID=1000 \ USER_NAME=networknt \ USER_UID=1000 RUN groupadd -g ${GROUP_ID} -r ${GROUP_NAME} && \ - useradd -u ${USER_UID} -g ${GROUP_NAME} -d "${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} + useradd -u ${USER_UID} -g ${GROUP_NAME} -d "/${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} # Add the jar file into the container at /app -ADD target/oauth2-code.jar ${APP_DIR}/server.jar +ADD target/oauth2-code.jar ./${APP_DIR}/server.jar # change permissions of app directory -RUN chown -R ${USER_NAME}:${GROUP_NAME} "${APP_DIR}" +RUN mkdir -p ./${APP_DIR}/config && \ + chown -R ${USER_NAME}:0 "./${APP_DIR}/config" && \ + find "./${APP_DIR}/config" -type d -exec chmod 750 {} \; && \ + find "./${APP_DIR}/config" -type f -exec chmod 640 {} \; # Port available to the world outside of this container -EXPOSE 6881 +EXPOSE 8080 USER ${USER_UID} # Set the working directory to /app -WORKDIR ${APP_DIR} +WORKDIR ./${APP_DIR} -CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] +CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] \ No newline at end of file diff --git a/code/src/main/resources/logback.xml b/code/src/main/resources/logback.xml index 6e58aff8..455f137d 100644 --- a/code/src/main/resources/logback.xml +++ b/code/src/main/resources/logback.xml @@ -28,7 +28,7 @@ - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n @@ -36,7 +36,7 @@ target/test.log false - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %class{36}:%L %M - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n diff --git a/code/src/test/resources/create_h2.sql b/code/src/test/resources/create_h2.sql index ad8e3dea..52c37cdf 100644 --- a/code/src/test/resources/create_h2.sql +++ b/code/src/test/resources/create_h2.sql @@ -1,8 +1,8 @@ -DROP table IF EXISTS users; -DROP table IF EXISTS clients; -DROP table IF EXISTS services; +DROP table IF EXISTS user_profile; +DROP table IF EXISTS client; +DROP table IF EXISTS service; -create table users ( +create table user_profile ( user_id varchar PRIMARY KEY, user_type varchar, -- admin, customer, employee, partner first_name varchar, @@ -13,13 +13,13 @@ create table users ( update_dt DATE ); -CREATE UNIQUE INDEX email_idx ON users(email); +CREATE UNIQUE INDEX email_idx ON user_profile(email); -create table clients ( +create table client ( client_id VARCHAR PRIMARY KEY, - client_type VARCHAR, client_secret VARCHAR, - client_profile VARCHAR, + client_type VARCHAR, -- public, confidential, trusted + client_profile VARCHAR, -- server, mobile, service, batch, browser client_name VARCHAR, client_desc VARCHAR, scope VARCHAR, @@ -30,7 +30,7 @@ create table clients ( update_dt DATE ); -create table services ( +create table service ( service_id VARCHAR PRIMARY KEY, service_type VARCHAR, -- api, ms service_name VARCHAR, @@ -41,10 +41,10 @@ create table services ( update_dt DATE ); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); -INSERT INTO services (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); +INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); diff --git a/db/mysql/config/oauth2-client/cors.yml b/db/mysql/config/oauth2-client/cors.yml new file mode 100644 index 00000000..b83eecdf --- /dev/null +++ b/db/mysql/config/oauth2-client/cors.yml @@ -0,0 +1,13 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +description: Cors Http Handler +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/mysql/config/oauth2-client/oauth/primary.crt b/db/mysql/config/oauth2-client/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/mysql/config/oauth2-client/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-client/oauth/secondary.crt b/db/mysql/config/oauth2-client/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/mysql/config/oauth2-client/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-client/secret.yml b/db/mysql/config/oauth2-client/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/mysql/config/oauth2-client/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/mysql/config/oauth2-client/security.yml b/db/mysql/config/oauth2-client/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/mysql/config/oauth2-client/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/mysql/config/oauth2-client/server.yml b/db/mysql/config/oauth2-client/server.yml new file mode 100644 index 00000000..151859b6 --- /dev/null +++ b/db/mysql/config/oauth2-client/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6884 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6884 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-client-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/mysql/config/oauth2-client/swagger.json b/db/mysql/config/oauth2-client/swagger.json new file mode 100644 index 00000000..1c42a623 --- /dev/null +++ b/db/mysql/config/oauth2-client/swagger.json @@ -0,0 +1,455 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "OAuth2 Client Registration", + "description": "OAuth2 Client Registration microservices endpoints.", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/client": { + "post": { + "description": "Return a client object", + "operationId": "createClient", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Client object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Client" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Client" + } + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "put": { + "description": "Return the updated client", + "operationId": "updateClient", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Client object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Client" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Client" + } + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "get": { + "description": "Return all clients", + "operationId": "getAllClient", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "pageSize", + "in": "query", + "description": "Pag size", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "clientName", + "in": "query", + "description": "Partial clientName for filter", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Client" + } + } + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.r" + ] + } + ] + } + }, + "/oauth2/client/{clientId}": { + "delete": { + "description": "Delete a client by Id", + "operationId": "deleteClient", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid clientId supplied" + }, + "404": { + "description": "Client not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "get": { + "description": "Get a client by Id", + "operationId": "getClient", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Client" + } + }, + "400": { + "description": "Invalid clientId supplied" + }, + "404": { + "description": "Client not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.r", + "oauth.client.w" + ] + } + ] + } + }, + "/oauth2/client/{clientId}/service": { + "delete": { + "description": "Delete all associated services for a client by clientId", + "operationId": "deleteAllClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "get": { + "description": "Get all associated services and endpoints by clientId", + "operationId": "getAllClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.r", + "oauth.client.w" + ] + } + ] + } + }, + "/oauth2/client/{clientId}/service/{serviceId}": { + "post": { + "description": "Link a service and its endpoints to a client", + "operationId": "linkClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "description": "A list of endpoints that needs to be linked to the client", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client or service not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "delete": { + "description": "Delete all endpoints of a service for a client", + "operationId": "deleteClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client or service not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "get": { + "description": "Get linked endpoints of a service from a client", + "operationId": "getClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client or service not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.r", + "oauth.client.w" + ] + } + ] + } + } + }, + "securityDefinitions": { + "client_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.client.w": "write oauth client", + "oauth.client.r": "read oauth client" + } + } + }, + "definitions": { + "Client": { + "type": "object", + "required": [ + "clientType", + "clientProfile", + "clientName", + "clientDesc", + "ownerId", + "scope" + ], + "properties": { + "clientId": { + "type": "string", + "description": "a unique client id" + }, + "clientSecret": { + "type": "string", + "description": "client secret" + }, + "clientType": { + "type": "string", + "description": "client type", + "enum": [ + "confidential", + "public", + "trusted" + ] + }, + "clientProfile": { + "type": "string", + "description": "client profile", + "enum": [ + "webserver", + "browser", + "mobile", + "service", + "batch" + ] + }, + "clientName": { + "type": "string", + "description": "client name" + }, + "clientDesc": { + "type": "string", + "description": "client description" + }, + "ownerId": { + "type": "string", + "description": "client owner id" + }, + "scope": { + "type": "string", + "description": "client scope separated by space" + }, + "redirectUri": { + "type": "string", + "description": "redirect uri" + } + } + } + } +} \ No newline at end of file diff --git a/db/mysql/config/oauth2-client/tls/server.keystore b/db/mysql/config/oauth2-client/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/mysql/config/oauth2-client/tls/server.keystore differ diff --git a/db/mysql/config/oauth2-client/tls/server.truststore b/db/mysql/config/oauth2-client/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/mysql/config/oauth2-client/tls/server.truststore differ diff --git a/db/mysql/config/oauth2-code/cors.yml b/db/mysql/config/oauth2-code/cors.yml new file mode 100644 index 00000000..b83eecdf --- /dev/null +++ b/db/mysql/config/oauth2-code/cors.yml @@ -0,0 +1,13 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +description: Cors Http Handler +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/mysql/config/oauth2-code/jwt.yml b/db/mysql/config/oauth2-code/jwt.yml new file mode 100644 index 00000000..bc7ae31c --- /dev/null +++ b/db/mysql/config/oauth2-code/jwt.yml @@ -0,0 +1,13 @@ +# This is the default JWT configuration and need to be updated when used to issue JWT tokens. It is a component that used to +# issue JWT token. Normally, it should be used by light-oauth2 only but can be used to issue tokens distributely. +--- +# Signature private key that used to sign JWT tokens. +key: + kid: '100' # kid that used to sign the JWT tokens. It will be shown up in the token header. + filename: "/config/oauth/primary.jks" # private key that is used to sign JWT tokens. + password: password # password for the private key. It should be set during deployment time along with pk + keyName: selfsigned # key name that is used to identify the right key in keystore. +issuer: urn:com:networknt:oauth2:v1 # default issuer of the JWT token +audience: urn:com.networknt # default audience of the JWT token +expiredInMinutes: 10 # expired in 10 minutes by default for issued JWT tokens +version: '1.0' # JWT token version diff --git a/db/mysql/config/oauth2-code/oauth/primary.crt b/db/mysql/config/oauth2-code/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/mysql/config/oauth2-code/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-code/oauth/secondary.crt b/db/mysql/config/oauth2-code/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/mysql/config/oauth2-code/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-code/secret.yml b/db/mysql/config/oauth2-code/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/mysql/config/oauth2-code/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/mysql/config/oauth2-code/security.yml b/db/mysql/config/oauth2-code/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/mysql/config/oauth2-code/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/mysql/config/oauth2-code/server.yml b/db/mysql/config/oauth2-code/server.yml new file mode 100644 index 00000000..95816ef8 --- /dev/null +++ b/db/mysql/config/oauth2-code/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6881 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6881 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-code-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/mysql/config/oauth2-code/swagger.json b/db/mysql/config/oauth2-code/swagger.json new file mode 100644 index 00000000..8e24d450 --- /dev/null +++ b/db/mysql/config/oauth2-code/swagger.json @@ -0,0 +1,197 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "OAuth2 Service Authorization Code", + "description": "OAuth2 Service that logs in user and provide authorization code.", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/code": { + "get": { + "description": "Return 302 redirect with authorization code", + "operationId": "getAuthCode", + "parameters": [ + { + "name": "Authorization", + "description": "encoded username:password mandatory if Basic Authentication is used", + "in": "header", + "required": false, + "type": "string" + }, + { + "name": "response_type", + "in": "query", + "description": "The response type for authorization code", + "required": true, + "type": "string", + "enum": [ + "code" + ] + }, + { + "name": "client_id", + "in": "query", + "description": "The client id for authorization code", + "required": true, + "type": "string" + }, + { + "name": "redirect_uri", + "in": "query", + "description": "The redirect uri for authorization code", + "required": false, + "type": "string" + }, + { + "name": "username", + "in": "query", + "description": "The user name for authorization code", + "required": false, + "type": "string" + }, + { + "name": "password", + "in": "query", + "description": "The password for authorization code in clear text", + "required": false, + "type": "string" + }, + { + "name": "state", + "in": "query", + "description": "to prevent cross-site request forgery", + "required": false, + "type": "string" + }, + { + "name": "scope", + "in": "query", + "description": "scope of the request", + "required": false, + "type": "string" + }, + { + "name": "code_challenge", + "in": "query", + "description": "PKCE code challenge", + "required": false, + "type": "string" + }, + { + "name": "code_challenge_method", + "in": "query", + "description": "PKCE code challenge method", + "required": false, + "type": "string" + } + ], + "responses": { + "302": { + "description": "Successful Operation" + } + } + }, + "post": { + "description": "Return 302 redirect with authorization code", + "operationId": "postAuthCode", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "j_username", + "in": "formData", + "description": "User name", + "required": true, + "type": "string" + }, + { + "name": "j_password", + "in": "formData", + "description": "Password", + "required": true, + "type": "string" + }, + { + "name": "response_type", + "in": "formData", + "description": "Response type", + "required": true, + "type": "string", + "enum": [ + "code" + ] + }, + { + "name": "client_id", + "in": "formData", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "redirect_uri", + "in": "formData", + "description": "Redirect Uri", + "required": false, + "type": "string" + }, + { + "name": "state", + "in": "formData", + "description": "to prevent cross-site request forgery", + "required": false, + "type": "string" + }, + { + "name": "scope", + "in": "formData", + "description": "scope of the request", + "required": false, + "type": "string" + }, + { + "name": "code_challenge", + "in": "formData", + "description": "PKCE code challenge", + "required": false, + "type": "string" + }, + { + "name": "code_challenge_method", + "in": "formData", + "description": "PKCE code challenge method", + "required": false, + "type": "string" + } + ], + "responses": { + "302": { + "description": "Successful Operation" + } + } + } + } + } +} \ No newline at end of file diff --git a/db/mysql/config/oauth2-code/tls/server.keystore b/db/mysql/config/oauth2-code/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/mysql/config/oauth2-code/tls/server.keystore differ diff --git a/db/mysql/config/oauth2-code/tls/server.truststore b/db/mysql/config/oauth2-code/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/mysql/config/oauth2-code/tls/server.truststore differ diff --git a/db/mysql/config/oauth2-key/cors.yml b/db/mysql/config/oauth2-key/cors.yml new file mode 100644 index 00000000..b83eecdf --- /dev/null +++ b/db/mysql/config/oauth2-key/cors.yml @@ -0,0 +1,13 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +description: Cors Http Handler +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/mysql/config/oauth2-key/oauth/primary.crt b/db/mysql/config/oauth2-key/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/mysql/config/oauth2-key/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-key/oauth/secondary.crt b/db/mysql/config/oauth2-key/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/mysql/config/oauth2-key/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-key/secret.yml b/db/mysql/config/oauth2-key/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/mysql/config/oauth2-key/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/mysql/config/oauth2-key/security.yml b/db/mysql/config/oauth2-key/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/mysql/config/oauth2-key/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/mysql/config/oauth2-key/server.yml b/db/mysql/config/oauth2-key/server.yml new file mode 100644 index 00000000..454ba61a --- /dev/null +++ b/db/mysql/config/oauth2-key/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6886 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6886 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-key-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/mysql/config/oauth2-key/swagger.json b/db/mysql/config/oauth2-key/swagger.json new file mode 100644 index 00000000..1f8a6c2a --- /dev/null +++ b/db/mysql/config/oauth2-key/swagger.json @@ -0,0 +1,125 @@ +{ + "swagger": "2.0", + "info": { + "description": "OAuth2 Key Service microservices endpoints.", + "version": "1.0.0", + "title": "OAuth2 Key Service", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/key/{keyId}": { + "get": { + "description": "Get a key by Id", + "operationId": "getKeyById", + "parameters": [ + { + "name": "keyId", + "in": "path", + "description": "Key Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Key" + } + }, + "400": { + "description": "Invalid keyId supplied" + }, + "404": { + "description": "Key not found" + } + }, + "security": [ + { + "key_auth": [ + "oauth.key.r", + "oauth.key.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/server/info": { + "get": { + "security": [ + { + "key_auth": [ + "server.info.r" + ] + } + ], + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + }, + "/health": { + "get": { + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + } + }, + "securityDefinitions": { + "key_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.key.w": "write key", + "oauth.key.r": "read key", + "server.info.r": "read server info" + } + } + }, + "definitions": { + "Key": { + "type": "object", + "required": [ + "certificate", + "keyId" + ], + "properties": { + "keyId": { + "type": "string", + "description": "a unique id" + }, + "certificate": { + "type": "string", + "description": "certificate" + } + } + } + } +} \ No newline at end of file diff --git a/db/mysql/config/oauth2-key/tls/server.keystore b/db/mysql/config/oauth2-key/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/mysql/config/oauth2-key/tls/server.keystore differ diff --git a/db/mysql/config/oauth2-key/tls/server.truststore b/db/mysql/config/oauth2-key/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/mysql/config/oauth2-key/tls/server.truststore differ diff --git a/db/mysql/config/oauth2-refresh-token/cors.yml b/db/mysql/config/oauth2-refresh-token/cors.yml new file mode 100644 index 00000000..99437103 --- /dev/null +++ b/db/mysql/config/oauth2-refresh-token/cors.yml @@ -0,0 +1,12 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/mysql/config/oauth2-refresh-token/oauth/primary.crt b/db/mysql/config/oauth2-refresh-token/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/mysql/config/oauth2-refresh-token/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-refresh-token/oauth/secondary.crt b/db/mysql/config/oauth2-refresh-token/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/mysql/config/oauth2-refresh-token/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-refresh-token/secret.yml b/db/mysql/config/oauth2-refresh-token/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/mysql/config/oauth2-refresh-token/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/mysql/config/oauth2-refresh-token/security.yml b/db/mysql/config/oauth2-refresh-token/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/mysql/config/oauth2-refresh-token/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/mysql/config/oauth2-refresh-token/server.yml b/db/mysql/config/oauth2-refresh-token/server.yml new file mode 100644 index 00000000..58ec6aec --- /dev/null +++ b/db/mysql/config/oauth2-refresh-token/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6887 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6887 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-refresh-token-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/mysql/config/oauth2-refresh-token/swagger.json b/db/mysql/config/oauth2-refresh-token/swagger.json new file mode 100644 index 00000000..fc2c1fbb --- /dev/null +++ b/db/mysql/config/oauth2-refresh-token/swagger.json @@ -0,0 +1,215 @@ +{ + "swagger": "2.0", + "info": { + "description": "OAuth2 refresh token management microservices endpoints.", + "version": "1.0.0", + "title": "OAuth2 Refresh Token Management", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/refresh_token": { + "get": { + "description": "Return all refresh tokens", + "operationId": "getAllRefreshToken", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "pageSize", + "in": "query", + "description": "Pag size", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "userId", + "in": "query", + "description": "Partial userId for filter", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/RefreshToken" + } + } + } + }, + "security": [ + { + "refresh_token_auth": [ + "oauth.refresh_token.r" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/oauth2/refresh_token/{refreshToken}": { + "get": { + "description": "Get a refresh token", + "operationId": "getRefreshToken", + "parameters": [ + { + "name": "refreshToken", + "in": "path", + "description": "Refresh token", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/RefreshToken" + } + }, + "400": { + "description": "Invalid refresh token supplied" + }, + "404": { + "description": "Refresh token not found" + } + }, + "security": [ + { + "refresh_token_auth": [ + "oauth.refresh_token.r", + "oauth.refresh_token.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + }, + "delete": { + "description": "Delete a refresh token", + "operationId": "deleteRefreshToken", + "parameters": [ + { + "name": "refreshToken", + "in": "path", + "description": "Refresh Token", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid refresh token supplied" + }, + "404": { + "description": "Refresh token not found" + } + }, + "security": [ + { + "refresh_token_auth": [ + "oauth.refresh_token.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/server/info": { + "get": { + "security": [ + { + "refresh_token_auth": [ + "server.info.r" + ] + } + ], + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + }, + "/health": { + "get": { + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + } + }, + "securityDefinitions": { + "refresh_token_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.refresh_token.w": "write oauth refresh token", + "oauth.refresh_token.r": "read oauth refresh token", + "server.info.r": "read server info" + } + } + }, + "definitions": { + "RefreshToken": { + "type": "object", + "required": [ + "clientId", + "refreshToken", + "userId" + ], + "properties": { + "refreshToken": { + "type": "string", + "description": "refresh token" + }, + "userId": { + "type": "string", + "description": "user id" + }, + "clientId": { + "type": "string", + "description": "client id" + }, + "scope": { + "type": "string", + "description": "service scopes separated by space" + } + } + } + } +} \ No newline at end of file diff --git a/db/mysql/config/oauth2-refresh-token/tls/server.keystore b/db/mysql/config/oauth2-refresh-token/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/mysql/config/oauth2-refresh-token/tls/server.keystore differ diff --git a/db/mysql/config/oauth2-refresh-token/tls/server.truststore b/db/mysql/config/oauth2-refresh-token/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/mysql/config/oauth2-refresh-token/tls/server.truststore differ diff --git a/db/mysql/config/oauth2-service/cors.yml b/db/mysql/config/oauth2-service/cors.yml new file mode 100644 index 00000000..99437103 --- /dev/null +++ b/db/mysql/config/oauth2-service/cors.yml @@ -0,0 +1,12 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/mysql/config/oauth2-service/oauth/primary.crt b/db/mysql/config/oauth2-service/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/mysql/config/oauth2-service/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-service/oauth/secondary.crt b/db/mysql/config/oauth2-service/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/mysql/config/oauth2-service/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-service/secret.yml b/db/mysql/config/oauth2-service/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/mysql/config/oauth2-service/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/mysql/config/oauth2-service/security.yml b/db/mysql/config/oauth2-service/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/mysql/config/oauth2-service/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/mysql/config/oauth2-service/server.yml b/db/mysql/config/oauth2-service/server.yml new file mode 100644 index 00000000..ff558b00 --- /dev/null +++ b/db/mysql/config/oauth2-service/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6883 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6883 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-service-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/mysql/config/oauth2-service/swagger.json b/db/mysql/config/oauth2-service/swagger.json new file mode 100644 index 00000000..c51d14a3 --- /dev/null +++ b/db/mysql/config/oauth2-service/swagger.json @@ -0,0 +1,393 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "OAuth2 Service Registration", + "description": "OAuth2 Service Registration microservices endpoints.", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/service": { + "post": { + "description": "Return a service object", + "operationId": "createService", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Service object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Service" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Service" + } + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "put": { + "description": "Return the updated service", + "operationId": "updateService", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Service object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Service" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Service" + } + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "get": { + "description": "Return all services", + "operationId": "getAllService", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "pageSize", + "in": "query", + "description": "Pag size", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "serviceId", + "in": "query", + "description": "Partial serviceId for filter", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Service" + } + } + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.r" + ] + } + ] + } + }, + "/oauth2/service/{serviceId}": { + "delete": { + "description": "Delete a service by Id", + "operationId": "deleteService", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "Service not found" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "get": { + "description": "Get a service by Id", + "operationId": "getService", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Service" + } + }, + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "Service not found" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.r", + "oauth.service.w" + ] + } + ] + } + }, + "/oauth2/service/{serviceId}/endpoint": { + "post": { + "description": "create endpoints for service", + "operationId": "createServiceEndpoint", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "A list of endpoint object", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ServiceEndpoint" + } + } + } + ], + "responses": { + "201": { + "description": "Successful response" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "delete": { + "description": "Delete all endpoints for a service", + "operationId": "deleteServiceEndpoint", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "Service not found" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "get": { + "description": "Get all endpoints for a service", + "operationId": "getServiceEndpoint", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ServiceEndpoint" + } + } + }, + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "ServiceEndpoint not found" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.r", + "oauth.service.w" + ] + } + ] + } + } + }, + "securityDefinitions": { + "service_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.service.w": "write oauth service", + "oauth.service.r": "read oauth service" + } + } + }, + "definitions": { + "Service": { + "type": "object", + "required": [ + "serviceId", + "serviceName", + "serviceType", + "scope" + ], + "properties": { + "serviceId": { + "type": "string", + "description": "a unique service id" + }, + "serviceType": { + "type": "string", + "description": "service type", + "enum": [ + "swagger", + "openapi", + "graphql", + "hybrid" + ] + }, + "serviceName": { + "type": "string", + "description": "service name" + }, + "serviceDesc": { + "type": "string", + "description": "service description" + }, + "ownerId": { + "type": "string", + "description": "service owner userId" + }, + "scope": { + "type": "string", + "description": "service scopes separated by space" + }, + "createDt": { + "type": "string", + "format": "date-time", + "description": "create date time" + }, + "updateDt": { + "type": "string", + "format": "date-time", + "description": "update date time" + } + } + }, + "ServiceEndpoint": { + "type": "object", + "required": [ + "endpoint", + "operation", + "scope" + ], + "properties": { + "endpoint": { + "type": "string", + "description": "a combination of path and method to uniquely identify an operation" + }, + "operation": { + "type": "string", + "description": "operationId of the endpoint" + }, + "scope": { + "type": "string", + "description": "scope associated with the endpoint" + } + } + } + } +} \ No newline at end of file diff --git a/db/mysql/config/oauth2-service/tls/server.keystore b/db/mysql/config/oauth2-service/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/mysql/config/oauth2-service/tls/server.keystore differ diff --git a/db/mysql/config/oauth2-service/tls/server.truststore b/db/mysql/config/oauth2-service/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/mysql/config/oauth2-service/tls/server.truststore differ diff --git a/db/mysql/config/oauth2-token/cors.yml b/db/mysql/config/oauth2-token/cors.yml new file mode 100644 index 00000000..b83eecdf --- /dev/null +++ b/db/mysql/config/oauth2-token/cors.yml @@ -0,0 +1,13 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +description: Cors Http Handler +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/mysql/config/oauth2-token/jwt.yml b/db/mysql/config/oauth2-token/jwt.yml new file mode 100644 index 00000000..bc7ae31c --- /dev/null +++ b/db/mysql/config/oauth2-token/jwt.yml @@ -0,0 +1,13 @@ +# This is the default JWT configuration and need to be updated when used to issue JWT tokens. It is a component that used to +# issue JWT token. Normally, it should be used by light-oauth2 only but can be used to issue tokens distributely. +--- +# Signature private key that used to sign JWT tokens. +key: + kid: '100' # kid that used to sign the JWT tokens. It will be shown up in the token header. + filename: "/config/oauth/primary.jks" # private key that is used to sign JWT tokens. + password: password # password for the private key. It should be set during deployment time along with pk + keyName: selfsigned # key name that is used to identify the right key in keystore. +issuer: urn:com:networknt:oauth2:v1 # default issuer of the JWT token +audience: urn:com.networknt # default audience of the JWT token +expiredInMinutes: 10 # expired in 10 minutes by default for issued JWT tokens +version: '1.0' # JWT token version diff --git a/db/mysql/config/oauth2-token/oauth/primary.crt b/db/mysql/config/oauth2-token/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/mysql/config/oauth2-token/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-token/oauth/primary.jks b/db/mysql/config/oauth2-token/oauth/primary.jks new file mode 100644 index 00000000..0d6ae7cf Binary files /dev/null and b/db/mysql/config/oauth2-token/oauth/primary.jks differ diff --git a/db/mysql/config/oauth2-token/oauth/secondary.crt b/db/mysql/config/oauth2-token/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/mysql/config/oauth2-token/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-token/oauth/secondary.jks b/db/mysql/config/oauth2-token/oauth/secondary.jks new file mode 100644 index 00000000..33824c89 Binary files /dev/null and b/db/mysql/config/oauth2-token/oauth/secondary.jks differ diff --git a/db/mysql/config/oauth2-token/secret.yml b/db/mysql/config/oauth2-token/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/mysql/config/oauth2-token/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/mysql/config/oauth2-token/security.yml b/db/mysql/config/oauth2-token/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/mysql/config/oauth2-token/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/mysql/config/oauth2-token/server.yml b/db/mysql/config/oauth2-token/server.yml new file mode 100644 index 00000000..2a414220 --- /dev/null +++ b/db/mysql/config/oauth2-token/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6882 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6882 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-token-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/mysql/config/oauth2-token/swagger.json b/db/mysql/config/oauth2-token/swagger.json new file mode 100644 index 00000000..b56f7433 --- /dev/null +++ b/db/mysql/config/oauth2-token/swagger.json @@ -0,0 +1,125 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "OAuth2 Service Token Service", + "description": "OAuth2 Service that issues access tokens.", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/x-www-form-urlencoded" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/token": { + "post": { + "description": "JSON object that contains access token", + "operationId": "postToken", + "parameters": [ + { + "name": "authorization", + "description": "encoded client_id and client_secret pair", + "in": "header", + "type": "string", + "required": false + }, + { + "name": "grant_type", + "type": "string", + "enum": [ + "authorization_code", + "client_credentials", + "password", + "refresh_token", + "client_authenticated_user" + ], + "required": true, + "in": "formData" + }, + { + "name": "client_id", + "description": "used as alternative to authentication header for client authentication", + "type": "string", + "in": "formData" + }, + { + "name": "client_secret", + "description": "used as alternative to authentication header for client authentication", + "type": "string", + "in": "formData" + }, + { + "name": "code", + "description": "used in authorization_code to specify the code", + "type": "string", + "in": "formData" + }, + { + "name": "username", + "description": "mandatory in password grant type", + "type": "string", + "in": "formData" + }, + { + "name": "password", + "description": "mandatory in password grant type", + "type": "string", + "in": "formData" + }, + { + "name": "scope", + "description": "used by all flows to specify scope in the access token", + "type": "string", + "in": "formData" + }, + { + "name": "redirect_uri", + "description": "used in authorization code if code endpoint with rediret_uri", + "type": "string", + "in": "formData" + }, + { + "name": "refresh_token", + "description": "refresh token used to get another access token", + "type": "string", + "in": "formData" + }, + { + "name": "code_verifier", + "description": "PKCE code verifier", + "type": "string", + "in": "formData" + } + ], + "responses": { + "200": { + "description": "Successful Operation" + } + } + } + }, + "/health": { + "get": { + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + } + } +} diff --git a/db/mysql/config/oauth2-token/tls/server.keystore b/db/mysql/config/oauth2-token/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/mysql/config/oauth2-token/tls/server.keystore differ diff --git a/db/mysql/config/oauth2-token/tls/server.truststore b/db/mysql/config/oauth2-token/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/mysql/config/oauth2-token/tls/server.truststore differ diff --git a/db/mysql/config/oauth2-user/cors.yml b/db/mysql/config/oauth2-user/cors.yml new file mode 100644 index 00000000..99437103 --- /dev/null +++ b/db/mysql/config/oauth2-user/cors.yml @@ -0,0 +1,12 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/mysql/config/oauth2-user/oauth/primary.crt b/db/mysql/config/oauth2-user/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/mysql/config/oauth2-user/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-user/oauth/secondary.crt b/db/mysql/config/oauth2-user/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/mysql/config/oauth2-user/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/mysql/config/oauth2-user/secret.yml b/db/mysql/config/oauth2-user/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/mysql/config/oauth2-user/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/mysql/config/oauth2-user/security.yml b/db/mysql/config/oauth2-user/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/mysql/config/oauth2-user/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/mysql/config/oauth2-user/server.yml b/db/mysql/config/oauth2-user/server.yml new file mode 100644 index 00000000..8718d5a6 --- /dev/null +++ b/db/mysql/config/oauth2-user/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6885 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6885 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-user-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/mysql/config/oauth2-user/swagger.json b/db/mysql/config/oauth2-user/swagger.json new file mode 100644 index 00000000..9717cc2a --- /dev/null +++ b/db/mysql/config/oauth2-user/swagger.json @@ -0,0 +1,368 @@ +{ + "swagger": "2.0", + "info": { + "description": "OAuth2 User Service microservices endpoints.", + "version": "1.0.0", + "title": "OAuth2 User Service", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/password/{userId}": { + "post": { + "description": "Reset Password", + "operationId": "resetPassword", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Password object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Password" + } + }, + { + "name": "userId", + "in": "path", + "description": "User Id", + "required": true, + "type": "string" + } + ], + "responses": { + "404": { + "description": "User not found" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/oauth2/user": { + "get": { + "description": "Return all users", + "operationId": "getAllUsers", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "pageSize", + "in": "query", + "description": "Pag size", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "userId", + "in": "query", + "description": "Partial userId for filter", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/User" + } + } + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.r" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + }, + "post": { + "description": "Return a user object", + "operationId": "createUser", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "User object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/User" + } + } + ], + "responses": { + "200": { + "description": "Successful response" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + }, + "put": { + "description": "Return the updated user", + "operationId": "updateUser", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "User object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/User" + } + } + ], + "responses": { + "200": { + "description": "Successful response" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/oauth2/user/{userId}": { + "get": { + "description": "Get a user by Id", + "operationId": "getUser", + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "User Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/User" + } + }, + "400": { + "description": "Invalid userId supplied" + }, + "404": { + "description": "User not found" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.r", + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + }, + "delete": { + "description": "Delete a user by Id", + "operationId": "deleteUser", + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "User Id", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid userId supplied" + }, + "404": { + "description": "User not found" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/server/info": { + "get": { + "security": [ + { + "service_auth": [ + "server.info.r" + ] + } + ], + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + }, + "/health": { + "get": { + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + } + }, + "securityDefinitions": { + "user_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.user.w": "write user", + "oauth.user.r": "read user", + "server.info.r": "read server info" + } + } + }, + "definitions": { + "User": { + "type": "object", + "required": [ + "email", + "firstName", + "lastName", + "userId", + "userType" + ], + "properties": { + "userId": { + "type": "string", + "description": "a unique id" + }, + "userType": { + "type": "string", + "description": "user type", + "enum": [ + "admin", + "employee", + "customer", + "partner" + ] + }, + "firstName": { + "type": "string", + "description": "first name" + }, + "lastName": { + "type": "string", + "description": "last name" + }, + "email": { + "type": "string", + "description": "email address" + }, + "password": { + "type": "string", + "format": "password", + "description": "password" + }, + "passwordConfirm": { + "type": "string", + "format": "password", + "description": "password confirm" + }, + "createDt": { + "type": "string", + "format": "date-time", + "description": "create date time" + }, + "updateDt": { + "type": "string", + "format": "date-time", + "description": "update date time" + } + } + }, + "Password": { + "type": "object", + "required": [ + "newPassword", + "newPasswordConfirm", + "password" + ], + "properties": { + "password": { + "type": "string", + "format": "password", + "description": "existing password" + }, + "newPassword": { + "type": "string", + "format": "password", + "description": "new password" + }, + "newPasswordConfirm": { + "type": "string", + "format": "password", + "description": "new password confirm" + } + } + } + } +} \ No newline at end of file diff --git a/db/mysql/config/oauth2-user/tls/server.keystore b/db/mysql/config/oauth2-user/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/mysql/config/oauth2-user/tls/server.keystore differ diff --git a/db/mysql/config/oauth2-user/tls/server.truststore b/db/mysql/config/oauth2-user/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/mysql/config/oauth2-user/tls/server.truststore differ diff --git a/db/mysql/create_mysql.sql b/db/mysql/create_mysql.sql index 35bd6a11..27c2dfba 100644 --- a/db/mysql/create_mysql.sql +++ b/db/mysql/create_mysql.sql @@ -2,56 +2,86 @@ DROP DATABASE IF EXISTS oauth2; CREATE DATABASE oauth2; USE oauth2; -DROP TABLE IF EXISTS users; -CREATE TABLE users ( +DROP TABLE IF EXISTS user_profile; +CREATE TABLE user_profile ( user_id VARCHAR(32) NOT NULL, user_type VARCHAR(16) NOT NULL, -- admin, customer, employee, partner first_name VARCHAR(32) NOT NULL, last_name VARCHAR(32) NOT NULL, email VARCHAR(64) NOT NULL, password VARCHAR(1024) NOT NULL, - create_dt DATE NOT NULL, - update_dt DATE, PRIMARY KEY (user_id) ) ENGINE=INNODB; -CREATE UNIQUE INDEX email_idx ON users(email); +CREATE UNIQUE INDEX email_idx ON user_profile(email); -DROP TABLE IF EXISTS clients; -CREATE TABLE clients ( +DROP TABLE IF EXISTS client; +CREATE TABLE client ( client_id VARCHAR(36) NOT NULL, client_type VARCHAR(12) NOT NULL, -- public, confidential, trusted client_profile VARCHAR(10) NOT NULL, -- webserver, mobile, browser, batch, service client_secret VARCHAR(1024) NOT NULL, client_name VARCHAR(32) NOT NULL, client_desc VARCHAR(2048), - scope VARCHAR(1024), + scope VARCHAR(4096), redirect_uri VARCHAR(1024), authenticate_class VARCHAR(256), owner_id VARCHAR(32) NOT NULL, - create_dt DATE NOT NULL, - update_dt DATE, PRIMARY KEY (client_id), - FOREIGN KEY (owner_id) REFERENCES users(user_id) + FOREIGN KEY (owner_id) REFERENCES user_profile(user_id) ) ENGINE=INNODB; -DROP TABLE IF EXISTS services; -CREATE TABLE services ( +DROP TABLE IF EXISTS service; +CREATE TABLE service ( service_id VARCHAR(32) NOT NULL, - service_type VARCHAR(8) NOT NULL, -- api, ms + service_type VARCHAR(16) NOT NULL, -- swagger, openapi, graphql, hybrid service_name VARCHAR(32) NOT NULL, service_desc VARCHAR(1024), scope VARCHAR(1024), owner_id VARCHAR(32) NOT NULL, - create_dt DATE NOT NULL, - update_dt DATE, PRIMARY KEY (service_id), - FOREIGN KEY (owner_id) REFERENCES users(user_id) + FOREIGN KEY (owner_id) REFERENCES user_profile(user_id) +) +ENGINE=INNODB; + +DROP TABLE IF EXISTS service_endpoint; +CREATE TABLE service_endpoint ( + service_id VARCHAR(32) NOT NULL, + endpoint VARCHAR(256) NOT NULL, -- different framework will have different endpoint format. + operation VARCHAR(256) NOT NULL, + scope VARCHAR(64) NOT NULL, + PRIMARY KEY (service_id, endpoint), + FOREIGN KEY (service_id) REFERENCES service(service_id) ) ENGINE=INNODB; +DROP TABLE IF EXISTS client_service; +CREATE TABLE client_service ( + client_id VARCHAR(36) NOT NULL, + service_id VARCHAR(32) NOT NULL, + endpoint VARCHAR(256) NOT NULL, -- different framework will have different endpoint format. + PRIMARY KEY (client_id, service_id, endpoint), + FOREIGN KEY (service_id, endpoint) REFERENCES service_endpoint(service_id, endpoint), + FOREIGN KEY (client_id) REFERENCES client(client_id) +) +ENGINE=INNODB; + +DROP TABLE IF EXISTS audit_log; +create table audit_log ( + log_id INT, -- system milliseonds from 1970. + service_id VARCHAR(32) NOT NULL, + endpoint VARCHAR(256) NOT NULL, + request_header VARCHAR(4096), + request_body VARCHAR(4096), + response_code INT, + response_header VARCHAR(4096), + response_body VARCHAR(4096) +) +ENGINE=INNODB; + +/* CREATE TABLE IF NOT EXISTS client ( client_id VARCHAR(32) NOT NULL, client_secret VARCHAR(512) NOT NULL, @@ -105,14 +135,14 @@ CREATE TABLE IF NOT EXISTS client ( PRIMARY KEY (client_id) ) ENGINE=INNODB; +*/ +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) +VALUES('admin', 'admin', 'admin', 'admin', 'admin@cibc.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users (user_id, user_type, first_name, last_name, email, password, create_dt) -VALUES('admin', 'admin', 'admin', 'admin', 'admin@cibc.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992', NOW()); - -INSERT INTO clients (client_id, client_secret, client_type, client_profile, client_name, client_desc, scope, redirect_uri, owner_id, create_dt) -VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'public', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', 'admin', NOW()); +INSERT INTO client (client_id, client_secret, client_type, client_profile, client_name, client_desc, scope, redirect_uri, owner_id) +VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'public', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', 'admin'); -INSERT INTO services (service_id, service_type, service_name, service_desc, scope, owner_id, create_dt) -VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin', NOW()); +INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) +VALUES ('AACT0001', 'openapi', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); diff --git a/db/oracle/config/oauth2-client/cors.yml b/db/oracle/config/oauth2-client/cors.yml new file mode 100644 index 00000000..b83eecdf --- /dev/null +++ b/db/oracle/config/oauth2-client/cors.yml @@ -0,0 +1,13 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +description: Cors Http Handler +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/oracle/config/oauth2-client/oauth/primary.crt b/db/oracle/config/oauth2-client/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/oracle/config/oauth2-client/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-client/oauth/secondary.crt b/db/oracle/config/oauth2-client/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/oracle/config/oauth2-client/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-client/secret.yml b/db/oracle/config/oauth2-client/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/oracle/config/oauth2-client/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/oracle/config/oauth2-client/security.yml b/db/oracle/config/oauth2-client/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/oracle/config/oauth2-client/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/oracle/config/oauth2-client/server.yml b/db/oracle/config/oauth2-client/server.yml new file mode 100644 index 00000000..151859b6 --- /dev/null +++ b/db/oracle/config/oauth2-client/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6884 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6884 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-client-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/oracle/config/oauth2-client/swagger.json b/db/oracle/config/oauth2-client/swagger.json new file mode 100644 index 00000000..1c42a623 --- /dev/null +++ b/db/oracle/config/oauth2-client/swagger.json @@ -0,0 +1,455 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "OAuth2 Client Registration", + "description": "OAuth2 Client Registration microservices endpoints.", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/client": { + "post": { + "description": "Return a client object", + "operationId": "createClient", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Client object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Client" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Client" + } + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "put": { + "description": "Return the updated client", + "operationId": "updateClient", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Client object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Client" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Client" + } + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "get": { + "description": "Return all clients", + "operationId": "getAllClient", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "pageSize", + "in": "query", + "description": "Pag size", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "clientName", + "in": "query", + "description": "Partial clientName for filter", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Client" + } + } + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.r" + ] + } + ] + } + }, + "/oauth2/client/{clientId}": { + "delete": { + "description": "Delete a client by Id", + "operationId": "deleteClient", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid clientId supplied" + }, + "404": { + "description": "Client not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "get": { + "description": "Get a client by Id", + "operationId": "getClient", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Client" + } + }, + "400": { + "description": "Invalid clientId supplied" + }, + "404": { + "description": "Client not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.r", + "oauth.client.w" + ] + } + ] + } + }, + "/oauth2/client/{clientId}/service": { + "delete": { + "description": "Delete all associated services for a client by clientId", + "operationId": "deleteAllClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "get": { + "description": "Get all associated services and endpoints by clientId", + "operationId": "getAllClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.r", + "oauth.client.w" + ] + } + ] + } + }, + "/oauth2/client/{clientId}/service/{serviceId}": { + "post": { + "description": "Link a service and its endpoints to a client", + "operationId": "linkClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "description": "A list of endpoints that needs to be linked to the client", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client or service not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "delete": { + "description": "Delete all endpoints of a service for a client", + "operationId": "deleteClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client or service not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "get": { + "description": "Get linked endpoints of a service from a client", + "operationId": "getClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client or service not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.r", + "oauth.client.w" + ] + } + ] + } + } + }, + "securityDefinitions": { + "client_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.client.w": "write oauth client", + "oauth.client.r": "read oauth client" + } + } + }, + "definitions": { + "Client": { + "type": "object", + "required": [ + "clientType", + "clientProfile", + "clientName", + "clientDesc", + "ownerId", + "scope" + ], + "properties": { + "clientId": { + "type": "string", + "description": "a unique client id" + }, + "clientSecret": { + "type": "string", + "description": "client secret" + }, + "clientType": { + "type": "string", + "description": "client type", + "enum": [ + "confidential", + "public", + "trusted" + ] + }, + "clientProfile": { + "type": "string", + "description": "client profile", + "enum": [ + "webserver", + "browser", + "mobile", + "service", + "batch" + ] + }, + "clientName": { + "type": "string", + "description": "client name" + }, + "clientDesc": { + "type": "string", + "description": "client description" + }, + "ownerId": { + "type": "string", + "description": "client owner id" + }, + "scope": { + "type": "string", + "description": "client scope separated by space" + }, + "redirectUri": { + "type": "string", + "description": "redirect uri" + } + } + } + } +} \ No newline at end of file diff --git a/db/oracle/config/oauth2-client/tls/server.keystore b/db/oracle/config/oauth2-client/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/oracle/config/oauth2-client/tls/server.keystore differ diff --git a/db/oracle/config/oauth2-client/tls/server.truststore b/db/oracle/config/oauth2-client/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/oracle/config/oauth2-client/tls/server.truststore differ diff --git a/db/oracle/config/oauth2-code/cors.yml b/db/oracle/config/oauth2-code/cors.yml new file mode 100644 index 00000000..b83eecdf --- /dev/null +++ b/db/oracle/config/oauth2-code/cors.yml @@ -0,0 +1,13 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +description: Cors Http Handler +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/oracle/config/oauth2-code/jwt.yml b/db/oracle/config/oauth2-code/jwt.yml new file mode 100644 index 00000000..bc7ae31c --- /dev/null +++ b/db/oracle/config/oauth2-code/jwt.yml @@ -0,0 +1,13 @@ +# This is the default JWT configuration and need to be updated when used to issue JWT tokens. It is a component that used to +# issue JWT token. Normally, it should be used by light-oauth2 only but can be used to issue tokens distributely. +--- +# Signature private key that used to sign JWT tokens. +key: + kid: '100' # kid that used to sign the JWT tokens. It will be shown up in the token header. + filename: "/config/oauth/primary.jks" # private key that is used to sign JWT tokens. + password: password # password for the private key. It should be set during deployment time along with pk + keyName: selfsigned # key name that is used to identify the right key in keystore. +issuer: urn:com:networknt:oauth2:v1 # default issuer of the JWT token +audience: urn:com.networknt # default audience of the JWT token +expiredInMinutes: 10 # expired in 10 minutes by default for issued JWT tokens +version: '1.0' # JWT token version diff --git a/db/oracle/config/oauth2-code/oauth/primary.crt b/db/oracle/config/oauth2-code/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/oracle/config/oauth2-code/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-code/oauth/secondary.crt b/db/oracle/config/oauth2-code/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/oracle/config/oauth2-code/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-code/secret.yml b/db/oracle/config/oauth2-code/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/oracle/config/oauth2-code/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/oracle/config/oauth2-code/security.yml b/db/oracle/config/oauth2-code/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/oracle/config/oauth2-code/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/oracle/config/oauth2-code/server.yml b/db/oracle/config/oauth2-code/server.yml new file mode 100644 index 00000000..95816ef8 --- /dev/null +++ b/db/oracle/config/oauth2-code/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6881 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6881 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-code-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/oracle/config/oauth2-code/swagger.json b/db/oracle/config/oauth2-code/swagger.json new file mode 100644 index 00000000..8e24d450 --- /dev/null +++ b/db/oracle/config/oauth2-code/swagger.json @@ -0,0 +1,197 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "OAuth2 Service Authorization Code", + "description": "OAuth2 Service that logs in user and provide authorization code.", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/code": { + "get": { + "description": "Return 302 redirect with authorization code", + "operationId": "getAuthCode", + "parameters": [ + { + "name": "Authorization", + "description": "encoded username:password mandatory if Basic Authentication is used", + "in": "header", + "required": false, + "type": "string" + }, + { + "name": "response_type", + "in": "query", + "description": "The response type for authorization code", + "required": true, + "type": "string", + "enum": [ + "code" + ] + }, + { + "name": "client_id", + "in": "query", + "description": "The client id for authorization code", + "required": true, + "type": "string" + }, + { + "name": "redirect_uri", + "in": "query", + "description": "The redirect uri for authorization code", + "required": false, + "type": "string" + }, + { + "name": "username", + "in": "query", + "description": "The user name for authorization code", + "required": false, + "type": "string" + }, + { + "name": "password", + "in": "query", + "description": "The password for authorization code in clear text", + "required": false, + "type": "string" + }, + { + "name": "state", + "in": "query", + "description": "to prevent cross-site request forgery", + "required": false, + "type": "string" + }, + { + "name": "scope", + "in": "query", + "description": "scope of the request", + "required": false, + "type": "string" + }, + { + "name": "code_challenge", + "in": "query", + "description": "PKCE code challenge", + "required": false, + "type": "string" + }, + { + "name": "code_challenge_method", + "in": "query", + "description": "PKCE code challenge method", + "required": false, + "type": "string" + } + ], + "responses": { + "302": { + "description": "Successful Operation" + } + } + }, + "post": { + "description": "Return 302 redirect with authorization code", + "operationId": "postAuthCode", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "j_username", + "in": "formData", + "description": "User name", + "required": true, + "type": "string" + }, + { + "name": "j_password", + "in": "formData", + "description": "Password", + "required": true, + "type": "string" + }, + { + "name": "response_type", + "in": "formData", + "description": "Response type", + "required": true, + "type": "string", + "enum": [ + "code" + ] + }, + { + "name": "client_id", + "in": "formData", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "redirect_uri", + "in": "formData", + "description": "Redirect Uri", + "required": false, + "type": "string" + }, + { + "name": "state", + "in": "formData", + "description": "to prevent cross-site request forgery", + "required": false, + "type": "string" + }, + { + "name": "scope", + "in": "formData", + "description": "scope of the request", + "required": false, + "type": "string" + }, + { + "name": "code_challenge", + "in": "formData", + "description": "PKCE code challenge", + "required": false, + "type": "string" + }, + { + "name": "code_challenge_method", + "in": "formData", + "description": "PKCE code challenge method", + "required": false, + "type": "string" + } + ], + "responses": { + "302": { + "description": "Successful Operation" + } + } + } + } + } +} \ No newline at end of file diff --git a/db/oracle/config/oauth2-code/tls/server.keystore b/db/oracle/config/oauth2-code/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/oracle/config/oauth2-code/tls/server.keystore differ diff --git a/db/oracle/config/oauth2-code/tls/server.truststore b/db/oracle/config/oauth2-code/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/oracle/config/oauth2-code/tls/server.truststore differ diff --git a/db/oracle/config/oauth2-key/cors.yml b/db/oracle/config/oauth2-key/cors.yml new file mode 100644 index 00000000..b83eecdf --- /dev/null +++ b/db/oracle/config/oauth2-key/cors.yml @@ -0,0 +1,13 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +description: Cors Http Handler +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/oracle/config/oauth2-key/oauth/primary.crt b/db/oracle/config/oauth2-key/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/oracle/config/oauth2-key/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-key/oauth/secondary.crt b/db/oracle/config/oauth2-key/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/oracle/config/oauth2-key/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-key/secret.yml b/db/oracle/config/oauth2-key/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/oracle/config/oauth2-key/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/oracle/config/oauth2-key/security.yml b/db/oracle/config/oauth2-key/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/oracle/config/oauth2-key/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/oracle/config/oauth2-key/server.yml b/db/oracle/config/oauth2-key/server.yml new file mode 100644 index 00000000..454ba61a --- /dev/null +++ b/db/oracle/config/oauth2-key/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6886 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6886 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-key-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/oracle/config/oauth2-key/swagger.json b/db/oracle/config/oauth2-key/swagger.json new file mode 100644 index 00000000..1f8a6c2a --- /dev/null +++ b/db/oracle/config/oauth2-key/swagger.json @@ -0,0 +1,125 @@ +{ + "swagger": "2.0", + "info": { + "description": "OAuth2 Key Service microservices endpoints.", + "version": "1.0.0", + "title": "OAuth2 Key Service", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/key/{keyId}": { + "get": { + "description": "Get a key by Id", + "operationId": "getKeyById", + "parameters": [ + { + "name": "keyId", + "in": "path", + "description": "Key Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Key" + } + }, + "400": { + "description": "Invalid keyId supplied" + }, + "404": { + "description": "Key not found" + } + }, + "security": [ + { + "key_auth": [ + "oauth.key.r", + "oauth.key.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/server/info": { + "get": { + "security": [ + { + "key_auth": [ + "server.info.r" + ] + } + ], + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + }, + "/health": { + "get": { + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + } + }, + "securityDefinitions": { + "key_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.key.w": "write key", + "oauth.key.r": "read key", + "server.info.r": "read server info" + } + } + }, + "definitions": { + "Key": { + "type": "object", + "required": [ + "certificate", + "keyId" + ], + "properties": { + "keyId": { + "type": "string", + "description": "a unique id" + }, + "certificate": { + "type": "string", + "description": "certificate" + } + } + } + } +} \ No newline at end of file diff --git a/db/oracle/config/oauth2-key/tls/server.keystore b/db/oracle/config/oauth2-key/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/oracle/config/oauth2-key/tls/server.keystore differ diff --git a/db/oracle/config/oauth2-key/tls/server.truststore b/db/oracle/config/oauth2-key/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/oracle/config/oauth2-key/tls/server.truststore differ diff --git a/db/oracle/config/oauth2-refresh-token/cors.yml b/db/oracle/config/oauth2-refresh-token/cors.yml new file mode 100644 index 00000000..99437103 --- /dev/null +++ b/db/oracle/config/oauth2-refresh-token/cors.yml @@ -0,0 +1,12 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/oracle/config/oauth2-refresh-token/oauth/primary.crt b/db/oracle/config/oauth2-refresh-token/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/oracle/config/oauth2-refresh-token/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-refresh-token/oauth/secondary.crt b/db/oracle/config/oauth2-refresh-token/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/oracle/config/oauth2-refresh-token/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-refresh-token/primary.crt b/db/oracle/config/oauth2-refresh-token/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/oracle/config/oauth2-refresh-token/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-refresh-token/secret.yml b/db/oracle/config/oauth2-refresh-token/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/oracle/config/oauth2-refresh-token/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/oracle/config/oauth2-refresh-token/security.yml b/db/oracle/config/oauth2-refresh-token/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/oracle/config/oauth2-refresh-token/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/oracle/config/oauth2-refresh-token/server.yml b/db/oracle/config/oauth2-refresh-token/server.yml new file mode 100644 index 00000000..58ec6aec --- /dev/null +++ b/db/oracle/config/oauth2-refresh-token/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6887 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6887 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-refresh-token-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/oracle/config/oauth2-refresh-token/swagger.json b/db/oracle/config/oauth2-refresh-token/swagger.json new file mode 100644 index 00000000..fc2c1fbb --- /dev/null +++ b/db/oracle/config/oauth2-refresh-token/swagger.json @@ -0,0 +1,215 @@ +{ + "swagger": "2.0", + "info": { + "description": "OAuth2 refresh token management microservices endpoints.", + "version": "1.0.0", + "title": "OAuth2 Refresh Token Management", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/refresh_token": { + "get": { + "description": "Return all refresh tokens", + "operationId": "getAllRefreshToken", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "pageSize", + "in": "query", + "description": "Pag size", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "userId", + "in": "query", + "description": "Partial userId for filter", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/RefreshToken" + } + } + } + }, + "security": [ + { + "refresh_token_auth": [ + "oauth.refresh_token.r" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/oauth2/refresh_token/{refreshToken}": { + "get": { + "description": "Get a refresh token", + "operationId": "getRefreshToken", + "parameters": [ + { + "name": "refreshToken", + "in": "path", + "description": "Refresh token", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/RefreshToken" + } + }, + "400": { + "description": "Invalid refresh token supplied" + }, + "404": { + "description": "Refresh token not found" + } + }, + "security": [ + { + "refresh_token_auth": [ + "oauth.refresh_token.r", + "oauth.refresh_token.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + }, + "delete": { + "description": "Delete a refresh token", + "operationId": "deleteRefreshToken", + "parameters": [ + { + "name": "refreshToken", + "in": "path", + "description": "Refresh Token", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid refresh token supplied" + }, + "404": { + "description": "Refresh token not found" + } + }, + "security": [ + { + "refresh_token_auth": [ + "oauth.refresh_token.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/server/info": { + "get": { + "security": [ + { + "refresh_token_auth": [ + "server.info.r" + ] + } + ], + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + }, + "/health": { + "get": { + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + } + }, + "securityDefinitions": { + "refresh_token_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.refresh_token.w": "write oauth refresh token", + "oauth.refresh_token.r": "read oauth refresh token", + "server.info.r": "read server info" + } + } + }, + "definitions": { + "RefreshToken": { + "type": "object", + "required": [ + "clientId", + "refreshToken", + "userId" + ], + "properties": { + "refreshToken": { + "type": "string", + "description": "refresh token" + }, + "userId": { + "type": "string", + "description": "user id" + }, + "clientId": { + "type": "string", + "description": "client id" + }, + "scope": { + "type": "string", + "description": "service scopes separated by space" + } + } + } + } +} \ No newline at end of file diff --git a/db/oracle/config/oauth2-refresh-token/tls/server.keystore b/db/oracle/config/oauth2-refresh-token/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/oracle/config/oauth2-refresh-token/tls/server.keystore differ diff --git a/db/oracle/config/oauth2-refresh-token/tls/server.truststore b/db/oracle/config/oauth2-refresh-token/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/oracle/config/oauth2-refresh-token/tls/server.truststore differ diff --git a/db/oracle/config/oauth2-service/cors.yml b/db/oracle/config/oauth2-service/cors.yml new file mode 100644 index 00000000..99437103 --- /dev/null +++ b/db/oracle/config/oauth2-service/cors.yml @@ -0,0 +1,12 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/oracle/config/oauth2-service/oauth/primary.crt b/db/oracle/config/oauth2-service/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/oracle/config/oauth2-service/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-service/oauth/secondary.crt b/db/oracle/config/oauth2-service/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/oracle/config/oauth2-service/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-service/primary.crt b/db/oracle/config/oauth2-service/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/oracle/config/oauth2-service/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-service/secret.yml b/db/oracle/config/oauth2-service/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/oracle/config/oauth2-service/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/oracle/config/oauth2-service/security.yml b/db/oracle/config/oauth2-service/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/oracle/config/oauth2-service/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/oracle/config/oauth2-service/server.yml b/db/oracle/config/oauth2-service/server.yml new file mode 100644 index 00000000..ff558b00 --- /dev/null +++ b/db/oracle/config/oauth2-service/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6883 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6883 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-service-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/oracle/config/oauth2-service/swagger.json b/db/oracle/config/oauth2-service/swagger.json new file mode 100644 index 00000000..c51d14a3 --- /dev/null +++ b/db/oracle/config/oauth2-service/swagger.json @@ -0,0 +1,393 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "OAuth2 Service Registration", + "description": "OAuth2 Service Registration microservices endpoints.", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/service": { + "post": { + "description": "Return a service object", + "operationId": "createService", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Service object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Service" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Service" + } + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "put": { + "description": "Return the updated service", + "operationId": "updateService", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Service object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Service" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Service" + } + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "get": { + "description": "Return all services", + "operationId": "getAllService", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "pageSize", + "in": "query", + "description": "Pag size", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "serviceId", + "in": "query", + "description": "Partial serviceId for filter", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Service" + } + } + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.r" + ] + } + ] + } + }, + "/oauth2/service/{serviceId}": { + "delete": { + "description": "Delete a service by Id", + "operationId": "deleteService", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "Service not found" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "get": { + "description": "Get a service by Id", + "operationId": "getService", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Service" + } + }, + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "Service not found" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.r", + "oauth.service.w" + ] + } + ] + } + }, + "/oauth2/service/{serviceId}/endpoint": { + "post": { + "description": "create endpoints for service", + "operationId": "createServiceEndpoint", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "A list of endpoint object", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ServiceEndpoint" + } + } + } + ], + "responses": { + "201": { + "description": "Successful response" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "delete": { + "description": "Delete all endpoints for a service", + "operationId": "deleteServiceEndpoint", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "Service not found" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "get": { + "description": "Get all endpoints for a service", + "operationId": "getServiceEndpoint", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ServiceEndpoint" + } + } + }, + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "ServiceEndpoint not found" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.r", + "oauth.service.w" + ] + } + ] + } + } + }, + "securityDefinitions": { + "service_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.service.w": "write oauth service", + "oauth.service.r": "read oauth service" + } + } + }, + "definitions": { + "Service": { + "type": "object", + "required": [ + "serviceId", + "serviceName", + "serviceType", + "scope" + ], + "properties": { + "serviceId": { + "type": "string", + "description": "a unique service id" + }, + "serviceType": { + "type": "string", + "description": "service type", + "enum": [ + "swagger", + "openapi", + "graphql", + "hybrid" + ] + }, + "serviceName": { + "type": "string", + "description": "service name" + }, + "serviceDesc": { + "type": "string", + "description": "service description" + }, + "ownerId": { + "type": "string", + "description": "service owner userId" + }, + "scope": { + "type": "string", + "description": "service scopes separated by space" + }, + "createDt": { + "type": "string", + "format": "date-time", + "description": "create date time" + }, + "updateDt": { + "type": "string", + "format": "date-time", + "description": "update date time" + } + } + }, + "ServiceEndpoint": { + "type": "object", + "required": [ + "endpoint", + "operation", + "scope" + ], + "properties": { + "endpoint": { + "type": "string", + "description": "a combination of path and method to uniquely identify an operation" + }, + "operation": { + "type": "string", + "description": "operationId of the endpoint" + }, + "scope": { + "type": "string", + "description": "scope associated with the endpoint" + } + } + } + } +} \ No newline at end of file diff --git a/db/oracle/config/oauth2-service/tls/server.keystore b/db/oracle/config/oauth2-service/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/oracle/config/oauth2-service/tls/server.keystore differ diff --git a/db/oracle/config/oauth2-service/tls/server.truststore b/db/oracle/config/oauth2-service/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/oracle/config/oauth2-service/tls/server.truststore differ diff --git a/db/oracle/config/oauth2-token/cors.yml b/db/oracle/config/oauth2-token/cors.yml new file mode 100644 index 00000000..b83eecdf --- /dev/null +++ b/db/oracle/config/oauth2-token/cors.yml @@ -0,0 +1,13 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +description: Cors Http Handler +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/oracle/config/oauth2-token/jwt.yml b/db/oracle/config/oauth2-token/jwt.yml new file mode 100644 index 00000000..bc7ae31c --- /dev/null +++ b/db/oracle/config/oauth2-token/jwt.yml @@ -0,0 +1,13 @@ +# This is the default JWT configuration and need to be updated when used to issue JWT tokens. It is a component that used to +# issue JWT token. Normally, it should be used by light-oauth2 only but can be used to issue tokens distributely. +--- +# Signature private key that used to sign JWT tokens. +key: + kid: '100' # kid that used to sign the JWT tokens. It will be shown up in the token header. + filename: "/config/oauth/primary.jks" # private key that is used to sign JWT tokens. + password: password # password for the private key. It should be set during deployment time along with pk + keyName: selfsigned # key name that is used to identify the right key in keystore. +issuer: urn:com:networknt:oauth2:v1 # default issuer of the JWT token +audience: urn:com.networknt # default audience of the JWT token +expiredInMinutes: 10 # expired in 10 minutes by default for issued JWT tokens +version: '1.0' # JWT token version diff --git a/db/oracle/config/oauth2-token/oauth/primary.crt b/db/oracle/config/oauth2-token/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/oracle/config/oauth2-token/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-token/oauth/primary.jks b/db/oracle/config/oauth2-token/oauth/primary.jks new file mode 100644 index 00000000..0d6ae7cf Binary files /dev/null and b/db/oracle/config/oauth2-token/oauth/primary.jks differ diff --git a/db/oracle/config/oauth2-token/oauth/secondary.crt b/db/oracle/config/oauth2-token/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/oracle/config/oauth2-token/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-token/oauth/secondary.jks b/db/oracle/config/oauth2-token/oauth/secondary.jks new file mode 100644 index 00000000..33824c89 Binary files /dev/null and b/db/oracle/config/oauth2-token/oauth/secondary.jks differ diff --git a/db/oracle/config/oauth2-token/secret.yml b/db/oracle/config/oauth2-token/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/oracle/config/oauth2-token/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/oracle/config/oauth2-token/security.yml b/db/oracle/config/oauth2-token/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/oracle/config/oauth2-token/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/oracle/config/oauth2-token/server.yml b/db/oracle/config/oauth2-token/server.yml new file mode 100644 index 00000000..2a414220 --- /dev/null +++ b/db/oracle/config/oauth2-token/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6882 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6882 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-token-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/oracle/config/oauth2-token/swagger.json b/db/oracle/config/oauth2-token/swagger.json new file mode 100644 index 00000000..b56f7433 --- /dev/null +++ b/db/oracle/config/oauth2-token/swagger.json @@ -0,0 +1,125 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "OAuth2 Service Token Service", + "description": "OAuth2 Service that issues access tokens.", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/x-www-form-urlencoded" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/token": { + "post": { + "description": "JSON object that contains access token", + "operationId": "postToken", + "parameters": [ + { + "name": "authorization", + "description": "encoded client_id and client_secret pair", + "in": "header", + "type": "string", + "required": false + }, + { + "name": "grant_type", + "type": "string", + "enum": [ + "authorization_code", + "client_credentials", + "password", + "refresh_token", + "client_authenticated_user" + ], + "required": true, + "in": "formData" + }, + { + "name": "client_id", + "description": "used as alternative to authentication header for client authentication", + "type": "string", + "in": "formData" + }, + { + "name": "client_secret", + "description": "used as alternative to authentication header for client authentication", + "type": "string", + "in": "formData" + }, + { + "name": "code", + "description": "used in authorization_code to specify the code", + "type": "string", + "in": "formData" + }, + { + "name": "username", + "description": "mandatory in password grant type", + "type": "string", + "in": "formData" + }, + { + "name": "password", + "description": "mandatory in password grant type", + "type": "string", + "in": "formData" + }, + { + "name": "scope", + "description": "used by all flows to specify scope in the access token", + "type": "string", + "in": "formData" + }, + { + "name": "redirect_uri", + "description": "used in authorization code if code endpoint with rediret_uri", + "type": "string", + "in": "formData" + }, + { + "name": "refresh_token", + "description": "refresh token used to get another access token", + "type": "string", + "in": "formData" + }, + { + "name": "code_verifier", + "description": "PKCE code verifier", + "type": "string", + "in": "formData" + } + ], + "responses": { + "200": { + "description": "Successful Operation" + } + } + } + }, + "/health": { + "get": { + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + } + } +} diff --git a/db/oracle/config/oauth2-token/tls/server.keystore b/db/oracle/config/oauth2-token/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/oracle/config/oauth2-token/tls/server.keystore differ diff --git a/db/oracle/config/oauth2-token/tls/server.truststore b/db/oracle/config/oauth2-token/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/oracle/config/oauth2-token/tls/server.truststore differ diff --git a/db/oracle/config/oauth2-user/cors.yml b/db/oracle/config/oauth2-user/cors.yml new file mode 100644 index 00000000..99437103 --- /dev/null +++ b/db/oracle/config/oauth2-user/cors.yml @@ -0,0 +1,12 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/oracle/config/oauth2-user/oauth/primary.crt b/db/oracle/config/oauth2-user/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/oracle/config/oauth2-user/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-user/oauth/secondary.crt b/db/oracle/config/oauth2-user/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/oracle/config/oauth2-user/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/oracle/config/oauth2-user/secret.yml b/db/oracle/config/oauth2-user/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/oracle/config/oauth2-user/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/oracle/config/oauth2-user/security.yml b/db/oracle/config/oauth2-user/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/oracle/config/oauth2-user/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/oracle/config/oauth2-user/server.yml b/db/oracle/config/oauth2-user/server.yml new file mode 100644 index 00000000..8718d5a6 --- /dev/null +++ b/db/oracle/config/oauth2-user/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6885 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6885 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-user-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/oracle/config/oauth2-user/swagger.json b/db/oracle/config/oauth2-user/swagger.json new file mode 100644 index 00000000..9717cc2a --- /dev/null +++ b/db/oracle/config/oauth2-user/swagger.json @@ -0,0 +1,368 @@ +{ + "swagger": "2.0", + "info": { + "description": "OAuth2 User Service microservices endpoints.", + "version": "1.0.0", + "title": "OAuth2 User Service", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/password/{userId}": { + "post": { + "description": "Reset Password", + "operationId": "resetPassword", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Password object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Password" + } + }, + { + "name": "userId", + "in": "path", + "description": "User Id", + "required": true, + "type": "string" + } + ], + "responses": { + "404": { + "description": "User not found" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/oauth2/user": { + "get": { + "description": "Return all users", + "operationId": "getAllUsers", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "pageSize", + "in": "query", + "description": "Pag size", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "userId", + "in": "query", + "description": "Partial userId for filter", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/User" + } + } + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.r" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + }, + "post": { + "description": "Return a user object", + "operationId": "createUser", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "User object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/User" + } + } + ], + "responses": { + "200": { + "description": "Successful response" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + }, + "put": { + "description": "Return the updated user", + "operationId": "updateUser", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "User object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/User" + } + } + ], + "responses": { + "200": { + "description": "Successful response" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/oauth2/user/{userId}": { + "get": { + "description": "Get a user by Id", + "operationId": "getUser", + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "User Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/User" + } + }, + "400": { + "description": "Invalid userId supplied" + }, + "404": { + "description": "User not found" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.r", + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + }, + "delete": { + "description": "Delete a user by Id", + "operationId": "deleteUser", + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "User Id", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid userId supplied" + }, + "404": { + "description": "User not found" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/server/info": { + "get": { + "security": [ + { + "service_auth": [ + "server.info.r" + ] + } + ], + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + }, + "/health": { + "get": { + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + } + }, + "securityDefinitions": { + "user_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.user.w": "write user", + "oauth.user.r": "read user", + "server.info.r": "read server info" + } + } + }, + "definitions": { + "User": { + "type": "object", + "required": [ + "email", + "firstName", + "lastName", + "userId", + "userType" + ], + "properties": { + "userId": { + "type": "string", + "description": "a unique id" + }, + "userType": { + "type": "string", + "description": "user type", + "enum": [ + "admin", + "employee", + "customer", + "partner" + ] + }, + "firstName": { + "type": "string", + "description": "first name" + }, + "lastName": { + "type": "string", + "description": "last name" + }, + "email": { + "type": "string", + "description": "email address" + }, + "password": { + "type": "string", + "format": "password", + "description": "password" + }, + "passwordConfirm": { + "type": "string", + "format": "password", + "description": "password confirm" + }, + "createDt": { + "type": "string", + "format": "date-time", + "description": "create date time" + }, + "updateDt": { + "type": "string", + "format": "date-time", + "description": "update date time" + } + } + }, + "Password": { + "type": "object", + "required": [ + "newPassword", + "newPasswordConfirm", + "password" + ], + "properties": { + "password": { + "type": "string", + "format": "password", + "description": "existing password" + }, + "newPassword": { + "type": "string", + "format": "password", + "description": "new password" + }, + "newPasswordConfirm": { + "type": "string", + "format": "password", + "description": "new password confirm" + } + } + } + } +} \ No newline at end of file diff --git a/db/oracle/config/oauth2-user/tls/server.keystore b/db/oracle/config/oauth2-user/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/oracle/config/oauth2-user/tls/server.keystore differ diff --git a/db/oracle/config/oauth2-user/tls/server.truststore b/db/oracle/config/oauth2-user/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/oracle/config/oauth2-user/tls/server.truststore differ diff --git a/db/oracle/create_oracle.sql b/db/oracle/create_oracle.sql index 535e9b37..2bae362e 100644 --- a/db/oracle/create_oracle.sql +++ b/db/oracle/create_oracle.sql @@ -1,60 +1,88 @@ -DROP TABLE users CASCADE CONSTRAINTS; -CREATE TABLE users ( +DROP TABLE user_profile CASCADE CONSTRAINTS; +CREATE TABLE user_profile ( user_id VARCHAR2(32) NOT NULL, user_type VARCHAR2(16) NOT NULL, -- admin, customer, employee, partner first_name VARCHAR2(32) NOT NULL, last_name VARCHAR2(32) NOT NULL, email VARCHAR2(64) NOT NULL, password VARCHAR2(1024) NOT NULL, - create_dt DATE NOT NULL, - update_dt DATE, - CONSTRAINT users_pk PRIMARY KEY (user_id) + CONSTRAINT user_profile_pk PRIMARY KEY (user_id) ); -CREATE UNIQUE INDEX email_idx ON users(email); +CREATE UNIQUE INDEX email_idx ON user_profile(email); -DROP TABLE clients CASCADE CONSTRAINTS; -CREATE TABLE clients ( +DROP TABLE client CASCADE CONSTRAINTS; +CREATE TABLE client ( client_id VARCHAR2(36) NOT NULL, client_type VARCHAR2(12) NOT NULL, -- public, confidential, trusted client_profile VARCHAR2(10) NOT NULL, -- webserver, mobile, browser, service, batch client_secret VARCHAR2(1024) NOT NULL, client_name VARCHAR2(32) NOT NULL, client_desc VARCHAR2(2048), - scope VARCHAR2(1024), + scope VARCHAR2(4000), redirect_uri VARCHAR2(1024), authenticate_class VARCHAR2(256), owner_id VARCHAR2(32) NOT NULL, - create_dt DATE NOT NULL, - update_dt DATE, - CONSTRAINT clients_pk PRIMARY KEY (client_id), - CONSTRAINT clients_users_fk + CONSTRAINT client_pk PRIMARY KEY (client_id), + CONSTRAINT client_user_fk FOREIGN KEY (owner_id) - REFERENCES users(user_id) + REFERENCES user_profile(user_id) ); -DROP TABLE services CASCADE CONSTRAINTS; -CREATE TABLE services ( +DROP TABLE service CASCADE CONSTRAINTS; +CREATE TABLE service ( service_id VARCHAR2(32) NOT NULL, - service_type VARCHAR2(8) NOT NULL, -- api, ms + service_type VARCHAR2(16) NOT NULL, -- swagger, openapi, graphql, hybrid service_name VARCHAR2(32) NOT NULL, service_desc VARCHAR2(1024), scope VARCHAR2(1024), owner_id VARCHAR2(32) NOT NULL, - create_dt DATE NOT NULL, - update_dt DATE, - CONSTRAINT services_pk PRIMARY KEY (service_id), - CONSTRAINT services_users_fk + CONSTRAINT service_pk PRIMARY KEY (service_id), + CONSTRAINT service_user_fk FOREIGN KEY (owner_id) - REFERENCES users(user_id) + REFERENCES user_profile(user_id) +); + +DROP TABLE service_endpoint CASCADE CONSTRAINTS; +CREATE TABLE service_endpoint ( + service_id VARCHAR2(32) NOT NULL, + endpoint VARCHAR2(256) NOT NULL, -- different framework will have different endpoint format. + operation VARCHAR2(256) NOT NULL, + scope VARCHAR2(64) NOT NULL, + CONSTRAINT service_endpoint_pk PRIMARY KEY (service_id, endpoint), + CONSTRAINT service_endpoint_service_fk FOREIGN KEY (service_id) REFERENCES service(service_id) ); -INSERT INTO users (user_id, user_type, first_name, last_name, email, password, create_dt) -VALUES('admin', 'admin', 'admin', 'admin', 'admin@cibc.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992', SYSDATE); +DROP TABLE client_service CASCADE CONSTRAINTS; +CREATE TABLE client_service ( + client_id VARCHAR2(36) NOT NULL, + service_id VARCHAR2(32) NOT NULL, + endpoint VARCHAR2(256) NOT NULL, -- different framework will have different endpoint format. + CONSTRAINT client_service_pk PRIMARY KEY (client_id, service_id, endpoint), + CONSTRAINT client_service_endpoint_fk FOREIGN KEY (service_id, endpoint) REFERENCES service_endpoint(service_id, endpoint), + CONSTRAINT client_service_client_fk FOREIGN KEY (client_id) REFERENCES client(client_id) +); + +DROP TABLE audit_log CASCADE CONSTRAINTS; +create table audit_log ( + log_id INT, -- system milliseonds from 1970. + service_id VARCHAR2(32) NOT NULL, + endpoint VARCHAR2(256) NOT NULL, + request_header VARCHAR2(4000), + request_body VARCHAR2(4000), + response_code INT, + response_header VARCHAR2(4000), + response_body VARCHAR2(4000) +); + + + +INSERT INTO user_profile (user_id, user_type, first_name, last_name, email, password) +VALUES('admin', 'admin', 'admin', 'admin', 'admin@cibc.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO clients (client_id, client_secret, client_type, client_profile, client_name, client_desc, scope, redirect_uri, owner_id, create_dt) -VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'public', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', 'admin', SYSDATE); +INSERT INTO client (client_id, client_secret, client_type, client_profile, client_name, client_desc, scope, redirect_uri, owner_id) +VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'public', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', 'admin'); -INSERT INTO services (service_id, service_type, service_name, service_desc, scope, owner_id, create_dt) -VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin', SYSDATE); +INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) +VALUES ('AACT0001', 'openapi', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); diff --git a/db/postgres/config/oauth2-client/cors.yml b/db/postgres/config/oauth2-client/cors.yml new file mode 100644 index 00000000..b83eecdf --- /dev/null +++ b/db/postgres/config/oauth2-client/cors.yml @@ -0,0 +1,13 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +description: Cors Http Handler +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/postgres/config/oauth2-client/oauth/primary.crt b/db/postgres/config/oauth2-client/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/postgres/config/oauth2-client/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-client/oauth/secondary.crt b/db/postgres/config/oauth2-client/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/postgres/config/oauth2-client/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-client/secret.yml b/db/postgres/config/oauth2-client/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/postgres/config/oauth2-client/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/postgres/config/oauth2-client/security.yml b/db/postgres/config/oauth2-client/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/postgres/config/oauth2-client/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/postgres/config/oauth2-client/server.yml b/db/postgres/config/oauth2-client/server.yml new file mode 100644 index 00000000..151859b6 --- /dev/null +++ b/db/postgres/config/oauth2-client/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6884 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6884 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-client-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/postgres/config/oauth2-client/swagger.json b/db/postgres/config/oauth2-client/swagger.json new file mode 100644 index 00000000..1c42a623 --- /dev/null +++ b/db/postgres/config/oauth2-client/swagger.json @@ -0,0 +1,455 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "OAuth2 Client Registration", + "description": "OAuth2 Client Registration microservices endpoints.", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/client": { + "post": { + "description": "Return a client object", + "operationId": "createClient", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Client object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Client" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Client" + } + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "put": { + "description": "Return the updated client", + "operationId": "updateClient", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Client object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Client" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Client" + } + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "get": { + "description": "Return all clients", + "operationId": "getAllClient", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "pageSize", + "in": "query", + "description": "Pag size", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "clientName", + "in": "query", + "description": "Partial clientName for filter", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Client" + } + } + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.r" + ] + } + ] + } + }, + "/oauth2/client/{clientId}": { + "delete": { + "description": "Delete a client by Id", + "operationId": "deleteClient", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid clientId supplied" + }, + "404": { + "description": "Client not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "get": { + "description": "Get a client by Id", + "operationId": "getClient", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Client" + } + }, + "400": { + "description": "Invalid clientId supplied" + }, + "404": { + "description": "Client not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.r", + "oauth.client.w" + ] + } + ] + } + }, + "/oauth2/client/{clientId}/service": { + "delete": { + "description": "Delete all associated services for a client by clientId", + "operationId": "deleteAllClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "get": { + "description": "Get all associated services and endpoints by clientId", + "operationId": "getAllClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.r", + "oauth.client.w" + ] + } + ] + } + }, + "/oauth2/client/{clientId}/service/{serviceId}": { + "post": { + "description": "Link a service and its endpoints to a client", + "operationId": "linkClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + }, + { + "name": "body", + "in": "body", + "description": "A list of endpoints that needs to be linked to the client", + "required": true, + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client or service not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "delete": { + "description": "Delete all endpoints of a service for a client", + "operationId": "deleteClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client or service not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.w" + ] + } + ] + }, + "get": { + "description": "Get linked endpoints of a service from a client", + "operationId": "getClientService", + "parameters": [ + { + "name": "clientId", + "in": "path", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response" + }, + "404": { + "description": "Client or service not found" + } + }, + "security": [ + { + "client_auth": [ + "oauth.client.r", + "oauth.client.w" + ] + } + ] + } + } + }, + "securityDefinitions": { + "client_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.client.w": "write oauth client", + "oauth.client.r": "read oauth client" + } + } + }, + "definitions": { + "Client": { + "type": "object", + "required": [ + "clientType", + "clientProfile", + "clientName", + "clientDesc", + "ownerId", + "scope" + ], + "properties": { + "clientId": { + "type": "string", + "description": "a unique client id" + }, + "clientSecret": { + "type": "string", + "description": "client secret" + }, + "clientType": { + "type": "string", + "description": "client type", + "enum": [ + "confidential", + "public", + "trusted" + ] + }, + "clientProfile": { + "type": "string", + "description": "client profile", + "enum": [ + "webserver", + "browser", + "mobile", + "service", + "batch" + ] + }, + "clientName": { + "type": "string", + "description": "client name" + }, + "clientDesc": { + "type": "string", + "description": "client description" + }, + "ownerId": { + "type": "string", + "description": "client owner id" + }, + "scope": { + "type": "string", + "description": "client scope separated by space" + }, + "redirectUri": { + "type": "string", + "description": "redirect uri" + } + } + } + } +} \ No newline at end of file diff --git a/db/postgres/config/oauth2-client/tls/server.keystore b/db/postgres/config/oauth2-client/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/postgres/config/oauth2-client/tls/server.keystore differ diff --git a/db/postgres/config/oauth2-client/tls/server.truststore b/db/postgres/config/oauth2-client/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/postgres/config/oauth2-client/tls/server.truststore differ diff --git a/db/postgres/config/oauth2-code/cors.yml b/db/postgres/config/oauth2-code/cors.yml new file mode 100644 index 00000000..b83eecdf --- /dev/null +++ b/db/postgres/config/oauth2-code/cors.yml @@ -0,0 +1,13 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +description: Cors Http Handler +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/postgres/config/oauth2-code/jwt.yml b/db/postgres/config/oauth2-code/jwt.yml new file mode 100644 index 00000000..bc7ae31c --- /dev/null +++ b/db/postgres/config/oauth2-code/jwt.yml @@ -0,0 +1,13 @@ +# This is the default JWT configuration and need to be updated when used to issue JWT tokens. It is a component that used to +# issue JWT token. Normally, it should be used by light-oauth2 only but can be used to issue tokens distributely. +--- +# Signature private key that used to sign JWT tokens. +key: + kid: '100' # kid that used to sign the JWT tokens. It will be shown up in the token header. + filename: "/config/oauth/primary.jks" # private key that is used to sign JWT tokens. + password: password # password for the private key. It should be set during deployment time along with pk + keyName: selfsigned # key name that is used to identify the right key in keystore. +issuer: urn:com:networknt:oauth2:v1 # default issuer of the JWT token +audience: urn:com.networknt # default audience of the JWT token +expiredInMinutes: 10 # expired in 10 minutes by default for issued JWT tokens +version: '1.0' # JWT token version diff --git a/db/postgres/config/oauth2-code/oauth/primary.crt b/db/postgres/config/oauth2-code/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/postgres/config/oauth2-code/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-code/oauth/secondary.crt b/db/postgres/config/oauth2-code/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/postgres/config/oauth2-code/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-code/secret.yml b/db/postgres/config/oauth2-code/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/postgres/config/oauth2-code/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/postgres/config/oauth2-code/security.yml b/db/postgres/config/oauth2-code/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/postgres/config/oauth2-code/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/postgres/config/oauth2-code/server.yml b/db/postgres/config/oauth2-code/server.yml new file mode 100644 index 00000000..95816ef8 --- /dev/null +++ b/db/postgres/config/oauth2-code/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6881 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6881 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-code-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/postgres/config/oauth2-code/swagger.json b/db/postgres/config/oauth2-code/swagger.json new file mode 100644 index 00000000..8e24d450 --- /dev/null +++ b/db/postgres/config/oauth2-code/swagger.json @@ -0,0 +1,197 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "OAuth2 Service Authorization Code", + "description": "OAuth2 Service that logs in user and provide authorization code.", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/code": { + "get": { + "description": "Return 302 redirect with authorization code", + "operationId": "getAuthCode", + "parameters": [ + { + "name": "Authorization", + "description": "encoded username:password mandatory if Basic Authentication is used", + "in": "header", + "required": false, + "type": "string" + }, + { + "name": "response_type", + "in": "query", + "description": "The response type for authorization code", + "required": true, + "type": "string", + "enum": [ + "code" + ] + }, + { + "name": "client_id", + "in": "query", + "description": "The client id for authorization code", + "required": true, + "type": "string" + }, + { + "name": "redirect_uri", + "in": "query", + "description": "The redirect uri for authorization code", + "required": false, + "type": "string" + }, + { + "name": "username", + "in": "query", + "description": "The user name for authorization code", + "required": false, + "type": "string" + }, + { + "name": "password", + "in": "query", + "description": "The password for authorization code in clear text", + "required": false, + "type": "string" + }, + { + "name": "state", + "in": "query", + "description": "to prevent cross-site request forgery", + "required": false, + "type": "string" + }, + { + "name": "scope", + "in": "query", + "description": "scope of the request", + "required": false, + "type": "string" + }, + { + "name": "code_challenge", + "in": "query", + "description": "PKCE code challenge", + "required": false, + "type": "string" + }, + { + "name": "code_challenge_method", + "in": "query", + "description": "PKCE code challenge method", + "required": false, + "type": "string" + } + ], + "responses": { + "302": { + "description": "Successful Operation" + } + } + }, + "post": { + "description": "Return 302 redirect with authorization code", + "operationId": "postAuthCode", + "consumes": [ + "application/x-www-form-urlencoded" + ], + "produces": [ + "application/json" + ], + "parameters": [ + { + "name": "j_username", + "in": "formData", + "description": "User name", + "required": true, + "type": "string" + }, + { + "name": "j_password", + "in": "formData", + "description": "Password", + "required": true, + "type": "string" + }, + { + "name": "response_type", + "in": "formData", + "description": "Response type", + "required": true, + "type": "string", + "enum": [ + "code" + ] + }, + { + "name": "client_id", + "in": "formData", + "description": "Client Id", + "required": true, + "type": "string" + }, + { + "name": "redirect_uri", + "in": "formData", + "description": "Redirect Uri", + "required": false, + "type": "string" + }, + { + "name": "state", + "in": "formData", + "description": "to prevent cross-site request forgery", + "required": false, + "type": "string" + }, + { + "name": "scope", + "in": "formData", + "description": "scope of the request", + "required": false, + "type": "string" + }, + { + "name": "code_challenge", + "in": "formData", + "description": "PKCE code challenge", + "required": false, + "type": "string" + }, + { + "name": "code_challenge_method", + "in": "formData", + "description": "PKCE code challenge method", + "required": false, + "type": "string" + } + ], + "responses": { + "302": { + "description": "Successful Operation" + } + } + } + } + } +} \ No newline at end of file diff --git a/db/postgres/config/oauth2-code/tls/server.keystore b/db/postgres/config/oauth2-code/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/postgres/config/oauth2-code/tls/server.keystore differ diff --git a/db/postgres/config/oauth2-code/tls/server.truststore b/db/postgres/config/oauth2-code/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/postgres/config/oauth2-code/tls/server.truststore differ diff --git a/db/postgres/config/oauth2-key/cors.yml b/db/postgres/config/oauth2-key/cors.yml new file mode 100644 index 00000000..b83eecdf --- /dev/null +++ b/db/postgres/config/oauth2-key/cors.yml @@ -0,0 +1,13 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +description: Cors Http Handler +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/postgres/config/oauth2-key/oauth/primary.crt b/db/postgres/config/oauth2-key/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/postgres/config/oauth2-key/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-key/oauth/secondary.crt b/db/postgres/config/oauth2-key/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/postgres/config/oauth2-key/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-key/secret.yml b/db/postgres/config/oauth2-key/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/postgres/config/oauth2-key/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/postgres/config/oauth2-key/security.yml b/db/postgres/config/oauth2-key/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/postgres/config/oauth2-key/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/postgres/config/oauth2-key/server.yml b/db/postgres/config/oauth2-key/server.yml new file mode 100644 index 00000000..454ba61a --- /dev/null +++ b/db/postgres/config/oauth2-key/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6886 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6886 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-key-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/postgres/config/oauth2-key/swagger.json b/db/postgres/config/oauth2-key/swagger.json new file mode 100644 index 00000000..1f8a6c2a --- /dev/null +++ b/db/postgres/config/oauth2-key/swagger.json @@ -0,0 +1,125 @@ +{ + "swagger": "2.0", + "info": { + "description": "OAuth2 Key Service microservices endpoints.", + "version": "1.0.0", + "title": "OAuth2 Key Service", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/key/{keyId}": { + "get": { + "description": "Get a key by Id", + "operationId": "getKeyById", + "parameters": [ + { + "name": "keyId", + "in": "path", + "description": "Key Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Key" + } + }, + "400": { + "description": "Invalid keyId supplied" + }, + "404": { + "description": "Key not found" + } + }, + "security": [ + { + "key_auth": [ + "oauth.key.r", + "oauth.key.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/server/info": { + "get": { + "security": [ + { + "key_auth": [ + "server.info.r" + ] + } + ], + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + }, + "/health": { + "get": { + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + } + }, + "securityDefinitions": { + "key_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.key.w": "write key", + "oauth.key.r": "read key", + "server.info.r": "read server info" + } + } + }, + "definitions": { + "Key": { + "type": "object", + "required": [ + "certificate", + "keyId" + ], + "properties": { + "keyId": { + "type": "string", + "description": "a unique id" + }, + "certificate": { + "type": "string", + "description": "certificate" + } + } + } + } +} \ No newline at end of file diff --git a/db/postgres/config/oauth2-key/tls/server.keystore b/db/postgres/config/oauth2-key/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/postgres/config/oauth2-key/tls/server.keystore differ diff --git a/db/postgres/config/oauth2-key/tls/server.truststore b/db/postgres/config/oauth2-key/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/postgres/config/oauth2-key/tls/server.truststore differ diff --git a/db/postgres/config/oauth2-refresh-token/cors.yml b/db/postgres/config/oauth2-refresh-token/cors.yml new file mode 100644 index 00000000..99437103 --- /dev/null +++ b/db/postgres/config/oauth2-refresh-token/cors.yml @@ -0,0 +1,12 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/postgres/config/oauth2-refresh-token/oauth/primary.crt b/db/postgres/config/oauth2-refresh-token/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/postgres/config/oauth2-refresh-token/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-refresh-token/oauth/secondary.crt b/db/postgres/config/oauth2-refresh-token/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/postgres/config/oauth2-refresh-token/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-refresh-token/primary.crt b/db/postgres/config/oauth2-refresh-token/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/postgres/config/oauth2-refresh-token/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-refresh-token/secret.yml b/db/postgres/config/oauth2-refresh-token/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/postgres/config/oauth2-refresh-token/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/postgres/config/oauth2-refresh-token/security.yml b/db/postgres/config/oauth2-refresh-token/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/postgres/config/oauth2-refresh-token/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/postgres/config/oauth2-refresh-token/server.yml b/db/postgres/config/oauth2-refresh-token/server.yml new file mode 100644 index 00000000..58ec6aec --- /dev/null +++ b/db/postgres/config/oauth2-refresh-token/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6887 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6887 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-refresh-token-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/postgres/config/oauth2-refresh-token/swagger.json b/db/postgres/config/oauth2-refresh-token/swagger.json new file mode 100644 index 00000000..fc2c1fbb --- /dev/null +++ b/db/postgres/config/oauth2-refresh-token/swagger.json @@ -0,0 +1,215 @@ +{ + "swagger": "2.0", + "info": { + "description": "OAuth2 refresh token management microservices endpoints.", + "version": "1.0.0", + "title": "OAuth2 Refresh Token Management", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/refresh_token": { + "get": { + "description": "Return all refresh tokens", + "operationId": "getAllRefreshToken", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "pageSize", + "in": "query", + "description": "Pag size", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "userId", + "in": "query", + "description": "Partial userId for filter", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/RefreshToken" + } + } + } + }, + "security": [ + { + "refresh_token_auth": [ + "oauth.refresh_token.r" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/oauth2/refresh_token/{refreshToken}": { + "get": { + "description": "Get a refresh token", + "operationId": "getRefreshToken", + "parameters": [ + { + "name": "refreshToken", + "in": "path", + "description": "Refresh token", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/RefreshToken" + } + }, + "400": { + "description": "Invalid refresh token supplied" + }, + "404": { + "description": "Refresh token not found" + } + }, + "security": [ + { + "refresh_token_auth": [ + "oauth.refresh_token.r", + "oauth.refresh_token.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + }, + "delete": { + "description": "Delete a refresh token", + "operationId": "deleteRefreshToken", + "parameters": [ + { + "name": "refreshToken", + "in": "path", + "description": "Refresh Token", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid refresh token supplied" + }, + "404": { + "description": "Refresh token not found" + } + }, + "security": [ + { + "refresh_token_auth": [ + "oauth.refresh_token.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/server/info": { + "get": { + "security": [ + { + "refresh_token_auth": [ + "server.info.r" + ] + } + ], + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + }, + "/health": { + "get": { + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + } + }, + "securityDefinitions": { + "refresh_token_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.refresh_token.w": "write oauth refresh token", + "oauth.refresh_token.r": "read oauth refresh token", + "server.info.r": "read server info" + } + } + }, + "definitions": { + "RefreshToken": { + "type": "object", + "required": [ + "clientId", + "refreshToken", + "userId" + ], + "properties": { + "refreshToken": { + "type": "string", + "description": "refresh token" + }, + "userId": { + "type": "string", + "description": "user id" + }, + "clientId": { + "type": "string", + "description": "client id" + }, + "scope": { + "type": "string", + "description": "service scopes separated by space" + } + } + } + } +} \ No newline at end of file diff --git a/db/postgres/config/oauth2-refresh-token/tls/server.keystore b/db/postgres/config/oauth2-refresh-token/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/postgres/config/oauth2-refresh-token/tls/server.keystore differ diff --git a/db/postgres/config/oauth2-refresh-token/tls/server.truststore b/db/postgres/config/oauth2-refresh-token/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/postgres/config/oauth2-refresh-token/tls/server.truststore differ diff --git a/db/postgres/config/oauth2-service/cors.yml b/db/postgres/config/oauth2-service/cors.yml new file mode 100644 index 00000000..99437103 --- /dev/null +++ b/db/postgres/config/oauth2-service/cors.yml @@ -0,0 +1,12 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/postgres/config/oauth2-service/oauth/primary.crt b/db/postgres/config/oauth2-service/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/postgres/config/oauth2-service/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-service/oauth/secondary.crt b/db/postgres/config/oauth2-service/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/postgres/config/oauth2-service/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-service/primary.crt b/db/postgres/config/oauth2-service/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/postgres/config/oauth2-service/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-service/secret.yml b/db/postgres/config/oauth2-service/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/postgres/config/oauth2-service/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/postgres/config/oauth2-service/security.yml b/db/postgres/config/oauth2-service/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/postgres/config/oauth2-service/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/postgres/config/oauth2-service/server.yml b/db/postgres/config/oauth2-service/server.yml new file mode 100644 index 00000000..ff558b00 --- /dev/null +++ b/db/postgres/config/oauth2-service/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6883 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6883 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-service-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/postgres/config/oauth2-service/swagger.json b/db/postgres/config/oauth2-service/swagger.json new file mode 100644 index 00000000..c51d14a3 --- /dev/null +++ b/db/postgres/config/oauth2-service/swagger.json @@ -0,0 +1,393 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "OAuth2 Service Registration", + "description": "OAuth2 Service Registration microservices endpoints.", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/service": { + "post": { + "description": "Return a service object", + "operationId": "createService", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Service object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Service" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Service" + } + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "put": { + "description": "Return the updated service", + "operationId": "updateService", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Service object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Service" + } + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Service" + } + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "get": { + "description": "Return all services", + "operationId": "getAllService", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "pageSize", + "in": "query", + "description": "Pag size", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "serviceId", + "in": "query", + "description": "Partial serviceId for filter", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/Service" + } + } + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.r" + ] + } + ] + } + }, + "/oauth2/service/{serviceId}": { + "delete": { + "description": "Delete a service by Id", + "operationId": "deleteService", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "Service not found" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "get": { + "description": "Get a service by Id", + "operationId": "getService", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/Service" + } + }, + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "Service not found" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.r", + "oauth.service.w" + ] + } + ] + } + }, + "/oauth2/service/{serviceId}/endpoint": { + "post": { + "description": "create endpoints for service", + "operationId": "createServiceEndpoint", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "A list of endpoint object", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ServiceEndpoint" + } + } + } + ], + "responses": { + "201": { + "description": "Successful response" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "delete": { + "description": "Delete all endpoints for a service", + "operationId": "deleteServiceEndpoint", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "Service not found" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, + "get": { + "description": "Get all endpoints for a service", + "operationId": "getServiceEndpoint", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ServiceEndpoint" + } + } + }, + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "ServiceEndpoint not found" + } + }, + "security": [ + { + "service_auth": [ + "oauth.service.r", + "oauth.service.w" + ] + } + ] + } + } + }, + "securityDefinitions": { + "service_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.service.w": "write oauth service", + "oauth.service.r": "read oauth service" + } + } + }, + "definitions": { + "Service": { + "type": "object", + "required": [ + "serviceId", + "serviceName", + "serviceType", + "scope" + ], + "properties": { + "serviceId": { + "type": "string", + "description": "a unique service id" + }, + "serviceType": { + "type": "string", + "description": "service type", + "enum": [ + "swagger", + "openapi", + "graphql", + "hybrid" + ] + }, + "serviceName": { + "type": "string", + "description": "service name" + }, + "serviceDesc": { + "type": "string", + "description": "service description" + }, + "ownerId": { + "type": "string", + "description": "service owner userId" + }, + "scope": { + "type": "string", + "description": "service scopes separated by space" + }, + "createDt": { + "type": "string", + "format": "date-time", + "description": "create date time" + }, + "updateDt": { + "type": "string", + "format": "date-time", + "description": "update date time" + } + } + }, + "ServiceEndpoint": { + "type": "object", + "required": [ + "endpoint", + "operation", + "scope" + ], + "properties": { + "endpoint": { + "type": "string", + "description": "a combination of path and method to uniquely identify an operation" + }, + "operation": { + "type": "string", + "description": "operationId of the endpoint" + }, + "scope": { + "type": "string", + "description": "scope associated with the endpoint" + } + } + } + } +} \ No newline at end of file diff --git a/db/postgres/config/oauth2-service/tls/server.keystore b/db/postgres/config/oauth2-service/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/postgres/config/oauth2-service/tls/server.keystore differ diff --git a/db/postgres/config/oauth2-service/tls/server.truststore b/db/postgres/config/oauth2-service/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/postgres/config/oauth2-service/tls/server.truststore differ diff --git a/db/postgres/config/oauth2-token/cors.yml b/db/postgres/config/oauth2-token/cors.yml new file mode 100644 index 00000000..b83eecdf --- /dev/null +++ b/db/postgres/config/oauth2-token/cors.yml @@ -0,0 +1,13 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +description: Cors Http Handler +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/postgres/config/oauth2-token/jwt.yml b/db/postgres/config/oauth2-token/jwt.yml new file mode 100644 index 00000000..bc7ae31c --- /dev/null +++ b/db/postgres/config/oauth2-token/jwt.yml @@ -0,0 +1,13 @@ +# This is the default JWT configuration and need to be updated when used to issue JWT tokens. It is a component that used to +# issue JWT token. Normally, it should be used by light-oauth2 only but can be used to issue tokens distributely. +--- +# Signature private key that used to sign JWT tokens. +key: + kid: '100' # kid that used to sign the JWT tokens. It will be shown up in the token header. + filename: "/config/oauth/primary.jks" # private key that is used to sign JWT tokens. + password: password # password for the private key. It should be set during deployment time along with pk + keyName: selfsigned # key name that is used to identify the right key in keystore. +issuer: urn:com:networknt:oauth2:v1 # default issuer of the JWT token +audience: urn:com.networknt # default audience of the JWT token +expiredInMinutes: 10 # expired in 10 minutes by default for issued JWT tokens +version: '1.0' # JWT token version diff --git a/db/postgres/config/oauth2-token/oauth/primary.crt b/db/postgres/config/oauth2-token/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/postgres/config/oauth2-token/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-token/oauth/primary.jks b/db/postgres/config/oauth2-token/oauth/primary.jks new file mode 100644 index 00000000..0d6ae7cf Binary files /dev/null and b/db/postgres/config/oauth2-token/oauth/primary.jks differ diff --git a/db/postgres/config/oauth2-token/oauth/secondary.crt b/db/postgres/config/oauth2-token/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/postgres/config/oauth2-token/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-token/oauth/secondary.jks b/db/postgres/config/oauth2-token/oauth/secondary.jks new file mode 100644 index 00000000..33824c89 Binary files /dev/null and b/db/postgres/config/oauth2-token/oauth/secondary.jks differ diff --git a/db/postgres/config/oauth2-token/secret.yml b/db/postgres/config/oauth2-token/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/postgres/config/oauth2-token/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/postgres/config/oauth2-token/security.yml b/db/postgres/config/oauth2-token/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/postgres/config/oauth2-token/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/postgres/config/oauth2-token/server.yml b/db/postgres/config/oauth2-token/server.yml new file mode 100644 index 00000000..2a414220 --- /dev/null +++ b/db/postgres/config/oauth2-token/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6882 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6882 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-token-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/postgres/config/oauth2-token/swagger.json b/db/postgres/config/oauth2-token/swagger.json new file mode 100644 index 00000000..b56f7433 --- /dev/null +++ b/db/postgres/config/oauth2-token/swagger.json @@ -0,0 +1,125 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "OAuth2 Service Token Service", + "description": "OAuth2 Service that issues access tokens.", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/x-www-form-urlencoded" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/token": { + "post": { + "description": "JSON object that contains access token", + "operationId": "postToken", + "parameters": [ + { + "name": "authorization", + "description": "encoded client_id and client_secret pair", + "in": "header", + "type": "string", + "required": false + }, + { + "name": "grant_type", + "type": "string", + "enum": [ + "authorization_code", + "client_credentials", + "password", + "refresh_token", + "client_authenticated_user" + ], + "required": true, + "in": "formData" + }, + { + "name": "client_id", + "description": "used as alternative to authentication header for client authentication", + "type": "string", + "in": "formData" + }, + { + "name": "client_secret", + "description": "used as alternative to authentication header for client authentication", + "type": "string", + "in": "formData" + }, + { + "name": "code", + "description": "used in authorization_code to specify the code", + "type": "string", + "in": "formData" + }, + { + "name": "username", + "description": "mandatory in password grant type", + "type": "string", + "in": "formData" + }, + { + "name": "password", + "description": "mandatory in password grant type", + "type": "string", + "in": "formData" + }, + { + "name": "scope", + "description": "used by all flows to specify scope in the access token", + "type": "string", + "in": "formData" + }, + { + "name": "redirect_uri", + "description": "used in authorization code if code endpoint with rediret_uri", + "type": "string", + "in": "formData" + }, + { + "name": "refresh_token", + "description": "refresh token used to get another access token", + "type": "string", + "in": "formData" + }, + { + "name": "code_verifier", + "description": "PKCE code verifier", + "type": "string", + "in": "formData" + } + ], + "responses": { + "200": { + "description": "Successful Operation" + } + } + } + }, + "/health": { + "get": { + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + } + } +} diff --git a/db/postgres/config/oauth2-token/tls/server.keystore b/db/postgres/config/oauth2-token/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/postgres/config/oauth2-token/tls/server.keystore differ diff --git a/db/postgres/config/oauth2-token/tls/server.truststore b/db/postgres/config/oauth2-token/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/postgres/config/oauth2-token/tls/server.truststore differ diff --git a/db/postgres/config/oauth2-user/cors.yml b/db/postgres/config/oauth2-user/cors.yml new file mode 100644 index 00000000..99437103 --- /dev/null +++ b/db/postgres/config/oauth2-user/cors.yml @@ -0,0 +1,12 @@ +# Cors Http Handler Configuration. This is to support connection +# from light-portal single page application which might served +# from another domain/host. You may need to update allowedOrigins. +--- +enabled: true +allowedOrigins: +- http://localhost:8080 +allowedMethods: +- GET +- POST +- PUT +- DELETE diff --git a/db/postgres/config/oauth2-user/oauth/primary.crt b/db/postgres/config/oauth2-user/oauth/primary.crt new file mode 100644 index 00000000..34f9272f --- /dev/null +++ b/db/postgres/config/oauth2-user/oauth/primary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDmzCCAoOgAwIBAgIEHnAgtDANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEUMBIGA1UEBxMLTWlzc2lzc2F1Z2ExJjAkBgNVBAoTHU5ldHdvcmsgTmV3IFRl +Y2hub2xvZ2llcyBJbmMuMQwwCgYDVQQLEwNERVYxETAPBgNVBAMTCFN0ZXZlIEh1MB4XDTE2MDkw +MTE2MTYxNVoXDTI2MDcxMTE2MTYxNVowfjELMAkGA1UEBhMCQ0ExEDAOBgNVBAgTB09udGFyaW8x +FDASBgNVBAcTC01pc3Npc3NhdWdhMSYwJAYDVQQKEx1OZXR3b3JrIE5ldyBUZWNobm9sb2dpZXMg +SW5jLjEMMAoGA1UECxMDREVWMREwDwYDVQQDEwhTdGV2ZSBIdTCCASIwDQYJKoZIhvcNAQEBBQAD +ggEPADCCAQoCggEBALrlxMtDb60DogElf4TBz504tRheZimAE0dJL/Yby4nacJdqvc5l4z+WWpDf +rI9krQ2Yi9yvhwAP+PrR6gWcIqWP4cpNE7XIAUDgr4CtyI7CptT/lpjtbkz4DGCMmaeDn0jqHqJt +SeSZGfwVu5zAGm8n4sHatjnnxBI/iWzkTII3V4xv0WeK37szNTEd+ly2ag7n2IV5zNnYmqZTeMQm +J2ENS+IwAG3ENtiVtrVTx/2bGtqutJjtdxsN58/cUG/guRyMT6OPI8Yi3ZzevdvRbxadyhEl/Kaw +6vJcdxmJI3tp4lx+p6sAxOWa7aapJe4JxutAQqzv0GKdVjoHKQ1wB60CAwEAAaMhMB8wHQYDVR0O +BBYEFIPF9SBd06RWU1eDL73CKfy01lavMA0GCSqGSIb3DQEBCwUAA4IBAQAoaKZGOak3Upz/ordF +slZoJuZlCu7jnKQEjYwHf3DNxcd1WmgFPtMcna6pW0VUxPIfidEA6VCMsGoK1RvshB0SjrRdCht6 +5qPXs9kV3NW0WvMiwDSYZZ9HgaZ9efTe5E9Fzc7ltKrE43L6k8NJcaEEWEdpdjFbrAqH4I+j/Vro +K3OhIo062fXjas5ipL4gF+3ECImjWzirQP8UiAfM0/36x7rtAu3btH/qI9hSyx39LBPPE5AsDJZ4 +dSMwNTW1gqmBAZIj+zQ/RD5dyWfPwON7Q+t96YbK6WBuYo0xy+I+PjcUgrWYWP3N24hlq8ZBIei+ +BudoEVJlIlmS0aRCuP8n +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-user/oauth/secondary.crt b/db/postgres/config/oauth2-user/oauth/secondary.crt new file mode 100644 index 00000000..215cedb4 --- /dev/null +++ b/db/postgres/config/oauth2-user/oauth/secondary.crt @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIEUBGbJDANBgkqhkiG9w0BAQsFADB6MQswCQYDVQQGEwJDQTEQMA4GA1UE +CBMHT250YXJpbzEQMA4GA1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5v +bG9naWVzIEluYy4xDDAKBgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwHhcNMTYwOTIyMjI1 +OTIxWhcNMjYwODAxMjI1OTIxWjB6MQswCQYDVQQGEwJDQTEQMA4GA1UECBMHT250YXJpbzEQMA4G +A1UEBxMHVG9yb250bzEmMCQGA1UEChMdTmV0d29yayBOZXcgVGVjaG5vbG9naWVzIEluYy4xDDAK +BgNVBAsTA0FQSTERMA8GA1UEAxMIU3RldmUgSHUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQCqYfarFwug2DwpG/mmcW77OluaHVNsKEVJ/BptLp5suJAH/Z70SS5pwM4x2QwMOVO2ke8U +rsAws8allxcuKXrbpVt4evpO1Ly2sFwqB1bjN3+VMp6wcT+tSjzYdVGFpQAYHpeA+OLuoHtQyfpB +0KCveTEe3KAG33zXDNfGKTGmupZ3ZfmBLINoey/X13rY71ITt67AY78VHUKb+D53MBahCcjJ9YpJ +UHG+Sd3d4oeXiQcqJCBCVpD97awWARf8WYRIgU1xfCe06wQ3CzH3+GyfozLeu76Ni5PwE1tm7Dhg +EDSSZo5khmzVzo4G0T2sOeshePc5weZBNRHdHlJA0L0fAgMBAAGjITAfMB0GA1UdDgQWBBT9rnek +spnrFus5wTszjdzYgKll9TANBgkqhkiG9w0BAQsFAAOCAQEAT8udTfUGBgeWbN6ZAXRI64VsSJj5 +1sNUN1GPDADLxZF6jArKU7LjBNXn9bG5VjJqlx8hQ1SNvi/t7FqBRCUt/3MxDmGZrVZqLY1kZ2e7 +x+5RykbspA8neEUtU8sOr/NP3O5jBjU77EVec9hNNT5zwKLevZNL/Q5mfHoc4GrIAolQvi/5fEqC +8OMdOIWS6sERgjaeI4tXxQtHDcMo5PeLW0/7t5sgEsadZ+pkdeEMVTmLfgf97bpNNI7KF5uEbYnQ +NpwCT+NNC5ACmJmKidrfW23kml1C7vr7YzTevw9QuH/hN8l/Rh0fr+iPEVpgN6Zv00ymoKGmjuuW +owVmdKg/0w== +-----END CERTIFICATE----- diff --git a/db/postgres/config/oauth2-user/secret.yml b/db/postgres/config/oauth2-user/secret.yml new file mode 100644 index 00000000..101f36db --- /dev/null +++ b/db/postgres/config/oauth2-user/secret.yml @@ -0,0 +1,46 @@ +# This file contains all the secrets for the server and client in order to manage and +# secure all of them in the same place. In Kubernetes, this file will be mapped to +# Secrets and all other config files will be mapped to mapConfig + +--- + +# Sever section + +# Key store password, the path of keystore is defined in server.yml +serverKeystorePass: password + +# Key password, the key is in keystore +serverKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +serverTruststorePass: password + + +# Client section + +# Key store password, the path of keystore is defined in server.yml +clientKeystorePass: password + +# Key password, the key is in keystore +clientKeyPass: password + +# Trust store password, the path of truststore is defined in server.yml +clientTruststorePass: password + +# Authorization code client secret for OAuth2 server +authorizationCodeClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Client credentials client secret for OAuth2 server +clientCredentialsClientSecret: f6h1FTI8Q3-7UScPZDzfXA + +# Key distribution client secret for OAuth2 server +keyClientSecret: f6h1FTI8Q3-7UScPZDzfXA + + +# Consul service registry and discovery + +# Consul Token for service registry and discovery +# consulToken: the_one_ring + +# EmailSender password +emailPassword: change-to-real-password diff --git a/db/postgres/config/oauth2-user/security.yml b/db/postgres/config/oauth2-user/security.yml new file mode 100644 index 00000000..5125bfa5 --- /dev/null +++ b/db/postgres/config/oauth2-user/security.yml @@ -0,0 +1,30 @@ +# Security configuration in light framework. +--- +# Enable JWT verification flag. +enableVerifyJwt: false + +# Enable JWT scope verification. Only valid when enableVerifyJwt is true. +enableVerifyScope: true + +# User for test only. should be always be false on official environment. +enableMockJwt: false + +# JWT signature public certificates. kid and certificate path mappings. +jwt: + certificate: + '100': oauth/primary.crt + '101': oauth/secondary.crt + clockSkewInSeconds: 60 + +# Enable or disable JWT token logging +logJwtToken: true + +# Enable or disable client_id, user_id and scope logging. +logClientUserScope: false + +# If OAuth2 provider support http2 protocol. If using light-oauth2, set this to true. +oauthHttp2Support: true + +# Enable JWT token cache to speed up verification. This will only verify expired time +# and skip the signature verification as it takes more CPU power and long time. +enableJwtCache: true diff --git a/db/postgres/config/oauth2-user/server.yml b/db/postgres/config/oauth2-user/server.yml new file mode 100644 index 00000000..8718d5a6 --- /dev/null +++ b/db/postgres/config/oauth2-user/server.yml @@ -0,0 +1,39 @@ +# Server configuration +--- +# This is the default binding address if the service is dockerized. +ip: 0.0.0.0 + +# Http port if enableHttp is true. +httpPort: 6885 + +# Enable HTTP should be false on official environment. +enableHttp: false + +# Https port if enableHttps is true. +httpsPort: 6885 + +# Enable HTTPS should be true on official environment. +enableHttps: true + +# Enable HTTP2 should be true on official environment. +enableHttp2: true + +# Keystore file name in config folder. KeystorePass is in secret.yml to access it. +keystoreName: tls/server.keystore + +# Flag that indicate if two way TLS is enabled. Not recommended in docker container. +enableTwoWayTls: false + +# Truststore file name in config folder. TruststorePass is in secret.yml to access it. +truststoreName: tls/server.truststore + +# Unique service identifier. Used in service registration and discovery etc. +serviceId: com.networknt.oauth2-user-1.0.0 + +# Flag to enable service registration. Only be true if running as standalone Java jar. +enableRegistry: false + +# environment tag that will be registered on consul to support multiple instances per env for testing. +# https://github.com/networknt/light-doc/blob/master/docs/content/design/env-segregation.md +# This tag should only be set for testing env, not production. The production certification process will enforce it. +# environment: test1 diff --git a/db/postgres/config/oauth2-user/swagger.json b/db/postgres/config/oauth2-user/swagger.json new file mode 100644 index 00000000..9717cc2a --- /dev/null +++ b/db/postgres/config/oauth2-user/swagger.json @@ -0,0 +1,368 @@ +{ + "swagger": "2.0", + "info": { + "description": "OAuth2 User Service microservices endpoints.", + "version": "1.0.0", + "title": "OAuth2 User Service", + "contact": { + "email": "stevehu@gmail.com" + }, + "license": { + "name": "Apache 2.0", + "url": "http://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "oauth2.networknt.com", + "schemes": [ + "http", + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/oauth2/password/{userId}": { + "post": { + "description": "Reset Password", + "operationId": "resetPassword", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "Password object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/Password" + } + }, + { + "name": "userId", + "in": "path", + "description": "User Id", + "required": true, + "type": "string" + } + ], + "responses": { + "404": { + "description": "User not found" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/oauth2/user": { + "get": { + "description": "Return all users", + "operationId": "getAllUsers", + "parameters": [ + { + "name": "page", + "in": "query", + "description": "Page number", + "required": true, + "type": "integer", + "format": "int32" + }, + { + "name": "pageSize", + "in": "query", + "description": "Pag size", + "required": false, + "type": "integer", + "format": "int32" + }, + { + "name": "userId", + "in": "query", + "description": "Partial userId for filter", + "required": false, + "type": "string" + } + ], + "responses": { + "200": { + "description": "successful operation", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/User" + } + } + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.r" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + }, + "post": { + "description": "Return a user object", + "operationId": "createUser", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "User object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/User" + } + } + ], + "responses": { + "200": { + "description": "Successful response" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + }, + "put": { + "description": "Return the updated user", + "operationId": "updateUser", + "parameters": [ + { + "in": "body", + "name": "body", + "description": "User object that needs to be added", + "required": true, + "schema": { + "$ref": "#/definitions/User" + } + } + ], + "responses": { + "200": { + "description": "Successful response" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/oauth2/user/{userId}": { + "get": { + "description": "Get a user by Id", + "operationId": "getUser", + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "User Id", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "Successful response", + "schema": { + "$ref": "#/definitions/User" + } + }, + "400": { + "description": "Invalid userId supplied" + }, + "404": { + "description": "User not found" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.r", + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + }, + "delete": { + "description": "Delete a user by Id", + "operationId": "deleteUser", + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "User Id", + "required": true, + "type": "string" + } + ], + "responses": { + "400": { + "description": "Invalid userId supplied" + }, + "404": { + "description": "User not found" + } + }, + "security": [ + { + "user_auth": [ + "oauth.user.w" + ] + } + ], + "x-accepts": "application/json", + "x-contentType": "application/json" + } + }, + "/server/info": { + "get": { + "security": [ + { + "service_auth": [ + "server.info.r" + ] + } + ], + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + }, + "/health": { + "get": { + "responses": { + "200": { + "description": "successful operation" + } + }, + "parameters": [] + } + } + }, + "securityDefinitions": { + "user_auth": { + "type": "oauth2", + "authorizationUrl": "http://localhost:8888/oauth2/code", + "flow": "implicit", + "scopes": { + "oauth.user.w": "write user", + "oauth.user.r": "read user", + "server.info.r": "read server info" + } + } + }, + "definitions": { + "User": { + "type": "object", + "required": [ + "email", + "firstName", + "lastName", + "userId", + "userType" + ], + "properties": { + "userId": { + "type": "string", + "description": "a unique id" + }, + "userType": { + "type": "string", + "description": "user type", + "enum": [ + "admin", + "employee", + "customer", + "partner" + ] + }, + "firstName": { + "type": "string", + "description": "first name" + }, + "lastName": { + "type": "string", + "description": "last name" + }, + "email": { + "type": "string", + "description": "email address" + }, + "password": { + "type": "string", + "format": "password", + "description": "password" + }, + "passwordConfirm": { + "type": "string", + "format": "password", + "description": "password confirm" + }, + "createDt": { + "type": "string", + "format": "date-time", + "description": "create date time" + }, + "updateDt": { + "type": "string", + "format": "date-time", + "description": "update date time" + } + } + }, + "Password": { + "type": "object", + "required": [ + "newPassword", + "newPasswordConfirm", + "password" + ], + "properties": { + "password": { + "type": "string", + "format": "password", + "description": "existing password" + }, + "newPassword": { + "type": "string", + "format": "password", + "description": "new password" + }, + "newPasswordConfirm": { + "type": "string", + "format": "password", + "description": "new password confirm" + } + } + } + } +} \ No newline at end of file diff --git a/db/postgres/config/oauth2-user/tls/server.keystore b/db/postgres/config/oauth2-user/tls/server.keystore new file mode 100644 index 00000000..feab9b6d Binary files /dev/null and b/db/postgres/config/oauth2-user/tls/server.keystore differ diff --git a/db/postgres/config/oauth2-user/tls/server.truststore b/db/postgres/config/oauth2-user/tls/server.truststore new file mode 100644 index 00000000..fb0c19cc Binary files /dev/null and b/db/postgres/config/oauth2-user/tls/server.truststore differ diff --git a/db/postgres/create_postgres.sql b/db/postgres/create_postgres.sql index 503e9f7b..46ead571 100644 --- a/db/postgres/create_postgres.sql +++ b/db/postgres/create_postgres.sql @@ -1,20 +1,18 @@ -DROP TABLE IF EXISTS users; -CREATE TABLE users ( +DROP TABLE IF EXISTS user_profile; +CREATE TABLE user_profile ( user_id VARCHAR(32) NOT NULL, user_type VARCHAR(16) NOT NULL, -- admin, customer, employee, partner first_name VARCHAR(32) NOT NULL, last_name VARCHAR(32) NOT NULL, email VARCHAR(64) NOT NULL, password VARCHAR(1024) NOT NULL, - create_dt DATE NOT NULL, - update_dt DATE, PRIMARY KEY (user_id) ); -CREATE UNIQUE INDEX email_idx ON users(email); +CREATE UNIQUE INDEX email_idx ON user_profile(email); -DROP TABLE IF EXISTS clients; -CREATE TABLE clients ( +DROP TABLE IF EXISTS client; +CREATE TABLE client ( client_id VARCHAR(36) NOT NULL, client_type VARCHAR(12) NOT NULL, -- public, confidential, trusted client_profile VARCHAR(10) NOT NULL, -- webserver, mobile, browser, service, batch @@ -25,32 +23,62 @@ CREATE TABLE clients ( redirect_uri VARCHAR(1024), authenticate_class VARCHAR(256), owner_id VARCHAR(32) NOT NULL, - create_dt DATE NOT NULL, - update_dt DATE, PRIMARY KEY (client_id), - FOREIGN KEY (owner_id) REFERENCES users(user_id) + FOREIGN KEY (owner_id) REFERENCES user_profile(user_id) ); -DROP TABLE IF EXISTS services; -CREATE TABLE services ( +DROP TABLE IF EXISTS service; +CREATE TABLE service ( service_id VARCHAR(32) NOT NULL, - service_type VARCHAR(8) NOT NULL, -- api, ms + service_type VARCHAR(16) NOT NULL, -- swagger, openapi, graphql, hybrid service_name VARCHAR(32) NOT NULL, service_desc VARCHAR(1024), scope VARCHAR(1024), owner_id VARCHAR(32) NOT NULL, - create_dt DATE NOT NULL, - update_dt DATE, PRIMARY KEY (service_id), - FOREIGN KEY (owner_id) REFERENCES users(user_id) + FOREIGN KEY (owner_id) REFERENCES user_profile(user_id) ); -INSERT INTO users (user_id, user_type, first_name, last_name, email, password, create_dt) -VALUES('admin', 'admin', 'admin', 'admin', 'admin@cibc.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992', current_timestamp); +DROP TABLE IF EXISTS service_endpoint; +CREATE TABLE service_endpoint ( + service_id VARCHAR(32) NOT NULL, + endpoint VARCHAR(256) NOT NULL, -- different framework will have different endpoint format. + operation VARCHAR(256) NOT NULL, + scope VARCHAR(64) NOT NULL, + PRIMARY KEY (service_id, endpoint), + FOREIGN KEY (service_id) REFERENCES service(service_id) +); + + +DROP TABLE IF EXISTS client_service; +CREATE TABLE client_service ( + client_id VARCHAR(36) NOT NULL, + service_id VARCHAR(32) NOT NULL, + endpoint VARCHAR(256) NOT NULL, -- different framework will have different endpoint format. + PRIMARY KEY (client_id, service_id, endpoint), + FOREIGN KEY (service_id, endpoint) REFERENCES service_endpoint(service_id, endpoint), + FOREIGN KEY (client_id) REFERENCES client(client_id) +); + +DROP TABLE IF EXISTS audit_log; +create table audit_log ( + log_id INT, -- system milliseonds from 1970. + service_id VARCHAR(32) NOT NULL, + endpoint VARCHAR(256) NOT NULL, + request_header VARCHAR(4096), + request_body VARCHAR(4096), + response_code INT, + response_header VARCHAR(4096), + response_body VARCHAR(4096) +); + + +INSERT INTO user_profile (user_id, user_type, first_name, last_name, email, password) +VALUES('admin', 'admin', 'admin', 'admin', 'admin@cibc.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO clients (client_id, client_secret, client_type, client_profile, client_name, client_desc, scope, redirect_uri, owner_id, create_dt) -VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'public', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', 'admin', current_timestamp); +INSERT INTO client (client_id, client_secret, client_type, client_profile, client_name, client_desc, scope, redirect_uri, owner_id) +VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'public', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', 'admin'); -INSERT INTO services (service_id, service_type, service_name, service_desc, scope, owner_id, create_dt) -VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin', current_timestamp); +INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) +VALUES ('AACT0001', 'openapi', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); diff --git a/key/docker/Dockerfile b/key/Dockerfile similarity index 100% rename from key/docker/Dockerfile rename to key/Dockerfile diff --git a/key/build.sh b/key/build.sh index 939da6b5..0be5cd71 100755 --- a/key/build.sh +++ b/key/build.sh @@ -42,7 +42,7 @@ cleanup() { publish() { echo "Building Docker image with version $VERSION" - docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./docker/Dockerfile . --no-cache=true + docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./Dockerfile . --no-cache=true docker build -t $IMAGE_NAME:$VERSION-redhat -f ./docker/Dockerfile-Redhat . --no-cache=true echo "Images built with version $VERSION" echo "Pushing image to DockerHub" diff --git a/key/docker/Dockerfile-Redhat b/key/docker/Dockerfile-Redhat index 60d304ed..64fb23fa 100644 --- a/key/docker/Dockerfile-Redhat +++ b/key/docker/Dockerfile-Redhat @@ -2,27 +2,30 @@ FROM registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift USER root -ENV APP_DIR=/app \ +ENV APP_DIR=app \ GROUP_NAME=networknt \ GROUP_ID=1000 \ USER_NAME=networknt \ USER_UID=1000 RUN groupadd -g ${GROUP_ID} -r ${GROUP_NAME} && \ - useradd -u ${USER_UID} -g ${GROUP_NAME} -d "${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} + useradd -u ${USER_UID} -g ${GROUP_NAME} -d "/${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} # Add the jar file into the container at /app -ADD target/oauth2-key.jar ${APP_DIR}/server.jar +ADD target/oauth2-key.jar ./${APP_DIR}/server.jar # change permissions of app directory -RUN chown -R ${USER_NAME}:${GROUP_NAME} "${APP_DIR}" +RUN mkdir -p ./${APP_DIR}/config && \ + chown -R ${USER_NAME}:0 "./${APP_DIR}/config" && \ + find "./${APP_DIR}/config" -type d -exec chmod 750 {} \; && \ + find "./${APP_DIR}/config" -type f -exec chmod 640 {} \; # Port available to the world outside of this container -EXPOSE 6886 +EXPOSE 8080 USER ${USER_UID} # Set the working directory to /app -WORKDIR ${APP_DIR} +WORKDIR ./${APP_DIR} -CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] +CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] \ No newline at end of file diff --git a/key/src/main/resources/logback.xml b/key/src/main/resources/logback.xml index 6e58aff8..455f137d 100644 --- a/key/src/main/resources/logback.xml +++ b/key/src/main/resources/logback.xml @@ -28,7 +28,7 @@ - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n @@ -36,7 +36,7 @@ target/test.log false - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %class{36}:%L %M - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n diff --git a/key/src/test/resources/create_h2.sql b/key/src/test/resources/create_h2.sql index cf8de8a0..52c37cdf 100644 --- a/key/src/test/resources/create_h2.sql +++ b/key/src/test/resources/create_h2.sql @@ -1,8 +1,8 @@ -DROP table IF EXISTS users; -DROP table IF EXISTS clients; -DROP table IF EXISTS services; +DROP table IF EXISTS user_profile; +DROP table IF EXISTS client; +DROP table IF EXISTS service; -create table users ( +create table user_profile ( user_id varchar PRIMARY KEY, user_type varchar, -- admin, customer, employee, partner first_name varchar, @@ -13,13 +13,13 @@ create table users ( update_dt DATE ); -CREATE UNIQUE INDEX email_idx ON users(email); +CREATE UNIQUE INDEX email_idx ON user_profile(email); -create table clients ( +create table client ( client_id VARCHAR PRIMARY KEY, - client_type VARCHAR, client_secret VARCHAR, - client_profile VARCHAR, + client_type VARCHAR, -- public, confidential, trusted + client_profile VARCHAR, -- server, mobile, service, batch, browser client_name VARCHAR, client_desc VARCHAR, scope VARCHAR, @@ -30,7 +30,7 @@ create table clients ( update_dt DATE ); -create table services ( +create table service ( service_id VARCHAR PRIMARY KEY, service_type VARCHAR, -- api, ms service_name VARCHAR, @@ -41,10 +41,10 @@ create table services ( update_dt DATE ); -INSERT INTO users (user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', 'admin'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); -INSERT INTO services (service_id, service_type, service_name, service_desc, scope) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r'); +INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); diff --git a/pom.xml b/pom.xml index 9a7c4425..3d5a90c6 100644 --- a/pom.xml +++ b/pom.xml @@ -66,9 +66,9 @@ 1.0.32 2.7.1 1.4.196 - 3.6.8 + 3.9.2 11.2.0.3 - 6.0.4 + 6.0.5 9.4.1211 2.4 -Xmx512m -XX:MaxPermSize=256m diff --git a/refresh-token/docker/Dockerfile b/refresh-token/Dockerfile similarity index 100% rename from refresh-token/docker/Dockerfile rename to refresh-token/Dockerfile diff --git a/refresh-token/build.sh b/refresh-token/build.sh index e72b9635..bc242fe0 100755 --- a/refresh-token/build.sh +++ b/refresh-token/build.sh @@ -42,7 +42,7 @@ cleanup() { publish() { echo "Building Docker image with version $VERSION" - docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./docker/Dockerfile . --no-cache=true + docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./Dockerfile . --no-cache=true docker build -t $IMAGE_NAME:$VERSION-redhat -f ./docker/Dockerfile-Redhat . --no-cache=true echo "Images built with version $VERSION" echo "Pushing image to DockerHub" diff --git a/refresh-token/docker/Dockerfile-Redhat b/refresh-token/docker/Dockerfile-Redhat index ec48c539..30141367 100644 --- a/refresh-token/docker/Dockerfile-Redhat +++ b/refresh-token/docker/Dockerfile-Redhat @@ -2,27 +2,30 @@ FROM registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift USER root -ENV APP_DIR=/app \ +ENV APP_DIR=app \ GROUP_NAME=networknt \ GROUP_ID=1000 \ USER_NAME=networknt \ USER_UID=1000 RUN groupadd -g ${GROUP_ID} -r ${GROUP_NAME} && \ - useradd -u ${USER_UID} -g ${GROUP_NAME} -d "${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} + useradd -u ${USER_UID} -g ${GROUP_NAME} -d "/${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} # Add the jar file into the container at /app -ADD target/oauth2-refresh-token.jar ${APP_DIR}/server.jar +ADD target/oauth2-refresh-token.jar ./${APP_DIR}/server.jar # change permissions of app directory -RUN chown -R ${USER_NAME}:${GROUP_NAME} "${APP_DIR}" +RUN mkdir -p ./${APP_DIR}/config && \ + chown -R ${USER_NAME}:0 "./${APP_DIR}/config" && \ + find "./${APP_DIR}/config" -type d -exec chmod 750 {} \; && \ + find "./${APP_DIR}/config" -type f -exec chmod 640 {} \; # Port available to the world outside of this container -EXPOSE 6887 +EXPOSE 8080 USER ${USER_UID} # Set the working directory to /app -WORKDIR ${APP_DIR} +WORKDIR ./${APP_DIR} -CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] +CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] \ No newline at end of file diff --git a/refresh-token/src/main/resources/logback.xml b/refresh-token/src/main/resources/logback.xml index 6e58aff8..455f137d 100644 --- a/refresh-token/src/main/resources/logback.xml +++ b/refresh-token/src/main/resources/logback.xml @@ -28,7 +28,7 @@ - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n @@ -36,7 +36,7 @@ target/test.log false - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %class{36}:%L %M - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n diff --git a/refresh-token/src/test/resources/create_h2.sql b/refresh-token/src/test/resources/create_h2.sql index 423a5fe0..52c37cdf 100644 --- a/refresh-token/src/test/resources/create_h2.sql +++ b/refresh-token/src/test/resources/create_h2.sql @@ -1,8 +1,8 @@ -DROP table IF EXISTS users; -DROP table IF EXISTS clients; -DROP table IF EXISTS services; +DROP table IF EXISTS user_profile; +DROP table IF EXISTS client; +DROP table IF EXISTS service; -create table users ( +create table user_profile ( user_id varchar PRIMARY KEY, user_type varchar, -- admin, customer, employee, partner first_name varchar, @@ -13,13 +13,13 @@ create table users ( update_dt DATE ); -CREATE UNIQUE INDEX email_idx ON users(email); +CREATE UNIQUE INDEX email_idx ON user_profile(email); -create table clients ( +create table client ( client_id VARCHAR PRIMARY KEY, - client_type VARCHAR, client_secret VARCHAR, - client_profile VARCHAR, + client_type VARCHAR, -- public, confidential, trusted + client_profile VARCHAR, -- server, mobile, service, batch, browser client_name VARCHAR, client_desc VARCHAR, scope VARCHAR, @@ -30,7 +30,7 @@ create table clients ( update_dt DATE ); -create table services ( +create table service ( service_id VARCHAR PRIMARY KEY, service_type VARCHAR, -- api, ms service_name VARCHAR, @@ -41,12 +41,10 @@ create table services ( update_dt DATE ); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO clients (client_id, client_type, client_profile, client_secret, client_name, client_desc, scope, redirect_uri, owner_id) -VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'trusted', 'mobile', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', 'admin' ); -INSERT INTO clients (client_id, client_type, client_profile, client_secret, client_name, client_desc, scope, redirect_uri, owner_id) -VALUES('6e9d1db3-2feb-4c1f-a5ad-9e93ae8ca59d', 'public', 'mobile', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); -INSERT INTO services (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); +INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); diff --git a/service/.gitignore b/service/.gitignore index 3901d721..7883fdc0 100644 --- a/service/.gitignore +++ b/service/.gitignore @@ -13,6 +13,7 @@ dist/ *.tmp *.zip *.bak +dependency-reduced-pom.xml # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml hs_err_pid* diff --git a/service/docker/Dockerfile b/service/Dockerfile similarity index 100% rename from service/docker/Dockerfile rename to service/Dockerfile diff --git a/service/build.sh b/service/build.sh index 877b4f6c..9a92f697 100755 --- a/service/build.sh +++ b/service/build.sh @@ -42,7 +42,7 @@ cleanup() { publish() { echo "Building Docker image with version $VERSION" - docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./docker/Dockerfile . --no-cache=true + docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./Dockerfile . --no-cache=true docker build -t $IMAGE_NAME:$VERSION-redhat -f ./docker/Dockerfile-Redhat . --no-cache=true echo "Images built with version $VERSION" echo "Pushing image to DockerHub" diff --git a/service/docker/Dockerfile-Redhat b/service/docker/Dockerfile-Redhat index dcba3efb..1cbf6d94 100644 --- a/service/docker/Dockerfile-Redhat +++ b/service/docker/Dockerfile-Redhat @@ -2,27 +2,30 @@ FROM registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift USER root -ENV APP_DIR=/app \ +ENV APP_DIR=app \ GROUP_NAME=networknt \ GROUP_ID=1000 \ USER_NAME=networknt \ USER_UID=1000 RUN groupadd -g ${GROUP_ID} -r ${GROUP_NAME} && \ - useradd -u ${USER_UID} -g ${GROUP_NAME} -d "${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} + useradd -u ${USER_UID} -g ${GROUP_NAME} -d "/${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} # Add the jar file into the container at /app -ADD target/oauth2-service.jar ${APP_DIR}/server.jar +ADD target/oauth2-service.jar ./${APP_DIR}/server.jar # change permissions of app directory -RUN chown -R ${USER_NAME}:${GROUP_NAME} "${APP_DIR}" +RUN mkdir -p ./${APP_DIR}/config && \ + chown -R ${USER_NAME}:0 "./${APP_DIR}/config" && \ + find "./${APP_DIR}/config" -type d -exec chmod 750 {} \; && \ + find "./${APP_DIR}/config" -type f -exec chmod 640 {} \; # Port available to the world outside of this container -EXPOSE 6883 +EXPOSE 8080 USER ${USER_UID} # Set the working directory to /app -WORKDIR ${APP_DIR} +WORKDIR ./${APP_DIR} -CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] +CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] \ No newline at end of file diff --git a/service/src/main/java/com/networknt/oauth/service/PathHandlerProvider.java b/service/src/main/java/com/networknt/oauth/service/PathHandlerProvider.java index f49d0603..a93c95e9 100644 --- a/service/src/main/java/com/networknt/oauth/service/PathHandlerProvider.java +++ b/service/src/main/java/com/networknt/oauth/service/PathHandlerProvider.java @@ -1,26 +1,41 @@ + package com.networknt.oauth.service; -import com.networknt.health.HealthGetHandler; -import com.networknt.info.ServerInfoGetHandler; -import com.networknt.oauth.service.handler.*; +import com.networknt.config.Config; import com.networknt.server.HandlerProvider; import io.undertow.Handlers; import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; import io.undertow.util.Methods; +import com.networknt.info.ServerInfoGetHandler; +import com.networknt.health.HealthGetHandler; +import com.networknt.oauth.service.handler.*; public class PathHandlerProvider implements HandlerProvider { @Override public HttpHandler getHandler() { - HttpHandler handler = Handlers.routing() - .add(Methods.GET, "/health", new HealthGetHandler()) - .add(Methods.GET, "/server/info", new ServerInfoGetHandler()) - .add(Methods.GET, "/oauth2/service", new Oauth2ServiceGetHandler()) + return Handlers.routing() + .add(Methods.POST, "/oauth2/service", new Oauth2ServicePostHandler()) + .add(Methods.PUT, "/oauth2/service", new Oauth2ServicePutHandler()) + + .add(Methods.GET, "/oauth2/service", new Oauth2ServiceGetHandler()) + + .add(Methods.POST, "/oauth2/service/{serviceId}/endpoint", new Oauth2ServiceServiceIdEndpointPostHandler()) + + .add(Methods.DELETE, "/oauth2/service/{serviceId}/endpoint", new Oauth2ServiceServiceIdEndpointDeleteHandler()) + + .add(Methods.GET, "/oauth2/service/{serviceId}/endpoint", new Oauth2ServiceServiceIdEndpointGetHandler()) + .add(Methods.DELETE, "/oauth2/service/{serviceId}", new Oauth2ServiceServiceIdDeleteHandler()) + .add(Methods.GET, "/oauth2/service/{serviceId}", new Oauth2ServiceServiceIdGetHandler()) + + .add(Methods.GET, "/health", new HealthGetHandler()) + + .add(Methods.GET, "/server/info", new ServerInfoGetHandler()) + ; - return handler; } } - diff --git a/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServicePostHandler.java b/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServicePostHandler.java index d8ece7a8..9553716c 100644 --- a/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServicePostHandler.java +++ b/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServicePostHandler.java @@ -39,8 +39,6 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { exchange.getResponseSender().send(status.toString()); } } - // set date here otherwise database will have the date populated but the cache without date - service.setCreateDt(new Date(System.currentTimeMillis())); services.set(serviceId, service); } else { Status status = new Status(SERVICE_ID_EXISTS, serviceId); diff --git a/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServicePutHandler.java b/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServicePutHandler.java index 2d9a2e7b..80b56d04 100644 --- a/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServicePutHandler.java +++ b/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServicePutHandler.java @@ -44,8 +44,6 @@ public void handleRequest(HttpServerExchange exchange) throws Exception { exchange.getResponseSender().send(status.toString()); } } - // set updateDt here - service.setUpdateDt(new Date(System.currentTimeMillis())); services.set(serviceId, service); } } diff --git a/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointDeleteHandler.java b/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointDeleteHandler.java new file mode 100644 index 00000000..208e546d --- /dev/null +++ b/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointDeleteHandler.java @@ -0,0 +1,38 @@ + +package com.networknt.oauth.service.handler; + +import com.hazelcast.core.IMap; +import com.networknt.oauth.cache.CacheStartupHookProvider; +import com.networknt.oauth.cache.model.ServiceEndpoint; +import com.networknt.status.Status; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.List; + +/** + * Delete all endpoints for a service by serviceId + * + * @author Steve Hu + */ +public class Oauth2ServiceServiceIdEndpointDeleteHandler implements HttpHandler { + private static Logger logger = LoggerFactory.getLogger(Oauth2ServiceServiceIdEndpointDeleteHandler.class); + private static final String SERVICE_ENDPOINT_NOT_FOUND = "ERR12042"; + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + String serviceId = exchange.getQueryParameters().get("serviceId").getFirst(); + if(logger.isDebugEnabled()) logger.debug("Delete service endpoint for serviceId " + serviceId); + IMap> serviceEndpoints = CacheStartupHookProvider.hz.getMap("serviceEndpoints"); + if(serviceEndpoints.get(serviceId) == null || serviceEndpoints.get(serviceId).size() == 0) { + Status status = new Status(SERVICE_ENDPOINT_NOT_FOUND, serviceId); + exchange.setStatusCode(status.getStatusCode()); + exchange.getResponseSender().send(status.toString()); + } else { + serviceEndpoints.delete(serviceId); + } + + } +} diff --git a/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointGetHandler.java b/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointGetHandler.java new file mode 100644 index 00000000..70d9c94f --- /dev/null +++ b/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointGetHandler.java @@ -0,0 +1,46 @@ + +package com.networknt.oauth.service.handler; + +import com.hazelcast.core.IMap; +import com.hazelcast.query.PagingPredicate; +import com.hazelcast.query.impl.predicates.LikePredicate; +import com.networknt.config.Config; +import com.networknt.oauth.cache.CacheStartupHookProvider; +import com.networknt.oauth.cache.model.Service; +import com.networknt.oauth.cache.model.ServiceComparator; +import com.networknt.oauth.cache.model.ServiceEndpoint; +import com.networknt.status.Status; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.*; + +/** + * Retrieve all service endpoints for a particular serviceId + * + * @author Steve Hu + */ +public class Oauth2ServiceServiceIdEndpointGetHandler implements HttpHandler { + static final Logger logger = LoggerFactory.getLogger(Oauth2ServiceServiceIdEndpointGetHandler.class); + static final String SERVICE_ENDPOINT_NOT_FOUND = "ERR12042"; + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + IMap> serviceEndpoints = CacheStartupHookProvider.hz.getMap("serviceEndpoints"); + + String serviceId = exchange.getQueryParameters().get("serviceId").getFirst(); + List values = serviceEndpoints.get(serviceId); + + if(values == null || values.size() == 0) { + Status status = new Status(SERVICE_ENDPOINT_NOT_FOUND, serviceId); + exchange.setStatusCode(status.getStatusCode()); + exchange.getResponseSender().send(status.toString()); + return; + } + exchange.getResponseHeaders().add(new HttpString("Content-Type"), "application/json"); + exchange.getResponseSender().send(Config.getInstance().getMapper().writeValueAsString(values)); + } +} diff --git a/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointPostHandler.java b/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointPostHandler.java new file mode 100644 index 00000000..77e138fe --- /dev/null +++ b/service/src/main/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointPostHandler.java @@ -0,0 +1,54 @@ + +package com.networknt.oauth.service.handler; + +import com.hazelcast.core.IMap; +import com.networknt.body.BodyHandler; +import com.networknt.config.Config; +import com.networknt.oauth.cache.CacheStartupHookProvider; +import com.networknt.oauth.cache.model.Service; +import com.networknt.oauth.cache.model.ServiceEndpoint; +import com.networknt.oauth.cache.model.User; +import com.networknt.status.Status; +import io.undertow.server.HttpHandler; +import io.undertow.server.HttpServerExchange; +import io.undertow.util.HttpString; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * create or update a list of endpoints for the serviceId + * + * @author Steve Hu + */ +public class Oauth2ServiceServiceIdEndpointPostHandler implements HttpHandler { + private static final Logger logger = LoggerFactory.getLogger(Oauth2ServiceServiceIdEndpointPostHandler.class); + static final String SERVICE_NOT_FOUND = "ERR12015"; + + @Override + public void handleRequest(HttpServerExchange exchange) throws Exception { + List> body = (List)exchange.getAttachment(BodyHandler.REQUEST_BODY); + String serviceId = exchange.getQueryParameters().get("serviceId").getFirst(); + if(logger.isDebugEnabled()) logger.debug("post serviceEndpoints for serviceId " + serviceId); + + // ensure that the serviceId exists + IMap services = CacheStartupHookProvider.hz.getMap("services"); + if(services.get(serviceId) == null) { + Status status = new Status(SERVICE_NOT_FOUND, serviceId); + exchange.setStatusCode(status.getStatusCode()); + exchange.getResponseSender().send(status.toString()); + return; + } + + IMap> serviceEndpoints = CacheStartupHookProvider.hz.getMap("serviceEndpoints"); + List list = new ArrayList<>(); + for(Map m: body) { + list.add(Config.getInstance().getMapper().convertValue(m, ServiceEndpoint.class)); + } + serviceEndpoints.set(serviceId, list); + } +} diff --git a/service/src/main/resources/logback.xml b/service/src/main/resources/logback.xml index 6e58aff8..455f137d 100644 --- a/service/src/main/resources/logback.xml +++ b/service/src/main/resources/logback.xml @@ -28,7 +28,7 @@ - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n @@ -36,7 +36,7 @@ target/test.log false - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %class{36}:%L %M - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n diff --git a/service/src/test/java/com/networknt/oauth/service/handler/HealthGetHandlerTest.java b/service/src/test/java/com/networknt/oauth/service/handler/HealthGetHandlerTest.java new file mode 100644 index 00000000..aebc9280 --- /dev/null +++ b/service/src/test/java/com/networknt/oauth/service/handler/HealthGetHandlerTest.java @@ -0,0 +1,68 @@ + +package com.networknt.oauth.service.handler; + +import com.networknt.client.Http2Client; +import com.networknt.exception.ApiException; +import com.networknt.exception.ClientException; +import io.undertow.UndertowOptions; +import io.undertow.client.ClientConnection; +import io.undertow.client.ClientRequest; +import io.undertow.client.ClientResponse; +import io.undertow.util.Headers; +import io.undertow.util.Methods; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import java.io.IOException; + + +public class HealthGetHandlerTest { + @ClassRule + public static TestServer server = TestServer.getInstance(); + + static final Logger logger = LoggerFactory.getLogger(HealthGetHandlerTest.class); + static final boolean enableHttp2 = server.getServerConfig().isEnableHttp2(); + static final boolean enableHttps = server.getServerConfig().isEnableHttps(); + static final int httpPort = server.getServerConfig().getHttpPort(); + static final int httpsPort = server.getServerConfig().getHttpsPort(); + static final String url = enableHttp2 || enableHttps ? "https://localhost:" + httpsPort : "http://localhost:" + httpPort; + + @Test + public void testHealthGetHandlerTest() throws ClientException, ApiException { + /* + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/health").setMethod(Methods.GET); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(200, statusCode); + Assert.assertNotNull(body); + */ + } +} diff --git a/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServicePostHandlerTest.java b/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServicePostHandlerTest.java index a26691d2..bb5bdee3 100644 --- a/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServicePostHandlerTest.java +++ b/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServicePostHandlerTest.java @@ -36,7 +36,7 @@ public class Oauth2ServicePostHandlerTest { @Test public void testOauth2ServicePostHandler() throws ClientException, ApiException, UnsupportedEncodingException { - String service = "{\"serviceId\":\"AACT0003\",\"serviceType\":\"ms\",\"serviceName\":\"Retail Account\",\"serviceDesc\":\"Microservices for Retail Account\",\"scope\":\"act.r act.w\",\"ownerId\":\"admin\"}"; + String service = "{\"serviceId\":\"AACT0003\",\"serviceType\":\"swagger\",\"serviceName\":\"Retail Account\",\"serviceDesc\":\"Microservices for Retail Account\",\"scope\":\"act.r act.w\",\"ownerId\":\"admin\"}"; final AtomicReference reference = new AtomicReference<>(); final Http2Client client = Http2Client.getInstance(); final CountDownLatch latch = new CountDownLatch(1); @@ -75,7 +75,7 @@ public void run() { @Test public void testOwnerIdNotFound() throws ClientException, ApiException, UnsupportedEncodingException { - String service = "{\"serviceId\":\"AACT0004\",\"serviceType\":\"ms\",\"serviceName\":\"Retail Account\",\"serviceDesc\":\"Microservices for Retail Account\",\"scope\":\"act.r act.w\",\"ownerId\":\"fake\"}"; + String service = "{\"serviceId\":\"AACT0004\",\"serviceType\":\"swagger\",\"serviceName\":\"Retail Account\",\"serviceDesc\":\"Microservices for Retail Account\",\"scope\":\"act.r act.w\",\"ownerId\":\"fake\"}"; final AtomicReference reference = new AtomicReference<>(); final Http2Client client = Http2Client.getInstance(); final CountDownLatch latch = new CountDownLatch(1); diff --git a/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServicePutHandlerTest.java b/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServicePutHandlerTest.java index a30c58f5..d1994401 100644 --- a/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServicePutHandlerTest.java +++ b/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServicePutHandlerTest.java @@ -36,7 +36,7 @@ public class Oauth2ServicePutHandlerTest { @Test public void testOauth2ServicePutHandler() throws ClientException, ApiException, UnsupportedEncodingException { - String service = "{\"serviceId\":\"AACT0001\",\"serviceType\":\"ms\",\"serviceName\":\"Retail Account\",\"serviceDesc\":\"Microservices for Retail Account\",\"scope\":\"act.r act.w\",\"ownerId\":\"admin\"}"; + String service = "{\"serviceId\":\"AACT0001\",\"serviceType\":\"swagger\",\"serviceName\":\"Retail Account\",\"serviceDesc\":\"Microservices for Retail Account\",\"scope\":\"act.r act.w\",\"ownerId\":\"admin\"}"; final AtomicReference reference = new AtomicReference<>(); final Http2Client client = Http2Client.getInstance(); final CountDownLatch latch = new CountDownLatch(1); @@ -75,7 +75,7 @@ public void run() { @Test public void testOwnerNotFound() throws ClientException, ApiException, UnsupportedEncodingException { - String service = "{\"serviceId\":\"AACT0001\",\"serviceType\":\"ms\",\"serviceName\":\"Retail Account\",\"serviceDesc\":\"Microservices for Retail Account\",\"scope\":\"act.r act.w\",\"ownerId\":\"fake\"}"; + String service = "{\"serviceId\":\"AACT0001\",\"serviceType\":\"swagger\",\"serviceName\":\"Retail Account\",\"serviceDesc\":\"Microservices for Retail Account\",\"scope\":\"act.r act.w\",\"ownerId\":\"fake\"}"; final AtomicReference reference = new AtomicReference<>(); final Http2Client client = Http2Client.getInstance(); final CountDownLatch latch = new CountDownLatch(1); diff --git a/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointDeleteHandlerTest.java b/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointDeleteHandlerTest.java new file mode 100644 index 00000000..05722818 --- /dev/null +++ b/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointDeleteHandlerTest.java @@ -0,0 +1,103 @@ + +package com.networknt.oauth.service.handler; + +import com.networknt.client.Http2Client; +import com.networknt.config.Config; +import com.networknt.exception.ApiException; +import com.networknt.exception.ClientException; +import com.networknt.status.Status; +import io.undertow.UndertowOptions; +import io.undertow.client.ClientConnection; +import io.undertow.client.ClientRequest; +import io.undertow.client.ClientResponse; +import io.undertow.util.Headers; +import io.undertow.util.Methods; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import java.io.IOException; + + +public class Oauth2ServiceServiceIdEndpointDeleteHandlerTest { + @ClassRule + public static TestServer server = TestServer.getInstance(); + + static final Logger logger = LoggerFactory.getLogger(Oauth2ServiceServiceIdEndpointDeleteHandlerTest.class); + static final boolean enableHttp2 = server.getServerConfig().isEnableHttp2(); + static final boolean enableHttps = server.getServerConfig().isEnableHttps(); + static final int httpPort = server.getServerConfig().getHttpPort(); + static final int httpsPort = server.getServerConfig().getHttpsPort(); + static final String url = enableHttp2 || enableHttps ? "https://localhost:" + httpsPort : "http://localhost:" + httpPort; + + @Test + public void testOauth2ServiceServiceIdEndpointDeleteHandlerTest() throws ClientException, ApiException { + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/service/AACT0002/endpoint").setMethod(Methods.DELETE); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(200, statusCode); + Assert.assertNotNull(body); + } + + @Test + public void testServiceEndpointNotFound() throws ClientException, IOException { + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/service/AACT0003/endpoint").setMethod(Methods.DELETE); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(404, statusCode); + if(statusCode == 404) { + Status status = Config.getInstance().getMapper().readValue(body, Status.class); + Assert.assertNotNull(status); + Assert.assertEquals("ERR12042", status.getCode()); + Assert.assertEquals("SERVICE_ENDPOINT_NOT_FOUND", status.getMessage()); + } + } + +} diff --git a/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointGetHandlerTest.java b/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointGetHandlerTest.java new file mode 100644 index 00000000..1364aadb --- /dev/null +++ b/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointGetHandlerTest.java @@ -0,0 +1,100 @@ + +package com.networknt.oauth.service.handler; + +import com.networknt.client.Http2Client; +import com.networknt.config.Config; +import com.networknt.exception.ApiException; +import com.networknt.exception.ClientException; +import com.networknt.status.Status; +import io.undertow.UndertowOptions; +import io.undertow.client.ClientConnection; +import io.undertow.client.ClientRequest; +import io.undertow.client.ClientResponse; +import io.undertow.util.Methods; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import java.io.IOException; + + +public class Oauth2ServiceServiceIdEndpointGetHandlerTest { + @ClassRule + public static TestServer server = TestServer.getInstance(); + + static final Logger logger = LoggerFactory.getLogger(Oauth2ServiceServiceIdEndpointGetHandlerTest.class); + static final boolean enableHttp2 = server.getServerConfig().isEnableHttp2(); + static final boolean enableHttps = server.getServerConfig().isEnableHttps(); + static final int httpPort = server.getServerConfig().getHttpPort(); + static final int httpsPort = server.getServerConfig().getHttpsPort(); + static final String url = enableHttp2 || enableHttps ? "https://localhost:" + httpsPort : "http://localhost:" + httpPort; + + @Test + public void testOauth2ServiceServiceIdEndpointGetHandlerTest() throws ClientException, ApiException { + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/service/AACT0001/endpoint").setMethod(Methods.GET); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(200, statusCode); + Assert.assertNotNull(body); + } + + @Test + public void testServiceEndpointNotFound() throws ClientException, IOException { + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/service/AACT0003/endpoint").setMethod(Methods.GET); + connection.sendRequest(request, client.createClientCallback(reference, latch)); + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(404, statusCode); + if(statusCode == 404) { + Status status = Config.getInstance().getMapper().readValue(body, Status.class); + Assert.assertNotNull(status); + Assert.assertEquals("ERR12042", status.getCode()); + Assert.assertEquals("SERVICE_ENDPOINT_NOT_FOUND", status.getMessage()); + } + } + +} diff --git a/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointPostHandlerTest.java b/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointPostHandlerTest.java new file mode 100644 index 00000000..afe62385 --- /dev/null +++ b/service/src/test/java/com/networknt/oauth/service/handler/Oauth2ServiceServiceIdEndpointPostHandlerTest.java @@ -0,0 +1,109 @@ + +package com.networknt.oauth.service.handler; + +import com.networknt.client.Http2Client; +import com.networknt.config.Config; +import com.networknt.exception.ApiException; +import com.networknt.exception.ClientException; +import com.networknt.status.Status; +import io.undertow.UndertowOptions; +import io.undertow.client.ClientConnection; +import io.undertow.client.ClientRequest; +import io.undertow.client.ClientResponse; +import io.undertow.util.Headers; +import io.undertow.util.Methods; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import java.io.IOException; + + +public class Oauth2ServiceServiceIdEndpointPostHandlerTest { + @ClassRule + public static TestServer server = TestServer.getInstance(); + + static final Logger logger = LoggerFactory.getLogger(Oauth2ServiceServiceIdEndpointPostHandlerTest.class); + static final boolean enableHttp2 = server.getServerConfig().isEnableHttp2(); + static final boolean enableHttps = server.getServerConfig().isEnableHttps(); + static final int httpPort = server.getServerConfig().getHttpPort(); + static final int httpsPort = server.getServerConfig().getHttpsPort(); + static final String url = enableHttp2 || enableHttps ? "https://localhost:" + httpsPort : "http://localhost:" + httpPort; + + @Test + public void testOauth2ServiceServiceIdEndpointPostHandlerTest() throws ClientException, ApiException { + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + String requestBody = "[{\"endpoint\":\"/v1/data@post\",\"operation\":\"createData\",\"scope\":\"data.w\"},{\"endpoint\":\"/v1/data@put\",\"operation\":\"updateData\",\"scope\":\"data.w\"},{\"endpoint\":\"/v1/data@get\",\"operation\":\"retrieveData\",\"scope\":\"data.r\"},{\"endpoint\":\"/v1/data@delete\",\"operation\":\"deleteData\",\"scope\":\"data.w\"}]"; + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/service/AACT0001/endpoint").setMethod(Methods.POST); + + request.getRequestHeaders().put(Headers.CONTENT_TYPE, "application/json"); + request.getRequestHeaders().put(Headers.TRANSFER_ENCODING, "chunked"); + connection.sendRequest(request, client.createClientCallback(reference, latch, requestBody)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(200, statusCode); + Assert.assertNotNull(body); + } + + @Test + public void testServiceNotFound() throws ClientException, IOException { + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + String requestBody = "[{\"endpoint\":\"/v1/data@post\",\"operation\":\"createData\",\"scope\":\"data.w\"},{\"endpoint\":\"/v1/data@put\",\"operation\":\"updateData\",\"scope\":\"data.w\"},{\"endpoint\":\"/v1/data@get\",\"operation\":\"retrieveData\",\"scope\":\"data.r\"},{\"endpoint\":\"/v1/data@delete\",\"operation\":\"deleteData\",\"scope\":\"data.w\"}]"; + try { + ClientRequest request = new ClientRequest().setPath("/oauth2/service/fake/endpoint").setMethod(Methods.POST); + + request.getRequestHeaders().put(Headers.CONTENT_TYPE, "application/json"); + request.getRequestHeaders().put(Headers.TRANSFER_ENCODING, "chunked"); + connection.sendRequest(request, client.createClientCallback(reference, latch, requestBody)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(404, statusCode); + if(statusCode == 404) { + Status status = Config.getInstance().getMapper().readValue(body, Status.class); + Assert.assertNotNull(status); + Assert.assertEquals("ERR12015", status.getCode()); + Assert.assertEquals("SERVICE_NOT_FOUND", status.getMessage()); + } + } + +} diff --git a/service/src/test/java/com/networknt/oauth/service/handler/ServerInfoGetHandlerTest.java b/service/src/test/java/com/networknt/oauth/service/handler/ServerInfoGetHandlerTest.java new file mode 100644 index 00000000..831ef599 --- /dev/null +++ b/service/src/test/java/com/networknt/oauth/service/handler/ServerInfoGetHandlerTest.java @@ -0,0 +1,68 @@ + +package com.networknt.oauth.service.handler; + +import com.networknt.client.Http2Client; +import com.networknt.exception.ApiException; +import com.networknt.exception.ClientException; +import io.undertow.UndertowOptions; +import io.undertow.client.ClientConnection; +import io.undertow.client.ClientRequest; +import io.undertow.client.ClientResponse; +import io.undertow.util.Headers; +import io.undertow.util.Methods; +import org.junit.Assert; +import org.junit.ClassRule; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xnio.IoUtils; +import org.xnio.OptionMap; +import java.net.URI; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.atomic.AtomicReference; + +import java.io.IOException; + + +public class ServerInfoGetHandlerTest { + @ClassRule + public static TestServer server = TestServer.getInstance(); + + static final Logger logger = LoggerFactory.getLogger(ServerInfoGetHandlerTest.class); + static final boolean enableHttp2 = server.getServerConfig().isEnableHttp2(); + static final boolean enableHttps = server.getServerConfig().isEnableHttps(); + static final int httpPort = server.getServerConfig().getHttpPort(); + static final int httpsPort = server.getServerConfig().getHttpsPort(); + static final String url = enableHttp2 || enableHttps ? "https://localhost:" + httpsPort : "http://localhost:" + httpPort; + + @Test + public void testServerInfoGetHandlerTest() throws ClientException, ApiException { + /* + final Http2Client client = Http2Client.getInstance(); + final CountDownLatch latch = new CountDownLatch(1); + final ClientConnection connection; + try { + connection = client.connect(new URI(url), Http2Client.WORKER, Http2Client.SSL, Http2Client.POOL, enableHttp2 ? OptionMap.create(UndertowOptions.ENABLE_HTTP2, true): OptionMap.EMPTY).get(); + } catch (Exception e) { + throw new ClientException(e); + } + final AtomicReference reference = new AtomicReference<>(); + try { + ClientRequest request = new ClientRequest().setPath("/server/info").setMethod(Methods.GET); + + connection.sendRequest(request, client.createClientCallback(reference, latch)); + + latch.await(); + } catch (Exception e) { + logger.error("Exception: ", e); + throw new ClientException(e); + } finally { + IoUtils.safeClose(connection); + } + int statusCode = reference.get().getResponseCode(); + String body = reference.get().getAttachment(Http2Client.RESPONSE_BODY); + Assert.assertEquals(200, statusCode); + Assert.assertNotNull(body); + */ + } +} diff --git a/service/src/test/java/com/networknt/oauth/service/handler/TestServer.java b/service/src/test/java/com/networknt/oauth/service/handler/TestServer.java index 228e30ab..e872d9cb 100644 --- a/service/src/test/java/com/networknt/oauth/service/handler/TestServer.java +++ b/service/src/test/java/com/networknt/oauth/service/handler/TestServer.java @@ -13,6 +13,8 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.concurrent.atomic.AtomicInteger; +import com.networknt.server.Server; +import com.networknt.server.ServerConfig; import static java.nio.charset.StandardCharsets.UTF_8; @@ -45,6 +47,10 @@ private TestServer() { } } + public ServerConfig getServerConfig() { + return Server.config; + } + @Override protected void before() { try { diff --git a/service/src/test/resources/config/swagger.json b/service/src/test/resources/config/swagger.json index c4944407..c51d14a3 100644 --- a/service/src/test/resources/config/swagger.json +++ b/service/src/test/resources/config/swagger.json @@ -198,31 +198,109 @@ ] } }, - "/server/info": { - "get": { + "/oauth2/service/{serviceId}/endpoint": { + "post": { + "description": "create endpoints for service", + "operationId": "createServiceEndpoint", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + }, + { + "in": "body", + "name": "body", + "description": "A list of endpoint object", + "required": true, + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ServiceEndpoint" + } + } + } + ], + "responses": { + "201": { + "description": "Successful response" + } + }, "security": [ { "service_auth": [ - "server.info.r" + "oauth.service.w" ] } + ] + }, + "delete": { + "description": "Delete all endpoints for a service", + "operationId": "deleteServiceEndpoint", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } ], "responses": { - "200": { - "description": "successful operation" + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "Service not found" } }, - "parameters": [] - } - }, - "/health": { + "security": [ + { + "service_auth": [ + "oauth.service.w" + ] + } + ] + }, "get": { + "description": "Get all endpoints for a service", + "operationId": "getServiceEndpoint", + "parameters": [ + { + "name": "serviceId", + "in": "path", + "description": "Service Id", + "required": true, + "type": "string" + } + ], "responses": { "200": { - "description": "successful operation" + "description": "Successful response", + "schema": { + "type": "array", + "items": { + "$ref": "#/definitions/ServiceEndpoint" + } + } + }, + "400": { + "description": "Invalid serviceId supplied" + }, + "404": { + "description": "ServiceEndpoint not found" } }, - "parameters": [] + "security": [ + { + "service_auth": [ + "oauth.service.r", + "oauth.service.w" + ] + } + ] } } }, @@ -233,8 +311,7 @@ "flow": "implicit", "scopes": { "oauth.service.w": "write oauth service", - "oauth.service.r": "read oauth service", - "server.info.r": "read server info" + "oauth.service.r": "read oauth service" } } }, @@ -256,8 +333,10 @@ "type": "string", "description": "service type", "enum": [ - "ms", - "api" + "swagger", + "openapi", + "graphql", + "hybrid" ] }, "serviceName": { @@ -287,6 +366,28 @@ "description": "update date time" } } + }, + "ServiceEndpoint": { + "type": "object", + "required": [ + "endpoint", + "operation", + "scope" + ], + "properties": { + "endpoint": { + "type": "string", + "description": "a combination of path and method to uniquely identify an operation" + }, + "operation": { + "type": "string", + "description": "operationId of the endpoint" + }, + "scope": { + "type": "string", + "description": "scope associated with the endpoint" + } + } } } } \ No newline at end of file diff --git a/service/src/test/resources/create_h2.sql b/service/src/test/resources/create_h2.sql index 35b7fbc5..67719900 100644 --- a/service/src/test/resources/create_h2.sql +++ b/service/src/test/resources/create_h2.sql @@ -1,50 +1,83 @@ -DROP table IF EXISTS users; -DROP table IF EXISTS clients; -DROP table IF EXISTS services; +DROP table IF EXISTS user_profile; +DROP table IF EXISTS client; +DROP table IF EXISTS service; +DROP table IF EXISTS service_endpoint; +DROP table IF EXISTS client_service; +DROP table IF EXISTS audit_log; -create table users ( +create table user_profile ( user_id varchar PRIMARY KEY, user_type varchar, -- admin, customer, employee, partner first_name varchar, last_name varchar, email varchar, - password varchar, - create_dt DATE, - update_dt DATE + password varchar ); -CREATE UNIQUE INDEX email_idx ON users(email); +CREATE UNIQUE INDEX email_idx ON user_profile(email); -create table clients ( +create table client ( client_id VARCHAR PRIMARY KEY, - client_type VARCHAR, client_secret VARCHAR, - client_profile VARCHAR, + client_type VARCHAR, -- public, confidential, trusted + client_profile VARCHAR, -- server, mobile, service, batch, browser client_name VARCHAR, client_desc VARCHAR, scope VARCHAR, redirect_uri VARCHAR, authenticate_class VARCHAR, - owner_id VARCHAR, - create_dt DATE, - update_dt DATE + owner_id VARCHAR ); -create table services ( +create table service ( service_id VARCHAR PRIMARY KEY, - service_type VARCHAR, -- api, ms + service_type VARCHAR, -- swagger, openapi, graphql, hybrid service_name VARCHAR, service_desc VARCHAR, scope VARCHAR, - owner_id VARCHAR, - create_dt DATE, - update_dt DATE + owner_id VARCHAR ); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +create table service_endpoint ( + service_id VARCHAR, + endpoint VARCHAR, -- different framework will have different endpoint format. + operation VARCHAR, + scope VARCHAR, + PRIMARY KEY (service_id, endpoint), + FOREIGN KEY (service_id) REFERENCES service(service_id) +); + +create table client_service ( + client_id VARCHAR NOT NULL, + service_id VARCHAR NOT NULL, + endpoint VARCHAR NOT NULL, -- different framework will have different endpoint format. + PRIMARY KEY (client_id, service_id, endpoint), + FOREIGN KEY (service_id, endpoint) REFERENCES service_endpoint(service_id, endpoint), + FOREIGN KEY (client_id) REFERENCES client(client_id) +); + +create table audit_log ( + log_id INT, + service_id VARCHAR NOT NULL, + path VARCHAR NOT NULL, + method VARCHAR NOT NULL, + request_header VARCHAR, + request_body VARCHAR, + response_code INT, + response_header VARCHAR, + response_body VARCHAR, +); + + +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); + +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); + +INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'openapi', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); +INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0002', 'openapi', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO service_endpoint(service_id, endpoint, operation, scope) VALUES ('AACT0001', '/v1/getData@get', 'retrieve data', 'data.r'); +INSERT INTO service_endpoint(service_id, endpoint, operation, scope) VALUES ('AACT0001', '/v1/postData@post', 'create data', 'data.w'); -INSERT INTO services (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); -INSERT INTO services (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0002', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); +INSERT INTO service_endpoint(service_id, endpoint, operation, scope) VALUES ('AACT0002', '/v1/deleteData@delete', 'deleteData', 'data.w'); \ No newline at end of file diff --git a/token/docker/Dockerfile b/token/Dockerfile similarity index 100% rename from token/docker/Dockerfile rename to token/Dockerfile diff --git a/token/build.sh b/token/build.sh index a79dc89c..b815e712 100755 --- a/token/build.sh +++ b/token/build.sh @@ -42,7 +42,7 @@ cleanup() { publish() { echo "Building Docker image with version $VERSION" - docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./docker/Dockerfile . --no-cache=true + docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./Dockerfile . --no-cache=true docker build -t $IMAGE_NAME:$VERSION-redhat -f ./docker/Dockerfile-Redhat . --no-cache=true echo "Images built with version $VERSION" echo "Pushing image to DockerHub" diff --git a/token/docker/Dockerfile-Redhat b/token/docker/Dockerfile-Redhat index 9c6a1c2e..a3ec07be 100644 --- a/token/docker/Dockerfile-Redhat +++ b/token/docker/Dockerfile-Redhat @@ -2,27 +2,30 @@ FROM registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift USER root -ENV APP_DIR=/app \ +ENV APP_DIR=app \ GROUP_NAME=networknt \ GROUP_ID=1000 \ USER_NAME=networknt \ USER_UID=1000 RUN groupadd -g ${GROUP_ID} -r ${GROUP_NAME} && \ - useradd -u ${USER_UID} -g ${GROUP_NAME} -d "${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} + useradd -u ${USER_UID} -g ${GROUP_NAME} -d "/${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} # Add the jar file into the container at /app -ADD target/oauth2-token.jar ${APP_DIR}/server.jar +ADD target/oauth2-token.jar ./${APP_DIR}/server.jar # change permissions of app directory -RUN chown -R ${USER_NAME}:${GROUP_NAME} "${APP_DIR}" +RUN mkdir -p ./${APP_DIR}/config && \ + chown -R ${USER_NAME}:0 "./${APP_DIR}/config" && \ + find "./${APP_DIR}/config" -type d -exec chmod 750 {} \; && \ + find "./${APP_DIR}/config" -type f -exec chmod 640 {} \; # Port available to the world outside of this container -EXPOSE 6882 +EXPOSE 8080 USER ${USER_UID} # Set the working directory to /app -WORKDIR ${APP_DIR} +WORKDIR ./${APP_DIR} -CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] +CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] \ No newline at end of file diff --git a/token/src/main/resources/logback.xml b/token/src/main/resources/logback.xml index 6e58aff8..455f137d 100644 --- a/token/src/main/resources/logback.xml +++ b/token/src/main/resources/logback.xml @@ -28,7 +28,7 @@ - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n @@ -36,7 +36,7 @@ target/test.log false - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %class{36}:%L %M - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n diff --git a/token/src/test/resources/create_h2.sql b/token/src/test/resources/create_h2.sql index 423a5fe0..0c334c8b 100644 --- a/token/src/test/resources/create_h2.sql +++ b/token/src/test/resources/create_h2.sql @@ -1,8 +1,8 @@ -DROP table IF EXISTS users; -DROP table IF EXISTS clients; -DROP table IF EXISTS services; +DROP table IF EXISTS user_profile; +DROP table IF EXISTS client; +DROP table IF EXISTS service; -create table users ( +create table user_profile ( user_id varchar PRIMARY KEY, user_type varchar, -- admin, customer, employee, partner first_name varchar, @@ -13,13 +13,13 @@ create table users ( update_dt DATE ); -CREATE UNIQUE INDEX email_idx ON users(email); +CREATE UNIQUE INDEX email_idx ON user_profile(email); -create table clients ( +create table client ( client_id VARCHAR PRIMARY KEY, - client_type VARCHAR, client_secret VARCHAR, - client_profile VARCHAR, + client_type VARCHAR, -- public, confidential, trusted + client_profile VARCHAR, -- server, mobile, service, batch, browser client_name VARCHAR, client_desc VARCHAR, scope VARCHAR, @@ -30,7 +30,7 @@ create table clients ( update_dt DATE ); -create table services ( +create table service ( service_id VARCHAR PRIMARY KEY, service_type VARCHAR, -- api, ms service_name VARCHAR, @@ -41,12 +41,12 @@ create table services ( update_dt DATE ); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO clients (client_id, client_type, client_profile, client_secret, client_name, client_desc, scope, redirect_uri, owner_id) +INSERT INTO client (client_id, client_type, client_profile, client_secret, client_name, client_desc, scope, redirect_uri, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'trusted', 'mobile', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', 'admin' ); -INSERT INTO clients (client_id, client_type, client_profile, client_secret, client_name, client_desc, scope, redirect_uri, owner_id) +INSERT INTO client (client_id, client_type, client_profile, client_secret, client_name, client_desc, scope, redirect_uri, owner_id) VALUES('6e9d1db3-2feb-4c1f-a5ad-9e93ae8ca59d', 'public', 'mobile', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', 'admin' ); -INSERT INTO services (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); +INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin'); diff --git a/user/docker/Dockerfile b/user/Dockerfile similarity index 100% rename from user/docker/Dockerfile rename to user/Dockerfile diff --git a/user/build.sh b/user/build.sh index 38d3a24a..e79dcb92 100755 --- a/user/build.sh +++ b/user/build.sh @@ -42,7 +42,7 @@ cleanup() { publish() { echo "Building Docker image with version $VERSION" - docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./docker/Dockerfile . --no-cache=true + docker build -t $IMAGE_NAME:$VERSION -t $IMAGE_NAME:latest -f ./Dockerfile . --no-cache=true docker build -t $IMAGE_NAME:$VERSION-redhat -f ./docker/Dockerfile-Redhat . --no-cache=true echo "Images built with version $VERSION" echo "Pushing image to DockerHub" diff --git a/user/docker/Dockerfile-Redhat b/user/docker/Dockerfile-Redhat index 90798fa1..fb798aee 100644 --- a/user/docker/Dockerfile-Redhat +++ b/user/docker/Dockerfile-Redhat @@ -2,27 +2,30 @@ FROM registry.access.redhat.com/redhat-openjdk-18/openjdk18-openshift USER root -ENV APP_DIR=/app \ +ENV APP_DIR=app \ GROUP_NAME=networknt \ GROUP_ID=1000 \ USER_NAME=networknt \ USER_UID=1000 RUN groupadd -g ${GROUP_ID} -r ${GROUP_NAME} && \ - useradd -u ${USER_UID} -g ${GROUP_NAME} -d "${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} + useradd -u ${USER_UID} -g ${GROUP_NAME} -d "/${APP_DIR}" -s /sbin/nologin -c "${USER_NAME} user" ${USER_NAME} # Add the jar file into the container at /app -ADD target/oauth2-user.jar ${APP_DIR}/server.jar +ADD target/oauth2-user.jar ./${APP_DIR}/server.jar # change permissions of app directory -RUN chown -R ${USER_NAME}:${GROUP_NAME} "${APP_DIR}" +RUN mkdir -p ./${APP_DIR}/config && \ + chown -R ${USER_NAME}:0 "./${APP_DIR}/config" && \ + find "./${APP_DIR}/config" -type d -exec chmod 750 {} \; && \ + find "./${APP_DIR}/config" -type f -exec chmod 640 {} \; # Port available to the world outside of this container -EXPOSE 6885 +EXPOSE 8080 USER ${USER_UID} # Set the working directory to /app -WORKDIR ${APP_DIR} +WORKDIR ./${APP_DIR} -CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] +CMD ["/bin/sh","-c","java -Dlight-4j-config-dir=/config -Dlogback.configurationFile=/config/logback.xml -jar server.jar"] \ No newline at end of file diff --git a/user/src/main/resources/logback.xml b/user/src/main/resources/logback.xml index 6e58aff8..455f137d 100644 --- a/user/src/main/resources/logback.xml +++ b/user/src/main/resources/logback.xml @@ -28,7 +28,7 @@ - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %logger{36} - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n @@ -36,7 +36,7 @@ target/test.log false - %d{HH:mm:ss.SSS} [%thread] %X{cId} %-5level %class{36}:%L %M - %msg%n + %d{HH:mm:ss.SSS} [%thread] %X{sId} %X{cId} %-5level %class{36}:%L %M - %msg%n diff --git a/user/src/test/resources/create_h2.sql b/user/src/test/resources/create_h2.sql index a3818195..3a3fb7a0 100644 --- a/user/src/test/resources/create_h2.sql +++ b/user/src/test/resources/create_h2.sql @@ -1,8 +1,8 @@ -DROP table IF EXISTS users; -DROP table IF EXISTS clients; -DROP table IF EXISTS services; +DROP table IF EXISTS user_profile; +DROP table IF EXISTS client; +DROP table IF EXISTS service; -create table users ( +create table user_profile ( user_id varchar PRIMARY KEY, user_type varchar, -- admin, customer, employee, partner first_name varchar, @@ -13,13 +13,13 @@ create table users ( update_dt DATE ); -CREATE UNIQUE INDEX email_idx ON users(email); +CREATE UNIQUE INDEX email_idx ON user_profile(email); -create table clients ( +create table client ( client_id VARCHAR PRIMARY KEY, - client_type VARCHAR, client_secret VARCHAR, - client_profile VARCHAR, + client_type VARCHAR, -- public, confidential, trusted + client_profile VARCHAR, -- server, mobile, service, batch, browser client_name VARCHAR, client_desc VARCHAR, scope VARCHAR, @@ -30,7 +30,7 @@ create table clients ( update_dt DATE ); -create table services ( +create table service ( service_id VARCHAR PRIMARY KEY, service_type VARCHAR, -- api, ms service_name VARCHAR, @@ -41,24 +41,24 @@ create table services ( update_dt DATE ); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('delete', 'admin', 'test', 'test', 'delete@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('test01', 'admin', 'test', 'test', 'test01@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('test02', 'admin', 'test', 'test', 'test02@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('test03', 'admin', 'test', 'test', 'test03@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('test04', 'admin', 'test', 'test', 'test04@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('test05', 'admin', 'test', 'test', 'test05@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('test06', 'admin', 'test', 'test', 'test06@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('test07', 'admin', 'test', 'test', 'test07@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('test08', 'admin', 'test', 'test', 'test08@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('test09', 'admin', 'test', 'test', 'test09@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('test10', 'admin', 'test', 'test', 'test10@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('test11', 'admin', 'test', 'test', 'test11@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO users(user_id, user_type, first_name, last_name, email, password) VALUES('test12', 'admin', 'test', 'test', 'test12@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('admin', 'admin', 'admin', 'admin', 'admin@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('delete', 'admin', 'test', 'test', 'delete@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('test01', 'admin', 'test', 'test', 'test01@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('test02', 'admin', 'test', 'test', 'test02@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('test03', 'admin', 'test', 'test', 'test03@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('test04', 'admin', 'test', 'test', 'test04@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('test05', 'admin', 'test', 'test', 'test05@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('test06', 'admin', 'test', 'test', 'test06@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('test07', 'admin', 'test', 'test', 'test07@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('test08', 'admin', 'test', 'test', 'test08@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('test09', 'admin', 'test', 'test', 'test09@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('test10', 'admin', 'test', 'test', 'test10@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('test11', 'admin', 'test', 'test', 'test11@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); +INSERT INTO user_profile(user_id, user_type, first_name, last_name, email, password) VALUES('test12', 'admin', 'test', 'test', 'test12@networknt.com', '1000:5b39342c202d37372c203132302c202d3132302c2034372c2032332c2034352c202d34342c202d31362c2034372c202d35392c202d35362c2039302c202d352c202d38322c202d32385d:949e6fcf9c4bb8a3d6a8c141a3a9182a572fb95fe8ccdc93b54ba53df8ef2e930f7b0348590df0d53f242ccceeae03aef6d273a34638b49c559ada110ec06992'); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); -INSERT INTO clients (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('f7d42348-c647-4efb-a52d-4c5787421e72', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); +INSERT INTO client (client_id, client_type, client_secret, client_profile, client_name, client_desc, scope, redirect_uri, authenticate_class, owner_id) VALUES('59f347a0-c92d-11e6-9d9d-cec0c932ce01', 'public', '1000:5b37332c202d36362c202d36392c203131362c203132362c2036322c2037382c20342c202d37382c202d3131352c202d35332c202d34352c202d342c202d3132322c203130322c2033325d:29ad1fe88d66584c4d279a6f58277858298dbf9270ffc0de4317a4d38ba4b41f35f122e0825c466f2fa14d91e17ba82b1a2f2a37877a2830fae2973076d93cc2', 'mobile', 'PetStore Web Server', 'PetStore Web Server that calls PetStore API', 'petstore.r petstore.w', 'http://localhost:8080/authorization', null, 'admin' ); -INSERT INTO services (service_id, service_type, service_name, service_desc, scope, owner_id) +INSERT INTO service (service_id, service_type, service_name, service_desc, scope, owner_id) VALUES ('AACT0001', 'ms', 'Account Service', 'A microservice that serves account information', 'a.r b.r', 'admin');