From 36c15c407bf6b678a53352067d607b262375c35a Mon Sep 17 00:00:00 2001 From: Gbenga Taylor <30447678+gbengataylor@users.noreply.github.com> Date: Wed, 1 May 2019 13:16:19 -0400 Subject: [PATCH 1/9] Update README.md --- code/userprofile/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/userprofile/README.md b/code/userprofile/README.md index 53b591a..2d461a5 100644 --- a/code/userprofile/README.md +++ b/code/userprofile/README.md @@ -134,7 +134,8 @@ oc new-app -f ../../deployment/install/microservices/openshift-configuration/use ### Building a container image for this service You can use [s2i][4] to easily build this into a container image. For example to use the Quarkus Native image as our base: ```bash -s2i build . quay.io/quarkus/centos-quarkus-native-s2i:graalvm-1.0.0-rc15 openshift-microservices-userprofile --loglevel 3 +QUARKUS_VERSION_TAG=graalvm-1.0.0-rc15 +s2i build . quay.io/quarkus/centos-quarkus-native-s2i:$QUARKUS_VERSION_TAG openshift-microservices-userprofile --loglevel 3 ``` [1]: https://access.redhat.com/documentation/en-us/red_hat_single_sign-on/7.3/ From 6f27661f71a93ac6ac797f94dda6baa8a21c972b Mon Sep 17 00:00:00 2001 From: gbengataylor Date: Wed, 1 May 2019 13:48:52 -0400 Subject: [PATCH 2/9] upgrade to Quarkus 0.14.0 --- code/userprofile/pom.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/userprofile/pom.xml b/code/userprofile/pom.xml index df421b8..94ae2d1 100644 --- a/code/userprofile/pom.xml +++ b/code/userprofile/pom.xml @@ -7,8 +7,7 @@ 1.0-SNAPSHOT 2.22.0 - 0.13.1 - + 0.14.0 5.1.4.RELEASE UTF-8 1.8 From b743e8a55a00a082996a63e9f72338a432c52ecd Mon Sep 17 00:00:00 2001 From: Gbenga Taylor <30447678+gbengataylor@users.noreply.github.com> Date: Thu, 2 May 2019 12:52:58 -0400 Subject: [PATCH 3/9] Update README.md --- code/userprofile/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/userprofile/README.md b/code/userprofile/README.md index 2d461a5..464ec67 100644 --- a/code/userprofile/README.md +++ b/code/userprofile/README.md @@ -31,7 +31,7 @@ If running on localhost, the APU is accessible to test and download at: ## Developer instructions - JDK 8+ - Apache Maven 3.5.3+ is required -- Optional for native applications [GraalVM](https://www.graalvm.org/) +- Optional for native applications [GraalVM](https://www.graalvm.org/) . At least version 1.0.0-rc15 required ### Environment variables From d9eb33b67996c0db3f3b6427139757856e8c2709 Mon Sep 17 00:00:00 2001 From: gbengataylor Date: Thu, 23 May 2019 11:06:43 -0400 Subject: [PATCH 4/9] upgrade to 0.15.0 --- code/userprofile/pom.xml | 4 ++-- .../org/microservices/demo/rest/UserProfileResource.java | 7 ++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/code/userprofile/pom.xml b/code/userprofile/pom.xml index 94ae2d1..3f69c63 100644 --- a/code/userprofile/pom.xml +++ b/code/userprofile/pom.xml @@ -6,8 +6,8 @@ userprofile 1.0-SNAPSHOT - 2.22.0 - 0.14.0 + 2.22.1 + 0.15.0 5.1.4.RELEASE UTF-8 1.8 diff --git a/code/userprofile/src/main/java/org/microservices/demo/rest/UserProfileResource.java b/code/userprofile/src/main/java/org/microservices/demo/rest/UserProfileResource.java index 06d6c7d..f631ec6 100644 --- a/code/userprofile/src/main/java/org/microservices/demo/rest/UserProfileResource.java +++ b/code/userprofile/src/main/java/org/microservices/demo/rest/UserProfileResource.java @@ -81,9 +81,8 @@ public Set getProfiles() { @POST @APIResponse(responseCode = "201", description = "User Profile Created") @APIResponse(responseCode = "400", description = "Bad Request") - // comment out JSR annotations so OpenAPI schema is generated // submitted https://github.com/quarkusio/quarkus/issues/2262s - public Response createProfile(/*@Valid @NotNull*/ UserProfile profile) { + public Response createProfile(@Valid @NotNull UserProfile profile) { return userProfileService.createProfile(profile) ? Response.status(Response.Status.CREATED).build() : Response.status(Response.Status.BAD_REQUEST).build(); } @@ -105,9 +104,7 @@ public Response getProfile(@PathParam("id") String id) { @PUT @Path("/{id}") @APIResponse(responseCode = "204", description = "User Profile Updated") - @APIResponse(responseCode = "400", description = "Bad Request") - // comment out JSR annotations so OpenAPI schema is generated - public Response updateProfile(/*@Valid @NotNull*/ UserProfile profile, @PathParam("id") String id) { + public Response updateProfile(@Valid @NotNull UserProfile profile, @PathParam("id") String id) { // does it exist return userProfileService.updateProfile(profile, id) ? Response.status(Response.Status.NO_CONTENT).build() : Response.status(Response.Status.BAD_REQUEST).build(); From 44687b6020e02e1e33f55b06ee8c9b765c350510 Mon Sep 17 00:00:00 2001 From: gbengataylor Date: Thu, 23 May 2019 11:30:18 -0400 Subject: [PATCH 5/9] update s2i image version --- code/userprofile/README.md | 4 ++-- code/userprofile/s2i.sh | 2 +- code/userprofile/template.sh | 2 +- .../openshift-configuration/userprofile-fromsource.yaml | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/code/userprofile/README.md b/code/userprofile/README.md index 464ec67..537954f 100644 --- a/code/userprofile/README.md +++ b/code/userprofile/README.md @@ -121,7 +121,7 @@ You can use a template to create all the build and deployment resources for Open POSTGRESQL_SERVICE_HOST=userprofile-postgresql USER_PROFILE_GIT_REPO=https://github.com/dudash/openshift-microservices USER_PROFILE_GIT_BRANCH=master -QUARKUS_VERSION_TAG=graalvm-1.0.0-rc15 +QUARKUS_VERSION_TAG=graalvm-1.0.0-rc16 oc new-app -f ../../deployment/install/microservices/openshift-configuration/userprofile-fromsource.yaml -p QUARKUS_VERSION_TAG=${QUARKUS_VERSION_TAG} -p GIT_URI=${USER_PROFILE_GIT_REPO} -p GIT_BRANCH=${USER_PROFILE_GIT_BRANCH} -p DATABASE_SERVICE_NAME=${POSTGRESQL_SERVICE_HOST} @@ -134,7 +134,7 @@ oc new-app -f ../../deployment/install/microservices/openshift-configuration/use ### Building a container image for this service You can use [s2i][4] to easily build this into a container image. For example to use the Quarkus Native image as our base: ```bash -QUARKUS_VERSION_TAG=graalvm-1.0.0-rc15 +QUARKUS_VERSION_TAG=graalvm-1.0.0-rc16 s2i build . quay.io/quarkus/centos-quarkus-native-s2i:$QUARKUS_VERSION_TAG openshift-microservices-userprofile --loglevel 3 ``` diff --git a/code/userprofile/s2i.sh b/code/userprofile/s2i.sh index cffbb46..bfb13f6 100755 --- a/code/userprofile/s2i.sh +++ b/code/userprofile/s2i.sh @@ -25,7 +25,7 @@ done # #using specific version of s2i as latest (rc16 wasn't working) # this can be improved to use the generated secret from postgressql deploy. for now just use env variable -oc new-app quay.io/quarkus/centos-quarkus-native-s2i:graalvm-1.0.0-rc15~${USER_PROFILE_GIT_REPO}#${USER_PROFILE_GIT_BRANCH} \ +oc new-app quay.io/quarkus/centos-quarkus-native-s2i:graalvm-1.0.0-rc16~${USER_PROFILE_GIT_REPO}#${USER_PROFILE_GIT_BRANCH} \ --context-dir=/code/userprofile --name=userprofile -luserprofile-component=microservice \ --env POSTGRESQL_USER=$POSTGRESQL_USER \ --env POSTGRESQL_PASSWORD=$POSTGRESQL_PASSWORD \ diff --git a/code/userprofile/template.sh b/code/userprofile/template.sh index 3981057..61f0daa 100755 --- a/code/userprofile/template.sh +++ b/code/userprofile/template.sh @@ -2,7 +2,7 @@ POSTGRESQL_SERVICE_HOST=userprofile-postgresql USER_PROFILE_GIT_REPO=https://github.com/gbengataylor/openshift-microservices USER_PROFILE_GIT_BRANCH=develop -QUARKUS_VERSION_TAG=graalvm-1.0.0-rc15 +QUARKUS_VERSION_TAG=graalvm-1.0.0-rc16 APPLICATION_IMAGE_URI=quay.io/gbengataylor/openshift-microservices-userprofile #s2i -- build and deploy from source diff --git a/deployment/install/microservices/openshift-configuration/userprofile-fromsource.yaml b/deployment/install/microservices/openshift-configuration/userprofile-fromsource.yaml index 4aab3ae..a3e0a90 100644 --- a/deployment/install/microservices/openshift-configuration/userprofile-fromsource.yaml +++ b/deployment/install/microservices/openshift-configuration/userprofile-fromsource.yaml @@ -2,7 +2,7 @@ # Usage example: # oc new-app -f ./userprofile-fromsource.yaml \ # -p APPLICATION_NAME=userprofile \ -# -p QUARKUS_IMAGE_TAG=graalvm-1.0.0-rc15 \ +# -p QUARKUS_IMAGE_TAG=graalvm-1.0.0-rc16 \ # -p GIT_URI=https://github.com/dudash/openshift-microservices.git \ # -p GIT_BRANCH=develop \ # -p DATABASE_SERVICE_NAME=userprofile-postgresql @@ -393,7 +393,7 @@ parameters: displayName: Quarkus version tag name: QUARKUS_VERSION_TAG required: true - value: 'graalvm-1.0.0-rc15' + value: 'graalvm-1.0.0-rc16' - description: Maximum amount of memory the container can use. displayName: Memory Limit name: MEMORY_LIMIT From 5576a06bc5617e015fda24340b719aae2411b7dc Mon Sep 17 00:00:00 2001 From: gbengataylor Date: Fri, 24 May 2019 17:13:53 -0400 Subject: [PATCH 6/9] auth import changes --- code/auth/README.md | 14 +- .../auth-sso73-x509.yaml | 33 +- .../openshift-configuration/import-realm.json | 2217 +++++++++++++++++ .../openshift-configuration/userprofile.yaml | 4 +- .../install/microservices/services-install.sh | 2 + 5 files changed, 2255 insertions(+), 15 deletions(-) create mode 100644 deployment/install/microservices/openshift-configuration/import-realm.json diff --git a/code/auth/README.md b/code/auth/README.md index 948a96a..be03a8a 100644 --- a/code/auth/README.md +++ b/code/auth/README.md @@ -42,15 +42,15 @@ This repo utilizes a OpenShift's source-to-image (s2i) for customizing and layer ### Building this service Build requires an OpenShift cluster the new-build must point to a git repo or be pointing to a locally cloned branch. For secrets, branches and other options type `oc new-build -h` ```bash -oc new-build redhat-sso-7/sso73-openshift:latest~https://github.com/dudash/openshift-microservices.git#develop \ +oc new-build redhat-sso73-openshift:latest~https://github.com/dudash/openshift-microservices.git#develop \ --name=auth \ - -l app=auth-sso73-x509 + -l app=auth-sso73-x509 \ + --context-dir=/code/auth ``` ### Building a container image for this service As an alternative to building on OpenShift, you can use [s2i][4] to build this into a container image. For example: ```bash -rm -rf node_modules s2i build . registry.access.redhat.com/redhat-sso-7/sso73-openshift openshift-microservices-auth ``` @@ -61,19 +61,25 @@ You can use a template to create all the OpenShift resources. Optionally, set pa - SSO_ADMIN_PASSWORD - SSO_REALM - APPLICATION_NAME +- POSTGRESQL_IMAGE_STREAM_TAG For example: ```bash + oc create configmap sso-realm \ + --from-file=../../deployment/install/microservices/openshift-configuration/import-realm.json + oc new-app -f ../../deployment/install/microservices/openshift-configuration/auth-sso73-x509.yaml \ -p SSO_ADMIN_USERNAME="admin" \ -p SSO_ADMIN_PASSWORD="password" \ -p SSO_REALM="microservices" \ - -p AUTH_IMAGE_STREAM_NAMESPACE=microservices-demo + -p AUTH_IMAGE_STREAM_NAMESPACE=microservices-demo \ + -p POSTGRESQL_IMAGE_STREAM_TAG='9.6' ``` deleting services related to this app only: ```bash oc delete all -l app=auth-sso73-x509 +oc delete configmap sso-realm ``` ### Environment variables diff --git a/deployment/install/microservices/openshift-configuration/auth-sso73-x509.yaml b/deployment/install/microservices/openshift-configuration/auth-sso73-x509.yaml index 3fab02f..a5216fd 100644 --- a/deployment/install/microservices/openshift-configuration/auth-sso73-x509.yaml +++ b/deployment/install/microservices/openshift-configuration/auth-sso73-x509.yaml @@ -148,7 +148,7 @@ objects: - name: SSO_ADMIN_PASSWORD value: ${SSO_ADMIN_PASSWORD} - name: SSO_REALM - value: ${SSO_REALM} + value: ${SSO_REALM} - name: SSO_SERVICE_USERNAME value: ${SSO_SERVICE_USERNAME} - name: SSO_SERVICE_PASSWORD @@ -192,6 +192,9 @@ objects: - mountPath: /etc/x509/jgroups name: sso-x509-jgroups-volume readOnly: true + - mountPath: /opt/eap/standalone/configuration/import-realm.json + name: sso-import-realm-volume + subPath: import-realm.json terminationGracePeriodSeconds: 75 volumes: - name: sso-x509-https-volume @@ -200,6 +203,12 @@ objects: - name: sso-x509-jgroups-volume secret: secretName: sso-x509-jgroups-secret + - name: sso-import-realm-volume + configMap: + name: sso-realm + items: + - key: import-realm.json + path: import-realm.json triggers: - imageChangeParams: automatic: true @@ -250,9 +259,13 @@ objects: imagePullPolicy: Always livenessProbe: initialDelaySeconds: 30 - tcpSocket: - port: 5432 - timeoutSeconds: 1 + exec: + command: + - /usr/libexec/check-container + - '--live' + # tcpSocket: + # port: 5432 + # timeoutSeconds: 1 name: ${APPLICATION_NAME}-postgresql ports: - containerPort: 5432 @@ -260,11 +273,13 @@ objects: readinessProbe: exec: command: - - /bin/sh - - -i - - -c - - psql -h 127.0.0.1 -U $POSTGRESQL_USER -q -d $POSTGRESQL_DATABASE -c - 'SELECT 1' + # - /bin/sh + # - -i + # - -c + # - psql -h 127.0.0.1 -U $POSTGRESQL_USER -q -d $POSTGRESQL_DATABASE -c + # 'SELECT 1' + # 'SELECT 1' + - /usr/libexec/check-container initialDelaySeconds: 5 timeoutSeconds: 1 volumeMounts: diff --git a/deployment/install/microservices/openshift-configuration/import-realm.json b/deployment/install/microservices/openshift-configuration/import-realm.json new file mode 100644 index 0000000..e40be44 --- /dev/null +++ b/deployment/install/microservices/openshift-configuration/import-realm.json @@ -0,0 +1,2217 @@ +{ + "id": "cb739b43-29db-42c9-8658-a0367c6bb173", + "realm": "microservices", + "notBefore": 0, + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "750e3985-4c32-4b09-8e4a-86654362e6ba", + "name": "admin", + "composite": false, + "clientRole": false, + "containerId": "cb739b43-29db-42c9-8658-a0367c6bb173", + "attributes": {} + }, + { + "id": "d724a3df-64bb-4f57-916d-e87906ba32c5", + "name": "confidential", + "composite": false, + "clientRole": false, + "containerId": "cb739b43-29db-42c9-8658-a0367c6bb173", + "attributes": {} + }, + { + "id": "bf4ebd38-027b-48a0-906e-c7eb8934a247", + "name": "user", + "composite": false, + "clientRole": false, + "containerId": "cb739b43-29db-42c9-8658-a0367c6bb173", + "attributes": {} + }, + { + "id": "18785ea5-7483-48b4-be48-bba20b054536", + "name": "offline_access", + "description": "${role_offline-access}", + "composite": false, + "clientRole": false, + "containerId": "cb739b43-29db-42c9-8658-a0367c6bb173", + "attributes": {} + }, + { + "id": "0a5a9ef5-a52a-4483-b810-de4978f7d689", + "name": "uma_authorization", + "description": "${role_uma_authorization}", + "composite": false, + "clientRole": false, + "containerId": "cb739b43-29db-42c9-8658-a0367c6bb173", + "attributes": {} + } + ], + "client": { + "public-exporter": [], + "realm-management": [ + { + "id": "1d61e9b7-ddc8-4556-b09d-88a25c11094d", + "name": "query-users", + "description": "${role_query-users}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "29f204c7-6be0-4499-abcc-4184617246f2", + "name": "manage-clients", + "description": "${role_manage-clients}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "e0fd05e0-8702-4d56-80a1-06a3fb0ea012", + "name": "manage-identity-providers", + "description": "${role_manage-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "9d34b950-30b8-446b-95f1-44f44d08c8e2", + "name": "manage-authorization", + "description": "${role_manage-authorization}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "221bc47b-f6a9-45c0-860d-403c48d7b7ea", + "name": "query-clients", + "description": "${role_query-clients}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "8340019f-74be-4797-9177-5bce2a9c1809", + "name": "query-groups", + "description": "${role_query-groups}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "5e61acb5-ad2f-4bae-81e3-073303194690", + "name": "query-realms", + "description": "${role_query-realms}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "7934f55b-8a13-4984-bf87-e98dd169a614", + "name": "view-events", + "description": "${role_view-events}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "05f10cb6-17d6-4e2a-aed0-b0313ac2f3ff", + "name": "realm-admin", + "description": "${role_realm-admin}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-users", + "manage-clients", + "manage-identity-providers", + "manage-authorization", + "query-clients", + "query-groups", + "query-realms", + "view-events", + "manage-users", + "view-identity-providers", + "view-realm", + "view-authorization", + "view-clients", + "create-client", + "manage-realm", + "impersonation", + "manage-events", + "view-users" + ] + } + }, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "604282a0-4522-4525-b7ef-cc4912596891", + "name": "manage-users", + "description": "${role_manage-users}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "378b9cb3-bb4d-4c22-9035-acde1fbe078f", + "name": "view-identity-providers", + "description": "${role_view-identity-providers}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "f6d4988f-e394-4a36-be24-dcaa5907dc71", + "name": "view-realm", + "description": "${role_view-realm}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "336e91c2-e7d7-4d98-b53a-09ccfbbd6e21", + "name": "view-authorization", + "description": "${role_view-authorization}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "f611a211-6d3b-4b6d-b0d0-57a57ebb6faf", + "name": "view-clients", + "description": "${role_view-clients}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-clients" + ] + } + }, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "1862b741-55e0-453d-beb5-1db78aece47a", + "name": "create-client", + "description": "${role_create-client}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "eed7e359-1d8e-45e7-8b23-1aab5a404a5d", + "name": "manage-realm", + "description": "${role_manage-realm}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "4fa5e33e-a73b-4581-96ec-8f475ee0328b", + "name": "impersonation", + "description": "${role_impersonation}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "fb02f9b8-f4a9-4d7e-991d-fe684003f04d", + "name": "manage-events", + "description": "${role_manage-events}", + "composite": false, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + }, + { + "id": "52be93d0-8462-42ba-a188-6a2a4a320733", + "name": "view-users", + "description": "${role_view-users}", + "composite": true, + "composites": { + "client": { + "realm-management": [ + "query-users", + "query-groups" + ] + } + }, + "clientRole": true, + "containerId": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "attributes": {} + } + ], + "app-ui": [], + "security-admin-console": [], + "boards": [], + "userprofile": [], + "scratch": [], + "backend-service": [ + { + "id": "c12335b5-81ee-4dab-98dc-297a74222a6e", + "name": "uma_protection", + "composite": false, + "clientRole": true, + "containerId": "281aeb22-8165-488d-87aa-720374619512", + "attributes": {} + } + ], + "mailer": [], + "broker": [ + { + "id": "b5dec37c-069a-4ef4-a383-690f35928f9c", + "name": "read-token", + "description": "${role_read-token}", + "composite": false, + "clientRole": true, + "containerId": "699f55a4-79c0-433c-8563-611259827560", + "attributes": {} + } + ], + "search": [], + "censor": [], + "admin-cli": [], + "sms-receiver": [], + "context-scrapper": [], + "account": [ + { + "id": "901e232f-42df-4d4a-8454-9e43134b1242", + "name": "manage-account", + "description": "${role_manage-account}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account-links" + ] + } + }, + "clientRole": true, + "containerId": "33c2bd25-88b2-4655-9b00-05c953d5710e", + "attributes": {} + }, + { + "id": "f7e185df-54bd-4edf-8615-b696ba827e60", + "name": "view-profile", + "description": "${role_view-profile}", + "composite": false, + "clientRole": true, + "containerId": "33c2bd25-88b2-4655-9b00-05c953d5710e", + "attributes": {} + }, + { + "id": "fa16a2c1-f4ac-49aa-8eec-0848ce27f5a5", + "name": "manage-account-links", + "description": "${role_manage-account-links}", + "composite": false, + "clientRole": true, + "containerId": "33c2bd25-88b2-4655-9b00-05c953d5710e", + "attributes": {} + } + ] + } + }, + "groups": [], + "defaultRoles": [ + "offline_access", + "uma_authorization" + ], + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpSupportedApplications": [ + "FreeOTP", + "Google Authenticator" + ], + "scopeMappings": [ + { + "clientScope": "offline_access", + "roles": [ + "offline_access" + ] + } + ], + "clients": [ + { + "id": "281aeb22-8165-488d-87aa-720374619512", + "clientId": "backend-service", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": true, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "protocolMappers": [ + { + "id": "1c535d09-4386-4865-86e9-0c7b0c7092db", + "name": "Client Host", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientHost", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientHost", + "jsonType.label": "String" + } + }, + { + "id": "6e1dbbce-d545-457c-b773-d8f9c2cdb5dd", + "name": "Client IP Address", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientAddress", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientAddress", + "jsonType.label": "String" + } + }, + { + "id": "939e9226-e95e-44b9-b62d-0c3600841c1a", + "name": "Client ID", + "protocol": "openid-connect", + "protocolMapper": "oidc-usersessionmodel-note-mapper", + "consentRequired": false, + "config": { + "user.session.note": "clientId", + "userinfo.token.claim": "true", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "clientId", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "e7da922f-92fb-4832-9af2-ca52ad2a93c8", + "clientId": "boards", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "2aaa93b2-ffb0-48ba-b222-5bd07674c324", + "clientId": "scratch", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "88c8847f-f088-4f79-92c5-e80cf02f255d", + "clientId": "search", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "9059f025-11e2-4e3f-a0d1-6027c06565cb", + "clientId": "mailer", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "be2c8d76-84e3-4cb9-baa6-38508b5b6096", + "clientId": "context-scrapper", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "33c2bd25-88b2-4655-9b00-05c953d5710e", + "clientId": "account", + "name": "${client_account}", + "baseUrl": "/auth/realms/microservices/account", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "/auth/realms/microservices/account/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "5f21c335-f144-4374-afac-20aabc58e4a3", + "clientId": "userprofile", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "role_list", + "roles", + "profile", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "cd62d808-e958-446f-89ca-b5e990779e02", + "clientId": "security-admin-console", + "name": "${client_security-admin-console}", + "baseUrl": "/auth/admin/microservices/console/index.html", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [ + "/auth/admin/microservices/console/*" + ], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "protocolMappers": [ + { + "id": "f8b5bf28-fdc2-4d8b-ac2e-cd7bc7fa5a0d", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + } + ], + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "cd5df0a3-f055-4cc7-ae96-5705e3ba10d4", + "clientId": "public-exporter", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "699f55a4-79c0-433c-8563-611259827560", + "clientId": "broker", + "name": "${client_broker}", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "8c41a0d9-4ec9-4a9b-ad45-79f9a773b1ed", + "clientId": "admin-cli", + "name": "${client_admin-cli}", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": false, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "e0a87854-3f48-4ba2-89fe-e438963d7281", + "clientId": "sms-receiver", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "41597162-bc28-4bb2-8bc1-0ffd7001bbf9", + "clientId": "censor", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "28e0a863-874d-49f9-b2cf-348cdd0f0233", + "clientId": "app-ui", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": false, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": true, + "serviceAccountsEnabled": false, + "publicClient": true, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": true, + "nodeReRegistrationTimeout": -1, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + }, + { + "id": "530c2457-f2c7-43bf-8fc5-fe5763343f76", + "clientId": "realm-management", + "name": "${client_realm-management}", + "surrogateAuthRequired": false, + "enabled": true, + "clientAuthenticatorType": "client-secret", + "secret": "**********", + "redirectUris": [], + "webOrigins": [], + "notBefore": 0, + "bearerOnly": true, + "consentRequired": false, + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "publicClient": false, + "frontchannelLogout": false, + "protocol": "openid-connect", + "attributes": {}, + "authenticationFlowBindingOverrides": {}, + "fullScopeAllowed": false, + "nodeReRegistrationTimeout": 0, + "defaultClientScopes": [ + "web-origins", + "role_list", + "profile", + "roles", + "email" + ], + "optionalClientScopes": [ + "address", + "phone", + "offline_access" + ] + } + ], + "clientScopes": [ + { + "id": "962f4e5a-0b87-4965-b99a-e152a0d615e6", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "ceb40d6e-855b-4c8e-812d-690806dbb5d0", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "45177a25-b1e9-4d8c-b37d-262b829b937f", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "consent.screen.text": "${rolesScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "f336d180-342f-4e38-b97c-08bfce713842", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "7437ba37-3a16-42ab-b755-2e91f42c3687", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + }, + { + "id": "7892720f-b1ed-499c-a7a9-d191fcf8757d", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + } + ] + }, + { + "id": "5153a265-3c51-4c5b-b278-458e9e8980ec", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${phoneScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "45bbf48f-b97a-4c41-ba78-6909df481cd1", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + }, + { + "id": "c31d0688-b40e-4222-bee4-18970f96bf23", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "cfc170e2-fdb8-4344-962b-b19bd13d43ea", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${addressScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "f275c113-35b7-469a-b79b-1a24dfd19fed", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "6e341316-44a3-439e-86ba-ecf355f2ab89", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${emailScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "1061e8d5-13f1-4e58-a6de-ccd7b555aea7", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + }, + { + "id": "69f0a938-6d2f-4879-b7b4-d114a1f6b753", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + } + ] + }, + { + "id": "c1191b6f-48a4-4517-8352-56a2df2a86ed", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${profileScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "fb3ef75d-8793-4d6d-9cc5-b2e448f15ba7", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "e6b45d9f-cf63-4f75-8e42-87b87cddc755", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "1d1c9a2d-20ac-4762-b80d-0f6a9ebf646d", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "3c356549-073c-4712-a9c1-85c22e89ba03", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "aed1db20-1a91-4d24-a83a-bc748a22f8ec", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + }, + { + "id": "25dbd75b-9fe0-42aa-b5a1-269337517801", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "bb058b24-b656-4131-9617-bc03b74cf512", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "92410a07-9830-49b6-9131-7a4e599b6554", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "71200a99-5c80-45c5-8375-7aa8a20c7a08", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "String" + } + }, + { + "id": "0b8b4e12-4ae9-40df-b909-998617e80240", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "a5ccb60a-e3be-4263-8555-dca72a86574d", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "51c06519-dd1a-4842-8741-009d1f18afd7", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "6bfc00ac-4ccc-4a33-a669-4ed9ea0478db", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "e573af52-62a8-48b4-9b7e-0e5d41df3c13", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "10046286-07e2-46cc-9edc-07d98297e70b", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "3c052e8f-df39-47ce-b610-5b59a67d90b8", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "5931ccdb-6621-468a-a1c7-87f1a21c7e91", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "profile", + "email", + "roles", + "web-origins" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "xXSSProtection": "1; mode=block", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "45b9265a-7405-4daf-b83a-1747d8f53508", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-user-attribute-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-full-name-mapper", + "oidc-address-mapper", + "oidc-usermodel-property-mapper", + "saml-user-property-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-role-list-mapper" + ] + } + }, + { + "id": "d2cd9f9a-feb5-43cb-a6a2-792e7e10b2d8", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "f05c8e35-a09a-45c3-9bb8-c575aaa41cbe", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "ace5aa9f-eb93-4cef-8b8a-1bf05213f128", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "8b270669-3570-4eaf-982f-80c0ae58276b", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "66f9afde-d044-401d-8ee5-cffa01095845", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "67eca3ef-c11e-4ea4-92d1-6092c914f2ed", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "fb3901e9-8a8e-444d-91af-659399a5d55e", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-address-mapper", + "oidc-full-name-mapper", + "saml-user-attribute-mapper", + "saml-user-property-mapper", + "oidc-sha256-pairwise-sub-mapper", + "oidc-usermodel-property-mapper", + "saml-role-list-mapper", + "oidc-usermodel-attribute-mapper" + ] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "4aea7de3-05fb-4bbd-820e-941eb2072a7f", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "875379b7-effe-4df3-9bbe-eeff2dc70888", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS256" + ] + } + }, + { + "id": "9a86b792-60c2-4dd8-91cd-32329c6c0508", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "ca4bb899-6633-4da0-b34f-61c56d01e997", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "idp-email-verification", + "requirement": "ALTERNATIVE", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 30, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "fcb23805-2918-42a3-8fe5-1cba8fd8a4c8", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-otp-form", + "requirement": "OPTIONAL", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "76dccb78-b192-4f2c-9373-f9bee547b892", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-spnego", + "requirement": "DISABLED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "identity-provider-redirector", + "requirement": "ALTERNATIVE", + "priority": 25, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 30, + "flowAlias": "forms", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "2d7b119a-9d3b-43ce-8654-4e3a02a813c3", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-jwt", + "requirement": "ALTERNATIVE", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-secret-jwt", + "requirement": "ALTERNATIVE", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-x509", + "requirement": "ALTERNATIVE", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "6b804531-7088-4c5c-9b83-c4df4cee6e48", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "direct-grant-validate-password", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "direct-grant-validate-otp", + "requirement": "OPTIONAL", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "6f44809d-7c93-4ac7-b94e-31c22ffca8ca", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "dba2fec4-63ec-4a24-a577-fb1f655b56e0", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "requirement": "ALTERNATIVE", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "requirement": "ALTERNATIVE", + "priority": 30, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "50b9e3f8-1732-4dba-9266-cf0c494897f4", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-otp-form", + "requirement": "OPTIONAL", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "90f6d9bd-e622-4e02-9469-f06b14a00781", + "alias": "http challenge", + "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "no-cookie-redirect", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "basic-auth", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "basic-auth-otp", + "requirement": "DISABLED", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-spnego", + "requirement": "DISABLED", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "73d15381-c790-4716-b22a-ce154bec9932", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "requirement": "REQUIRED", + "priority": 10, + "flowAlias": "registration form", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "254ec47a-51ed-42ee-9bb5-9d8543a93ba4", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-profile-action", + "requirement": "REQUIRED", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-password-action", + "requirement": "REQUIRED", + "priority": 50, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-recaptcha-action", + "requirement": "DISABLED", + "priority": 60, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "d384210a-974b-4d5b-b5c1-e7ad2febe2a8", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-credential-email", + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-password", + "requirement": "REQUIRED", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-otp", + "requirement": "OPTIONAL", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "19a62c8d-3588-47c6-8d68-7e0a0760fea5", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "6ba0688a-b236-41d9-9695-8a00078fc6ac", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "897aa5cb-12f0-4985-926d-643b565a5e6e", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "terms_and_conditions", + "name": "Terms and Conditions", + "providerId": "terms_and_conditions", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "attributes": { + "_browser_header.xXSSProtection": "1; mode=block", + "_browser_header.xFrameOptions": "SAMEORIGIN", + "_browser_header.strictTransportSecurity": "max-age=31536000; includeSubDomains", + "permanentLockout": "false", + "quickLoginCheckMilliSeconds": "1000", + "_browser_header.xRobotsTag": "none", + "maxFailureWaitSeconds": "900", + "minimumQuickLoginWaitSeconds": "60", + "failureFactor": "30", + "actionTokenGeneratedByUserLifespan": "300", + "maxDeltaTimeSeconds": "43200", + "_browser_header.xContentTypeOptions": "nosniff", + "offlineSessionMaxLifespan": "5184000", + "actionTokenGeneratedByAdminLifespan": "43200", + "_browser_header.contentSecurityPolicyReportOnly": "", + "bruteForceProtected": "false", + "_browser_header.contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "waitIncrementSeconds": "60", + "offlineSessionMaxLifespanEnabled": "false" + }, + "users" : [ { + "id" : "af134cab-f41c-4675-b141-205f975db679", + "username" : "admin", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "credentials" : [ { + "type" : "password", + "hashedSaltedValue" : "NICTtwsvSxJ5hL8hLAuleDUv9jwZcuXgxviMXvR++cciyPtiIEStEaJUyfA9DOir59awjPrHOumsclPVjNBplA==", + "salt" : "T/2P5o5oxFJUEk68BRURRg==", + "hashIterations" : 27500, + "counter" : 0, + "algorithm" : "pbkdf2-sha256", + "digits" : 0, + "period" : 0, + "createdDate" : 1554245879354, + "config" : { } + } ], + "disableableCredentialTypes" : [ "password" ], + "requiredActions" : [ ], + "realmRoles" : [ "admin", "user" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "eb4123a3-b722-4798-9af5-8957f823657a", + "username" : "alice", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "credentials" : [ { + "type" : "password", + "hashedSaltedValue" : "A3okqV2T/ybXTVEgKfosoSjP8Yc9IZbFP/SY4cEd6hag7TABQrQ6nUSuwagGt96l8cw1DTijO75PqX6uiTXMzw==", + "salt" : "sl4mXx6T9FypPH/s9TngfQ==", + "hashIterations" : 27500, + "counter" : 0, + "algorithm" : "pbkdf2-sha256", + "digits" : 0, + "period" : 0, + "createdDate" : 1554245879116, + "config" : { } + } ], + "disableableCredentialTypes" : [ "password" ], + "requiredActions" : [ ], + "realmRoles" : [ "user" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "1eed6a8e-a853-4597-b4c6-c4c2533546a0", + "username" : "jdoe", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "credentials" : [ { + "type" : "password", + "hashedSaltedValue" : "JV3DUNLjqOadjbBOtC4rvacQI553CGaDGAzBS8MR5ReCr7SwF3E6CsW3T7/XO8ITZAsch8+A/6loeuCoVLLJrg==", + "salt" : "uCbOH7HZtyDtMd0E9DG/nw==", + "hashIterations" : 27500, + "counter" : 0, + "algorithm" : "pbkdf2-sha256", + "digits" : 0, + "period" : 0, + "createdDate" : 1554245879227, + "config" : { } + } ], + "disableableCredentialTypes" : [ "password" ], + "requiredActions" : [ ], + "realmRoles" : [ "confidential", "user" ], + "notBefore" : 0, + "groups" : [ ] + } ], + "keycloakVersion": "7.3.0.GA", + "userManagedAccessAllowed": false +} \ No newline at end of file diff --git a/deployment/install/microservices/openshift-configuration/userprofile.yaml b/deployment/install/microservices/openshift-configuration/userprofile.yaml index 09b7fbd..3ca3650 100644 --- a/deployment/install/microservices/openshift-configuration/userprofile.yaml +++ b/deployment/install/microservices/openshift-configuration/userprofile.yaml @@ -7,14 +7,14 @@ apiVersion: template.openshift.io/v1 kind: Template labels: - template: userprofile-fromsource + template: userprofile message: A User Profile service has been created in your project along with it's PostgreSQL metadata: annotations: description: An user profile application for the microservices demo openshift.io/display-name: userprofile template.openshift.io/long-description: This template defines the userprofile microservice - name: userprofile-fromsource + name: userprofile objects: # ----------------------------------------------------------------------------- # Quarkus App Section diff --git a/deployment/install/microservices/services-install.sh b/deployment/install/microservices/services-install.sh index c1c2b42..16a3c9c 100755 --- a/deployment/install/microservices/services-install.sh +++ b/deployment/install/microservices/services-install.sh @@ -17,6 +17,8 @@ oc adm policy add-scc-to-user privileged -z default -n microservices-demo oc new-app -f ./openshift-configuration/boards.yaml oc new-app -f ./openshift-configuration/context-scraper.yaml oc new-app -f ./openshift-configuration/app-ui.yaml +#oc create configmap sso-realm --from-file=./openshift-configuration/import-realm.json +#TODO : need to make sure the auth image is built before applying. Should this be pulled from quay like the others? #oc new-app -f ./openshift-configuration/auth-sso73-x509.yaml #oc new-app -f ./openshift-configuration/userprofile.yaml From d9c0e4dab27c6f0f4905a18bbf59109891c292b9 Mon Sep 17 00:00:00 2001 From: dudash Date: Mon, 3 Jun 2019 16:50:00 -0400 Subject: [PATCH 7/9] app-ui and boards update for creating and adding items to boards --- README.md | 20 ++- code/app-ui/app.js | 9 + code/app-ui/public/javascripts/dashboard.js | 33 +++- code/app-ui/public/stylesheets/dashboard.css | 2 +- code/app-ui/routes/board.js | 164 +++++++++++++++++++ code/app-ui/routes/index.js | 58 ++++++- code/app-ui/routes/shared.js | 4 +- code/app-ui/views/board.pug | 41 ++++- code/app-ui/views/dashboard.pug | 56 ++++--- code/app-ui/views/layout-topbar.pug | 2 +- code/app-ui/views/shared.pug | 2 +- code/boards/controllers/boardsController.js | 18 +- code/boards/controllers/itemsController.js | 1 + code/boards/package-lock.json | 41 ++--- 14 files changed, 366 insertions(+), 85 deletions(-) create mode 100644 code/app-ui/routes/board.js diff --git a/README.md b/README.md index ef41e45..db7bd54 100644 --- a/README.md +++ b/README.md @@ -41,13 +41,13 @@ This repo is an example microservices based application. It's core functionality First off, you need access to an OpenShift cluster. Don't have an OpenShift cluster? That's OK, download the CDK (or minishift) for free here: https://developers.redhat.com/products/cdk/overview/. You will need a fairly beefy machine to run *everything* on the same machine via CDK, so I'd recommend you expose extra CPUs and Mem to the CDK when you start your cluster. You will also need to install/configure the additional dependencies you plan to leverage. We assume you want to run these in the cluster, so you might need to tweak the install scripts to move things outside or to use already existing shared services in different namespaces. - - [Istio](./deployment/install/istio) - - [3Scale](./deployment/install/3scale) - COMING SOON - - [Kafka](./deployment/install/kafka) - COMING SOON + - Istio + - 3Scale - COMING SOON + - Kafka - COMING SOON + - Caching - COMING SOON -To install the microservices demo, you can choose to do that from source or from pre-built container images. -- [The script to install for is located here](./deployment/install/microservices) -- You will need to tweak if you want to install from source [read this](./deployment/install/) +To install everything: +- [Follow instructions here](./deployment/install/) Once you have the basic app up and running, how about trying out [some demos](./deployment/demos) @@ -71,11 +71,19 @@ The parts in action here are: ## References, useful links, good videos to check out +### Microservices +* [Microservices at Spotify Talk](https://www.youtube.com/watch?v=7LGPeBgNFuU) +* [Microservices at Uber Talk](https://www.youtube.com/watch?v=kb-m2fasdDY) * [Mastering Chaos Netflix Talk](https://youtu.be/CZ3wIuvmHeM) * [Red Hat Developer's Learning - Microservices](https://developers.redhat.com/learn/microservices/) +### Istio Service Mesh * [What is Istio?](https://istio.io/docs/concepts/what-is-istio/) +* [Red Hat Developer's Istio Free Book](https://developers.redhat.com/books/introducing-istio-service-mesh-microservices/) +* [Free Hands-on with Istio](https://learn.openshift.com/servicemesh) +### Single Sign On * [Keycloak SSO](https://www.keycloak.org/) + ## Contributing [See guidelines here](./CONTRIBUTING.md). But in general I would love for help with 2 things. 1. Use this repo and [report issues][1], even fix them if you can. diff --git a/code/app-ui/app.js b/code/app-ui/app.js index ae6e632..fc41828 100644 --- a/code/app-ui/app.js +++ b/code/app-ui/app.js @@ -40,12 +40,21 @@ app.use(function(req,res,next) { next() }) +// TODO: we need to do real auth +app.use(function (req, res, next) { + res.locals.user = 'anonymous' + res.locals.authenticated = false + next() +}) + var indexRouter = require('./routes/index') var profileRouter = require('./routes/profile') var sharedRouter = require('./routes/shared') +var boardRouter = require('./routes/board') app.use('/', indexRouter) app.use('/profile', profileRouter) app.use('/shared', sharedRouter) +app.use('/:user/board', boardRouter) app.use(function(req, res, next) { next(createError(404)) // catch 404 and forward to error handler }) diff --git a/code/app-ui/public/javascripts/dashboard.js b/code/app-ui/public/javascripts/dashboard.js index 4b7219e..56b1b49 100644 --- a/code/app-ui/public/javascripts/dashboard.js +++ b/code/app-ui/public/javascripts/dashboard.js @@ -5,7 +5,34 @@ $('#newBoardModal').on('show.bs.modal', function (event) { // If necessary, you could initiate an AJAX request here (and then do the updating in a callback). // Update the modal's content. We'll use jQuery here, but you could use a data binding library or other methods instead. var modal = $(this) - //modal.find('.modal-title').text('REPLACED TITLE') - //modal.find('.modal-body input').val('New Board') - //modal.find('.modal-body textarea').val('New Board Description') + + // setup a validator + $('#newboardSubmitButton').prop('disabled', true); + $('.modal-body input').off('keyup'); + $('.modal-body input').on('keyup', validate); + + // clear out prior input values + modal.find('.modal-body input').val('') + modal.find('.modal-body textarea').val('') + modal.find('.modal-body input:checkbox').prop("checked", false) }) + +function validate() { + if ($('#newboardName').val()) { + $('#newboardSubmitButton').prop('disabled', false); + } else { + $('#newboardSubmitButton').prop('disabled', true); + } +} + +// $('#newBoardForm').click(function(e){ +// e.preventDefault(); +// alert($('#newboardName').val()); +// +// $.post('http://path/to/post', +// $('#newBoardForm').serialize(), +// function(data, status, xhr){ +// // do something here with response; +// }); +// +// }) \ No newline at end of file diff --git a/code/app-ui/public/stylesheets/dashboard.css b/code/app-ui/public/stylesheets/dashboard.css index 5982284..445b2f3 100644 --- a/code/app-ui/public/stylesheets/dashboard.css +++ b/code/app-ui/public/stylesheets/dashboard.css @@ -30,4 +30,4 @@ footer p { margin-bottom: .25rem; - } \ No newline at end of file + } diff --git a/code/app-ui/routes/board.js b/code/app-ui/routes/board.js new file mode 100644 index 0000000..6f97970 --- /dev/null +++ b/code/app-ui/routes/board.js @@ -0,0 +1,164 @@ +var express = require('express') +var router = express.Router() +var moment = require('moment') +var request = require('request-promise') + +/* GET board's page. */ +router.get('/:boardId', function(req, res, next) { + var user = res.locals.user + const boardsGetURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/boards/' + req.params.boardId + req.debug('GET from boards SVC at: ' + boardsGetURI) + var request_get_options = { + method: 'GET', + uri: boardsGetURI, + headers: { + 'user-agent': req.header('user-agent'), + 'x-request-id': req.header('x-request-id'), + 'x-b3-traceid': req.header('x-b3-traceid'), + 'x-b3-spanid': req.header('x-b3-spanid'), + 'x-b3-parentspanid': req.header('x-b3-parentspanid'), + 'x-b3-sampled': req.header('x-b3-sampled'), + 'x-b3-flags': req.header('x-b3-flags'), + 'x-ot-span-context': req.header('x-ot-span-context'), + 'b3': req.header('b3') + }, + json: true // Automatically parses the JSON string in the response + } + var itemsData = [] + request(request_get_options) + .then(function (getresult) { + // req.debug(getresult) // uncomment to show board JSON + var itemsData = [] + var itemListPromises = getresult.items.map(function(itemId) { return getItemRequest(req, user, itemId, itemsData)}); + Promise.all(itemListPromises).then(function(itemsData) { + req.debug(itemsData) + res.render('board', { title: 'Cut and Paster', board: getresult, items: itemsData, errorWithItems: false }) + }) + .catch(function (err) { + req.debug('ERROR GETTING DATA FROM BOARDS SERVICE') + req.debug(err) + res.render('board', { title: 'Cut and Paster', board: getresult, items: itemsData, errorWithItems: true }) + }) + }) + .catch(function (err) { + req.debug('ERROR GETTING DATA FROM BOARDS SERVICE') + req.debug(err) + res.render('board', { title: 'Cut and Paster', board: getresult, items: itemsData, errorWithItems: true }) + }) +}) + +function getItemRequest(req, user, itemId, itemsData) { + const boardsGetItemURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/items/' + itemId + req.debug('GET from boards SVC at: ' + boardsGetItemURI) + var request_getitem_options = { + method: 'GET', + uri: boardsGetItemURI, + headers: { + 'user-agent': req.header('user-agent'), + 'x-request-id': req.header('x-request-id'), + 'x-b3-traceid': req.header('x-b3-traceid'), + 'x-b3-spanid': req.header('x-b3-spanid'), + 'x-b3-parentspanid': req.header('x-b3-parentspanid'), + 'x-b3-sampled': req.header('x-b3-sampled'), + 'x-b3-flags': req.header('x-b3-flags'), + 'x-ot-span-context': req.header('x-ot-span-context'), + 'b3': req.header('b3') + }, + json: true // Automatically parses the JSON string in the response + } + return request(request_getitem_options) + .then(function (getitemresult) { + // req.debug(getitemresult) // uncomment to show item JSON + return getitemresult + }) + .catch(function (err) { + req.debug('ERROR GETTING ITEM DATA FROM BOARDS SERVICE') + req.debug(err) + return err + }) +} + +/* POST (form submission) to add an item to shared items list */ +router.post('/:boardId/paste', function(req, res) { + var pasteData = req.body.pastedata + if (pasteData.length < 1) { + req.debug('ignoring zero length add to shared board') + return + } + var user = res.locals.user + var board = JSON.parse(req.body.board) + const boardsNewItemURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/items' + req.debug('POST to boards SVC at: ' + boardsNewItemURI) + var request_post_options = { + method: 'POST', + uri: boardsNewItemURI, + body: { + owner: user, + type: 'string', + raw: pasteData, + name: '' + }, + headers: { + 'User-Agent': req.header('user-agent'), + 'x-request-id': req.header('x-request-id'), + 'x-b3-traceid': req.header('x-b3-traceid'), + 'x-b3-spanid': req.header('x-b3-spanid'), + 'x-b3-parentspanid': req.header('x-b3-parentspanid'), + 'x-b3-sampled': req.header('x-b3-sampled'), + 'x-b3-flags': req.header('x-b3-flags'), + 'x-ot-span-context': req.header('x-ot-span-context'), + 'b3': req.header('b3') + }, + json: true // Automatically parses the JSON string in the response + } + request(request_post_options) // ADD A NEW ITEM + .then(function (postresult) { + req.debug('SUCCESS CREATED NEW ITEM') + req.debug(postresult) + var itemId = postresult.split(' ')[1] + if (board.items == null || board.items.length < 1) { + board.items = [itemId] + } + else { + board.items.push(itemId) + } + // req.debug(board) + const boardsUpdateURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/boards/' + req.params.boardId + req.debug('PUT to boards SVC at: ' + boardsUpdateURI) + var request_put_options = { + method: 'PUT', + uri: boardsUpdateURI, + body: board, + headers: { + 'User-Agent': req.header('user-agent'), + 'x-request-id': req.header('x-request-id'), + 'x-b3-traceid': req.header('x-b3-traceid'), + 'x-b3-spanid': req.header('x-b3-spanid'), + 'x-b3-parentspanid': req.header('x-b3-parentspanid'), + 'x-b3-sampled': req.header('x-b3-sampled'), + 'x-b3-flags': req.header('x-b3-flags'), + 'x-ot-span-context': req.header('x-ot-span-context'), + 'b3': req.header('b3') + }, + json: true // Automatically parses the JSON string in the response + } + request(request_put_options) // UPDATE BOARD TO ADD NEW ITEM IN LIST + .then(function (putresult) { + req.debug('SUCCESS ADDED NEW ITEM TO BOARD') + req.debug(putresult) + res.redirect('back') + }) + .catch(function (err) { + req.debug('ERROR UPDATING DATA FOR BOARD') + req.debug(err) + res.redirect('back') + }) + }) + .catch(function (err) { + req.debug('ERROR CREATING NEW ITEM') + req.debug(err) + res.redirect('back') + }) +}) + +module.exports = router diff --git a/code/app-ui/routes/index.js b/code/app-ui/routes/index.js index 6700e4b..71bdb2d 100644 --- a/code/app-ui/routes/index.js +++ b/code/app-ui/routes/index.js @@ -6,13 +6,50 @@ var request = require('request-promise') /* GET dashboard page. */ router.get('/', function(req, res, next) { var userboards = '' - res.render('dashboard', { title: 'Cut and Paster', boards: userboards }) + var user = res.locals.user + const boardsURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/boards' + req.debug('GET from boards SVC at: ' + boardsURI) + var request_options = { + method: 'GET', + uri: boardsURI, + headers: { + 'user-agent': req.header('user-agent'), + 'x-request-id': req.header('x-request-id'), + 'x-b3-traceid': req.header('x-b3-traceid'), + 'x-b3-spanid': req.header('x-b3-spanid'), + 'x-b3-parentspanid': req.header('x-b3-parentspanid'), + 'x-b3-sampled': req.header('x-b3-sampled'), + 'x-b3-flags': req.header('x-b3-flags'), + 'x-ot-span-context': req.header('x-ot-span-context'), + 'b3': req.header('b3') + }, + json: true // Automatically parses the JSON string in the response + } + request(request_options) + .then(function (result) { + userboards = result + if (req.app.locals.errorAlertText != null && req.app.locals.errorAlertText != '') { // this can come from adding a new board failures too + var errorAlertText = req.app.locals.errorAlertText + req.app.locals.errorAlertText = null // clear the error now that we are rendering it + res.render('dashboard', { title: 'Cut and Paster', user:user, boards: userboards, errorAlert: true, errorAlertText: errorAlertText}) + } + else + res.render('dashboard', { title: 'Cut and Paster', user:user, boards: userboards, errorAlert: false }) + }) + .catch(function (err) { + req.debug('ERROR GETTING DATA FROM BOARDS SERVICE') + req.debug(err) + res.render('dashboard', { title: 'Cut and Paster', user:user, boards: userboards, errorAlert: true, errorAlertText: err.toString() }) + }) }) /* POST from form submission to create a board */ router.post('/newboard', function(req, res) { - var newBoardData = req.body.newboarddata - var user = 'userX' // TODO: replace this with real user + req.debug(req.body) + var newBoardName = req.body.newboardname + var newBoardDescription = req.body.newboarddesc + var newBoardIsPrivate = req.body.newboardprivate + var user = res.locals.user // TODO: validate data const boardsURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/boards' req.debug('POST to boards SVC at: ' + boardsURI) @@ -20,9 +57,10 @@ router.post('/newboard', function(req, res) { method: 'POST', uri: boardsURI, body: { - name: newBoardData.name, - description: newBoardData.description, - items: newBoardData.items + name: newBoardName, + description: newBoardDescription, + private: newBoardIsPrivate, + items: [] }, headers: { 'user-agent': req.header('user-agent'), @@ -39,13 +77,15 @@ router.post('/newboard', function(req, res) { } request(request_options) .then(function (result) { - // req.debug(result) - res.redirect("/") + //req.debug(result) + req.app.locals.errorAlertText = null + res.redirect('/') }) .catch(function (err) { req.debug('ERROR POSTING DATA TO CREATE NEW BOARD') req.debug(err) - res.redirect("/") + req.app.locals.errorAlertText = err.toString() + res.redirect('/') }) }) diff --git a/code/app-ui/routes/shared.js b/code/app-ui/routes/shared.js index bad3518..4775ff9 100644 --- a/code/app-ui/routes/shared.js +++ b/code/app-ui/routes/shared.js @@ -49,13 +49,13 @@ router.post('/paste', function(req, res) { method: 'POST', uri: boardsURI, body: { - owner: 'userX', // TODO replace this with actual owner + owner: res.locals.user, type: 'string', raw: pasteData, name: '' }, headers: { - 'User-Agent': req.SERVICE_NAME, + 'User-Agent': req.header('user-agent'), 'x-request-id': req.header('x-request-id'), 'x-b3-traceid': req.header('x-b3-traceid'), 'x-b3-spanid': req.header('x-b3-spanid'), diff --git a/code/app-ui/views/board.pug b/code/app-ui/views/board.pug index 6e7f5da..5e39d1e 100644 --- a/code/app-ui/views/board.pug +++ b/code/app-ui/views/board.pug @@ -5,7 +5,7 @@ block append content main.container(role='main') .container .justify-content-md-center-2.shadow-sm - form(type='form' action='/paste' method='post') + form(type='form' action='/'+user+'/board/'+board.id+'/paste' method='post') div.input-group.input-group-lg input#inputPasteData( name='pastedata' @@ -14,6 +14,7 @@ block append content placeholder='Paste your text here...' autofocus ) + input#inputBoardData(type='hidden', name='board', value=board) span.input-group-btn.pl-2 button.btn.btn-default.btn-dark.btn-lg(type='submit') Add hr @@ -23,11 +24,16 @@ block append content h6.mb-0.text-white.lh-100 #{board.name} small #{board.description} .my-3.p-3.bg-white.rounded.shadow-sm - - items = board.items - if items == null || items.length < 0 - // TODO: display empty board notice + if errorWithItems == true + .alert.alert-danger.alert-dismissible.fade.show(role='alert') + strong Error with getting the items! + | You should try refreshing the page to see if that fixes this + button.close(type='button', data-dismiss='alert', aria-label='Close') + span(aria-hidden='true') × + if !errorWithItems && (items == null || items.length < 0) + //- Empty items message could go here else - - var count = Math.min(50, items.length) // limit the max displayed items + - var count = Math.min(150, items.length) // TODO: limit the max displayed items, pagination? scroll loader? - var iter = 0 while iter < count - var owner = 'unknown' @@ -41,7 +47,28 @@ block append content strong.d-block.text-gray-dark #{owner} | #{itemText} p - button.btn.btn-outline-secondary.btn-sm(type='submit') Copy Me + button.btn.btn-outline-secondary.btn-sm(data-clipboard-text=''+itemText) Copy Me - iter++ small.d-block.text-right.mt-3 - a(href='#') All recent \ No newline at end of file + a(href='#') All recent + //- enable to copy paste using the clipboardjs lib + script. + var btns = document.querySelectorAll('button'); + var clipboard = new ClipboardJS(btns); + clipboard.on('success', function(e) { + console.log(e); + }); + clipboard.on('error', function(e) { + console.log(e); + }); + +block append javascripts + script. + var btns = document.querySelectorAll('button'); + var clipboard = new ClipboardJS(btns); + clipboard.on('success', function(e) { + console.log(e); + }); + clipboard.on('error', function(e) { + console.log(e); + }); \ No newline at end of file diff --git a/code/app-ui/views/dashboard.pug b/code/app-ui/views/dashboard.pug index da105d5..e76c16e 100644 --- a/code/app-ui/views/dashboard.pug +++ b/code/app-ui/views/dashboard.pug @@ -2,6 +2,13 @@ extends layout-topbar block append stylesheets link(href='/stylesheets/dashboard.css', rel='stylesheet') block content + if errorAlert == true + .alert.alert-danger.alert-dismissible.fade.show(role='alert') + strong Yikes! Something went wrong... Please try again. + br + | The details: #{errorAlertText} + button.close(type='button', data-dismiss='alert', aria-label='Close') + span(aria-hidden='true') × main(role='main') section.jumbotron.text-center .container @@ -20,24 +27,31 @@ block content #newBoardModal.modal.fade(tabindex='-1', role='dialog', aria-labelledby='newBoardModalLabel', aria-hidden='true') .modal-dialog(role='document') .modal-content - .modal-header - h5#newBoardModalLabel.modal-title New Board - button.close(type='button', data-dismiss='modal', aria-label='Close') - span(aria-hidden='true') x - .modal-body - form + form(type='form' action='/newboard' method='post')#newBoardForm + .modal-header + h5#newBoardModalLabel.modal-title New Board + button.close(type='button', data-dismiss='modal', aria-label='Close') + span(aria-hidden='true') x + .modal-body + .form-group.row + label.col-form-label.col-sm-3(for='newboardName') Name + div.col-sm-9 + input#newboardName.form-control(name='newboardname' type='text', placeholder='Like \"Linux Commands\" or \"Good Quotes\"') + .form-group.row + label.col-form-label.col-sm-3(for='newboardDescription') Description + div.col-sm-9 + textarea#newboardDescription.form-control(name='newboarddesc' placeholder='Describe what this board is all about') + .form-group.row + label.col-form-label.col-sm-3(for='newboardPrivate') Make Private + div.col-sm-9 + input#newboardPrivate.form-control(name='newboardprivate' type="checkbox" data-toggle="tooltip" data-placement="bottom" title="Keep this board secret") + //- TODO COLOR PICKER AND ICON IMAGE + .modal-footer .form-group.row - label.col-form-label.col-sm-2(for='newboardName') Name - div.col-sm-10 - input#newboardName.form-control(type='text', placeholder='Some name') - .form-group.row - label.col-form-label.col-sm-2(for='newboardDescription') Description - div.col-sm-10 - textarea#newboardDescription.form-control(placeholder='Describe what this board is all about') - //- TODO COLOR PICKER AND ICON IMAGE - .modal-footer - button.btn.btn-secondary(type='button', data-dismiss='modal') Cancel - button.btn.btn-primary(type='button') Create + div.col-sm-5 + button.btn.btn-secondary(type='button', data-dismiss='modal') Cancel + div.col-sm-5 + button#newboardSubmitButton.btn.btn-primary(type='submit') Create if boards != null && boards.length != 0 .album.py-5.bg-light .container @@ -57,8 +71,8 @@ block content | #{boards[iter].description} .d-flex.justify-content-between.align-items-center .btn-group - button.btn.btn-sm.btn-outline-secondary(type='button') Click to Open - //- button.btn.btn-sm.btn-outline-secondary(type='button') Delete + a.button.btn.btn-sm.btn-outline-secondary(href='/'+user+'/board/'+boards[iter].id, type='button') Click to Open + //- button.btn.btn-sm.btn-outline-secondary.btn-warning(type='button') Delete small.text-muted #{boards[iter].items.length} items else .col-md-4 @@ -72,8 +86,8 @@ block content | Something is wrong with this board, contact and admin if you would like to try to recover it. .d-flex.justify-content-between.align-items-center .btn-group - button.btn.btn-sm.btn-outline-secondary(type='button') Click to Open - //- button.btn.btn-sm.btn-outline-secondary(type='button') Delete + button.btn.btn-sm.btn-outline-secondary(type='button') Cannot Open + //- button.btn.btn-sm.btn-outline-secondary.btn-warning(type='button') Delete small.text-muted ? items - iter++ diff --git a/code/app-ui/views/layout-topbar.pug b/code/app-ui/views/layout-topbar.pug index b0cd2d6..f1be3a4 100644 --- a/code/app-ui/views/layout-topbar.pug +++ b/code/app-ui/views/layout-topbar.pug @@ -63,7 +63,7 @@ html(lang='en') br p(align='center') | Made with ❤️ at - img(src='./images/Logo-RedHat-A-Color-RGB.png' width='100') + img(src='/images/Logo-RedHat-A-Color-RGB.png' width='100') block javascripts script(src='https://code.jquery.com/jquery-3.3.1.slim.min.js', integrity='sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo', crossorigin='anonymous') diff --git a/code/app-ui/views/shared.pug b/code/app-ui/views/shared.pug index a021dcf..d01cdde 100644 --- a/code/app-ui/views/shared.pug +++ b/code/app-ui/views/shared.pug @@ -33,7 +33,7 @@ block append content if !errorWithItems && (items == null || items.length < 0) //- Empty items message could go here else - - var count = Math.min(50, items.length) // limit the max displayed items + - var count = Math.min(150, items.length) // TODO: limit the max displayed items, pagination? scroll loader? - var iter = 0 while iter < count - var owner = 'unknown' diff --git a/code/boards/controllers/boardsController.js b/code/boards/controllers/boardsController.js index 4555a64..397410a 100644 --- a/code/boards/controllers/boardsController.js +++ b/code/boards/controllers/boardsController.js @@ -47,7 +47,7 @@ module.exports.getboard = function getboard (req, res, next) { // TODO: future check requesting user can access board with arg ID req.db.get(BOARDS_COLLECTION).findOne({'id':req.swagger.params.boardId.value}) .then((docs) => { - console.log(docs) + // req.debugdb(docs) if (docs == null) {res.sendStatus(404)} else { res.setHeader('Content-Type', 'application/json'); @@ -60,9 +60,19 @@ module.exports.getboard = function getboard (req, res, next) { }) }; -// TODO: -// module.exports.updateboard = function updateboard (req, res, next) { -// }; +module.exports.updateboard = function updateboard (req, res, next) { + // TODO: future check requesting user can access board with arg ID + var boardUpdates = req.body + req.db.get(BOARDS_COLLECTION).findOneAndUpdate({'id':req.swagger.params.boardId.value}, boardUpdates) + .then((updatedDoc) => { + if (updatedDoc == null) {res.sendStatus(404)} + else {res.status(202).send('Updated ' + updatedDoc.id)} + }).catch((err) => { + req.debugdb('UPDATE BOARD failed') + req.debugdb(err) + res.sendStatus(500) + }) +}; module.exports.deleteboard = function deleteboard (req, res, next) { // TODO: future check requesting user can delete item with arg ID diff --git a/code/boards/controllers/itemsController.js b/code/boards/controllers/itemsController.js index 3b75f08..62eb554 100644 --- a/code/boards/controllers/itemsController.js +++ b/code/boards/controllers/itemsController.js @@ -44,6 +44,7 @@ module.exports.getitem = function getitem (req, res, next) { // TODO: future check requesting user can access item with arg ID req.db.get(ITEMS_COLLECTION).findOne({'id':req.swagger.params.itemId.value}) .then((docs) => { + req.debugdb(docs) if (docs == null) {res.sendStatus(404)} else { res.setHeader('Content-Type', 'application/json'); diff --git a/code/boards/package-lock.json b/code/boards/package-lock.json index 4af60cf..49d46c7 100644 --- a/code/boards/package-lock.json +++ b/code/boards/package-lock.json @@ -1520,8 +1520,7 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "aproba": { "version": "1.2.0", @@ -1542,14 +1541,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -1564,20 +1561,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -1694,8 +1688,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -1707,7 +1700,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -1722,7 +1714,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -1730,14 +1721,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -1756,7 +1745,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -1837,8 +1825,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -1850,7 +1837,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -1936,8 +1922,7 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "safer-buffer": { "version": "2.1.2", @@ -1973,7 +1958,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -1993,7 +1977,6 @@ "version": "3.0.1", "bundled": true, "dev": true, - "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -2037,14 +2020,12 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true } } }, From 50dc9ec58e22be85401ac07c7f6ba45e543ecb89 Mon Sep 17 00:00:00 2001 From: gbengataylor Date: Wed, 5 Jun 2019 07:31:14 -0400 Subject: [PATCH 8/9] minor change - update realm --- .../microservices/openshift-configuration/import-realm.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/install/microservices/openshift-configuration/import-realm.json b/deployment/install/microservices/openshift-configuration/import-realm.json index e40be44..5174191 100644 --- a/deployment/install/microservices/openshift-configuration/import-realm.json +++ b/deployment/install/microservices/openshift-configuration/import-realm.json @@ -20,7 +20,7 @@ "actionTokenGeneratedByUserLifespan": 300, "enabled": true, "sslRequired": "external", - "registrationAllowed": false, + "registrationAllowed": true, "registrationEmailAsUsername": false, "rememberMe": false, "verifyEmail": false, From 3ac3312517dc019c39916176693e001c3c59328e Mon Sep 17 00:00:00 2001 From: dudash Date: Wed, 14 Aug 2019 12:05:58 -0400 Subject: [PATCH 9/9] app ui updates --- code/app-ui/README.md | 11 ++- code/app-ui/app.js | 24 +++++++ code/app-ui/package-lock.json | 121 ++++++++++++++++++++++++++++++++ code/app-ui/package.json | 2 + code/app-ui/routes/board.js | 13 ++-- code/app-ui/routes/index.js | 4 +- code/app-ui/routes/shared.js | 4 +- code/app-ui/views/dashboard.pug | 2 +- code/auth/README.md | 12 +--- 9 files changed, 169 insertions(+), 24 deletions(-) diff --git a/code/app-ui/README.md b/code/app-ui/README.md index 7912434..c671f9d 100644 --- a/code/app-ui/README.md +++ b/code/app-ui/README.md @@ -6,7 +6,16 @@ This microservice provides the main user interface into the application. ### Env Vars - PORT, port to run the service (defaults to 8080 in PROD, 3000 in DEV) -- +- HTTP_PROTOCOL, default='http://' +- SERVICE_NAME, default='app-ui' +- BOARDS_SVC_HOST, default='boards' +- BOARDS_SVC_PORT, default='8080' +- PROFILE_SVC_HOST, default='profile' +- PROFILE_SVC_PORT, default='8080' +- SSO_SVC_HOST, default='auth-sso73-x509' +- SSO_SVC_PORT, default='8443' +- SESSION_SECRET, default='pleasechangeme' + ### Local Installation / Run / Test ```bash $ npm install diff --git a/code/app-ui/app.js b/code/app-ui/app.js index fc41828..eb9d1ee 100644 --- a/code/app-ui/app.js +++ b/code/app-ui/app.js @@ -10,7 +10,10 @@ var path = require('path') var cookieParser = require('cookie-parser') var cors = require('cors') var debug = require('debug')('app') +var session = require('express-session') //Using cookie-parser may result in issues if the secret is not the same between this module and cookie-parser. +var SSO = require('keycloak-connect') // https://www.keycloak.org/docs/latest/securing_apps/index.html#_javascript_adapter +const HTTP_PROTOCOL = process.env.HTTP_PROTOCOL || 'http://' const SERVICE_NAME = process.env.SERVICE_NAME || 'app-ui' const BOARDS_SVC_HOST = process.env.BOARDS_SVC_HOST || 'boards' const BOARDS_SVC_PORT = process.env.BOARDS_SVC_PORT || '8080' @@ -18,10 +21,23 @@ const PROFILE_SVC_HOST = process.env.PROFILE_SVC_HOST || 'profile' const PROFILE_SVC_PORT = process.env.PROFILE_SVC_PORT || '8080' const SSO_SVC_HOST = process.env.SSO_SVC_HOST || 'auth-sso73-x509' const SSO_SVC_PORT = process.env.SSO_SVC_PORT || '8443' +const SESSION_SECRET = process.env.SESSION_SECRET || 'pleasechangeme' var app = express() app.use(cors()) +// Create a session-store for keycloak middleware. +// Warning! MemoryStore, is purposely not designed for a production environment. +// It will leak memory under most conditions, does not scale past a single +// process, and is meant for debugging and developing. +var memoryStore = new session.MemoryStore(); +app.use(session({ + secret: SESSION_SECRET, // This is the secret used to sign the session ID cookie + resave: false, + saveUninitialized: true, + store: memoryStore +})); + // view engine setup app.set('views', path.join(__dirname, 'views')) app.set('view engine', 'pug') @@ -30,12 +46,17 @@ app.use(express.json()) app.use(express.urlencoded({ extended: false })) app.use(cookieParser()) app.use(express.static(path.join(__dirname, 'public'))) +var auth = new SSO({store: memoryStore}); +app.use(auth.middleware({logout: '/logout'})); app.use(function(req,res,next) { req.SERVICE_NAME = SERVICE_NAME req.debug = debug // pass along debugger for service + req.HTTP_PROTOCOL = HTTP_PROTOCOL req.BOARDS_SVC_HOST = BOARDS_SVC_HOST req.BOARDS_SVC_PORT = BOARDS_SVC_PORT + req.PROFILE_SVC_HOST = PROFILE_SVC_HOST + req.PROFILE_SVC_PORT = PROFILE_SVC_PORT res.locals.ua = req.get('user-agent') // put user agent info into the response data for client side logic next() }) @@ -55,6 +76,9 @@ app.use('/', indexRouter) app.use('/profile', profileRouter) app.use('/shared', sharedRouter) app.use('/:user/board', boardRouter) +//app.use('/:user/dashboard', auth.protect('realm:user'), dashboardRouter) +//app.use('/:user/board', auth.protect('realm:user'), boardRouter) // must be logged in and have 'user' role in the realm. TODO: switch to this when SSO is ready + app.use(function(req, res, next) { next(createError(404)) // catch 404 and forward to error handler }) diff --git a/code/app-ui/package-lock.json b/code/app-ui/package-lock.json index 1b496bd..e81438a 100644 --- a/code/app-ui/package-lock.json +++ b/code/app-ui/package-lock.json @@ -277,6 +277,16 @@ "safer-buffer": "~2.1.0" } }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", @@ -463,6 +473,11 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.4.tgz", "integrity": "sha512-FG+nFEZChJrbQ9tIccIfZJBz3J7mLrAhxakAbnrJWn8d7aKOC+LWifa0G+p4ZqKp4y13T7juYvdhq9NzKdsrjw==" }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==" + }, "body-parser": { "version": "1.18.3", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", @@ -572,6 +587,11 @@ } } }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, "buffer-alloc": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", @@ -1165,6 +1185,20 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "elliptic": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.1.tgz", + "integrity": "sha512-BsXLz5sqX8OHcsh7CqBMztyXARmGQ3LWPtGjJi6DiJHq5C/qvi9P3OqgswKSDftbu8+IoI/QDTAm2fFnQ9SZSQ==", + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, "email-validator": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/email-validator/-/email-validator-2.0.4.tgz", @@ -1347,6 +1381,28 @@ "vary": "~1.1.2" } }, + "express-session": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.16.1.tgz", + "integrity": "sha512-pWvUL8Tl5jUy1MLH7DhgUlpoKeVPUTe+y6WQD9YhcN0C5qAhsh4a8feVjiUXo3TFhIy191YGZ4tewW9edbl2xQ==", + "requires": { + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.2", + "safe-buffer": "5.1.2", + "uid-safe": "~2.1.5" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + } + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -2417,6 +2473,25 @@ } } }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", @@ -2939,6 +3014,16 @@ "set-immediate-shim": "~1.0.1" } }, + "jwk-to-pem": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwk-to-pem/-/jwk-to-pem-2.0.1.tgz", + "integrity": "sha512-KKu0WuDDjqw2FlRFp9/vk9TMO/KvgpZVKzdhhYcNyy5OwE8dw9lOK5OQTQHIJ7m+HioI/4P44sAtVuDrQ8KQfw==", + "requires": { + "asn1.js": "^4.5.2", + "elliptic": "^6.2.3", + "safe-buffer": "^5.0.1" + } + }, "kafka-node": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/kafka-node/-/kafka-node-4.0.0.tgz", @@ -2960,6 +3045,14 @@ "uuid": "^3.0.0" } }, + "keycloak-connect": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/keycloak-connect/-/keycloak-connect-6.0.1.tgz", + "integrity": "sha512-AXKnB6wvocOrdeJ4C8jIlxDn9NA2qwso+gOoAOXxC9cl9LjeO/2VEvrgjvhQJh/ENh+GNqm/Mb6h719LocXtVQ==", + "requires": { + "jwk-to-pem": "^2.0.0" + } + }, "kind-of": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", @@ -3187,6 +3280,16 @@ "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", "optional": true }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", @@ -3568,6 +3671,11 @@ "ee-first": "1.1.1" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -4032,6 +4140,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, + "random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" + }, "range-parser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", @@ -5399,6 +5512,14 @@ "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", "optional": true }, + "uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "requires": { + "random-bytes": "~1.0.0" + } + }, "undefsafe": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz", diff --git a/code/app-ui/package.json b/code/app-ui/package.json index c22fd10..cc561dc 100644 --- a/code/app-ui/package.json +++ b/code/app-ui/package.json @@ -18,8 +18,10 @@ "cors": "~2.8.5", "debug": "^2.6.9", "express": "~4.16.4", + "express-session": "^1.16.1", "http-errors": "~1.6.3", "kafka-node": "^4.0.0", + "keycloak-connect": "^6.0.1", "moment": "~2.24.0", "pug": "^2.0.3", "request": "^2.88.0", diff --git a/code/app-ui/routes/board.js b/code/app-ui/routes/board.js index 6f97970..0de2e42 100644 --- a/code/app-ui/routes/board.js +++ b/code/app-ui/routes/board.js @@ -6,7 +6,7 @@ var request = require('request-promise') /* GET board's page. */ router.get('/:boardId', function(req, res, next) { var user = res.locals.user - const boardsGetURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/boards/' + req.params.boardId + const boardsGetURI = req.HTTP_PROTOCOL + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/boards/' + req.params.boardId req.debug('GET from boards SVC at: ' + boardsGetURI) var request_get_options = { method: 'GET', @@ -31,7 +31,6 @@ router.get('/:boardId', function(req, res, next) { var itemsData = [] var itemListPromises = getresult.items.map(function(itemId) { return getItemRequest(req, user, itemId, itemsData)}); Promise.all(itemListPromises).then(function(itemsData) { - req.debug(itemsData) res.render('board', { title: 'Cut and Paster', board: getresult, items: itemsData, errorWithItems: false }) }) .catch(function (err) { @@ -48,7 +47,7 @@ router.get('/:boardId', function(req, res, next) { }) function getItemRequest(req, user, itemId, itemsData) { - const boardsGetItemURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/items/' + itemId + const boardsGetItemURI = req.HTTP_PROTOCOL + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/items/' + itemId req.debug('GET from boards SVC at: ' + boardsGetItemURI) var request_getitem_options = { method: 'GET', @@ -78,16 +77,16 @@ function getItemRequest(req, user, itemId, itemsData) { }) } -/* POST (form submission) to add an item to shared items list */ +/* POST (form submission) to add an item to board items list */ router.post('/:boardId/paste', function(req, res) { var pasteData = req.body.pastedata if (pasteData.length < 1) { - req.debug('ignoring zero length add to shared board') + req.debug('ignoring zero length add to user board') return } var user = res.locals.user var board = JSON.parse(req.body.board) - const boardsNewItemURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/items' + const boardsNewItemURI = req.HTTP_PROTOCOL + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/items' req.debug('POST to boards SVC at: ' + boardsNewItemURI) var request_post_options = { method: 'POST', @@ -123,7 +122,7 @@ router.post('/:boardId/paste', function(req, res) { board.items.push(itemId) } // req.debug(board) - const boardsUpdateURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/boards/' + req.params.boardId + const boardsUpdateURI = req.HTTP_PROTOCOL + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/boards/' + req.params.boardId req.debug('PUT to boards SVC at: ' + boardsUpdateURI) var request_put_options = { method: 'PUT', diff --git a/code/app-ui/routes/index.js b/code/app-ui/routes/index.js index 71bdb2d..7e7ed62 100644 --- a/code/app-ui/routes/index.js +++ b/code/app-ui/routes/index.js @@ -7,7 +7,7 @@ var request = require('request-promise') router.get('/', function(req, res, next) { var userboards = '' var user = res.locals.user - const boardsURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/boards' + const boardsURI = req.HTTP_PROTOCOL + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/boards' req.debug('GET from boards SVC at: ' + boardsURI) var request_options = { method: 'GET', @@ -51,7 +51,7 @@ router.post('/newboard', function(req, res) { var newBoardIsPrivate = req.body.newboardprivate var user = res.locals.user // TODO: validate data - const boardsURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/boards' + const boardsURI = req.HTTP_PROTOCOL + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/' + user + '/boards' req.debug('POST to boards SVC at: ' + boardsURI) var request_options = { method: 'POST', diff --git a/code/app-ui/routes/shared.js b/code/app-ui/routes/shared.js index 4775ff9..f1cc6cd 100644 --- a/code/app-ui/routes/shared.js +++ b/code/app-ui/routes/shared.js @@ -5,7 +5,7 @@ var request = require('request-promise') /* GET shared page. */ router.get('/', function(req, res, next) { - const boardsURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/shareditems' + const boardsURI = req.HTTP_PROTOCOL + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/shareditems' req.debug('GET from boards SVC at: ' + boardsURI) var request_options = { method: 'GET', @@ -43,7 +43,7 @@ router.post('/paste', function(req, res) { req.debug('ignoring zero length add to shared board') return } - const boardsURI = 'http://' + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/shareditems' + const boardsURI = req.HTTP_PROTOCOL + req.BOARDS_SVC_HOST + ':' + req.BOARDS_SVC_PORT + '/shareditems' req.debug('POST to boards SVC at: ' + boardsURI) var request_options = { method: 'POST', diff --git a/code/app-ui/views/dashboard.pug b/code/app-ui/views/dashboard.pug index e76c16e..e73bc2d 100644 --- a/code/app-ui/views/dashboard.pug +++ b/code/app-ui/views/dashboard.pug @@ -56,7 +56,7 @@ block content .album.py-5.bg-light .container .row - - var count = Math.min(30, boards.length) // limit the max displayed items + - var count = Math.min(50, boards.length) // limit the max displayed boards - var iter = 0 while iter < count if boards[iter].id != null && boards[iter].id.length > 0 diff --git a/code/auth/README.md b/code/auth/README.md index be03a8a..1954a8e 100644 --- a/code/auth/README.md +++ b/code/auth/README.md @@ -32,7 +32,7 @@ oc get is redhat-sso73-openshift -o json | sed "s/registry.redhat.io/registry.ac ## API documentation N/A - Admin can login at: https://auth-microservices-demo.apps.YOURCLUSTER.COM/ -- Users will login at: https://auth-microservices-demo.apps.YOURCLUSTER.COM/auth/realms/microservices/protocol/openid-connect +- Users will login at: https://auth-microservices-demo.apps.YOURCLUSTER.COM/auth/realms/microservices/account ## Developer instructions This repo utilizes a OpenShift's source-to-image (s2i) for customizing and layering extra configuration into the Red Hat official SSO container. You can see the code in the following folders: @@ -82,16 +82,6 @@ oc delete all -l app=auth-sso73-x509 oc delete configmap sso-realm ``` -### Environment variables -A configmap must be created in order for clients to connect to the SSO service. Details are TBD. -```bash -route_name=$(oc get routes -l app=auth | { read line1 ; read line2 ; echo "$line2" ; } | awk '{print $2;}') -oc create configmap sso-config \ - --from-literal=AUTH_URL=https:\/\/${route_name}/auth \ - --from-literal=KEYCLOAK=true \ - --from-literal=PUBLIC_KEY=MANUALLY_GET_THIS_FROM_AUTH_SERVICE_AND_UPDATE_ME -``` - ### Common Issues - I don't have access to the SSO container images... SSO container images are pulled by your cluster from the Red Hat Registry: registry.redhat.io. To consume container images from registry.redhat.io in shared environments such as OpenShift, it is recommended for an administrator to use a Registry Service Account, also referred to as authentication tokens in place of an individual person’s Red Hat Customer Portal credentials. So if you haven't already you can [use this link to create a service account to access the Red Hat container registry][1] (instructions on how to import the secret are there also).