├── 10_docker_tricks ├── .gitignore ├── 10_busybox │ └── run.sh ├── 1_healthcheck │ ├── docker-compose.yml │ └── run.sh ├── 2_multistage_builds │ ├── Dockerfile │ ├── pom.xml │ ├── run.sh │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── johannesinnerbichler │ │ │ │ └── dockerbuilddemo │ │ │ │ └── DockerBuildDemoApplication.java │ │ └── resources │ │ │ └── application.properties │ │ └── test │ │ └── java │ │ └── com │ │ └── johannesinnerbichler │ │ └── dockerbuilddemo │ │ └── DockerBuildDemoApplicationTests.java ├── 3_network_security │ ├── docker-compose.yaml │ └── run.sh ├── 4_database_init │ ├── docker-compose.yml │ ├── init.sql │ └── run.sh ├── 5_ps_output │ └── run.sh ├── 6_docker_in_docker │ ├── docker-compose.yml │ └── run.sh ├── 7_onbuild │ ├── Dockerfile │ ├── DockerfileOnBuild │ ├── main.py │ ├── requirements.txt │ └── run.sh ├── 8_non_root │ ├── Dockerfile │ ├── docker-compose.yml │ ├── index.html │ ├── nginx.conf │ └── run.sh └── 9_apt_get │ ├── Dockerfile │ └── run.sh ├── LICENSE ├── README.md ├── k8s_keycloak ├── .gitignore ├── Dockerfile ├── kubernetes │ ├── app-deployment.yml │ └── keycloak-deployment.yml ├── persons-application.iml ├── pom.xml ├── readme.md ├── src │ └── main │ │ ├── java │ │ └── com │ │ │ └── johannesinnerbichler │ │ │ └── personapp │ │ │ └── PersonApplication.java │ │ └── resources │ │ ├── application.properties │ │ ├── static │ │ └── index.html │ │ └── templates │ │ └── persons.ftl └── util.sh ├── keycloak_4_spring_boot_2 ├── keycloak │ ├── config │ │ ├── PersonRealm-realm.json │ │ ├── PersonRealm-users-0.json │ │ ├── master-realm.json │ │ └── master-users-0.json │ └── docker-compose.yml ├── pom.xml ├── readme.md └── src │ └── main │ ├── java │ └── com │ │ └── johannesinnerbichler │ │ └── personapp │ │ └── PersonApplication.java │ └── resources │ ├── application.yml │ └── templates │ ├── index.ftl │ └── persons.ftl └── spring-data-jpa-encryption ├── .gitignore ├── Dockerfile ├── docker-compose.yml ├── pom.xml ├── readme.md └── src ├── main ├── java │ └── com │ │ └── johannesinnerbichler │ │ └── spring │ │ └── data │ │ └── jpa │ │ └── encryption │ │ ├── JPAEncryptionApplication.java │ │ ├── converters │ │ ├── AbstractConverter.java │ │ ├── AesEncryptor.java │ │ ├── DatabaseEncryptionPasswordProperty.java │ │ ├── LocalDateConverter.java │ │ ├── LocalDateTimeConverter.java │ │ └── StringConverter.java │ │ └── customer │ │ ├── Customer.java │ │ └── CustomerRepository.java └── resources │ └── application.yml └── test └── java └── com └── johannesinnerbichler └── springdata └── jpa └── encryption └── customer └── CustomerRepositoryTest.java /10_docker_tricks/.gitignore: -------------------------------------------------------------------------------- 1 | 2_multistage_builds/target -------------------------------------------------------------------------------- /10_docker_tricks/10_busybox/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sample_job=$(docker run -d busybox /bin/sh -c "while true; do echo Docker; sleep 1; done") 4 | docker logs -f $sample_job 5 | -------------------------------------------------------------------------------- /10_docker_tricks/1_healthcheck/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '2.1' 2 | 3 | services: 4 | db: 5 | image: postgres:10 6 | environment: 7 | POSTGRES_USER: admin 8 | POSTGRES_PASSWORD: password 9 | healthcheck: 10 | test: ["CMD-SHELL", "pg_isready -U postgres"] 11 | interval: 30s 12 | timeout: 30s 13 | retries: 3 14 | 15 | pgweb: 16 | image: sosedoff/pgweb 17 | ports: 18 | - "8081:8081" 19 | environment: 20 | - DATABASE_URL=postgres://admin:password@db:5432/postgres?sslmode=disable 21 | depends_on: 22 | db: 23 | condition: service_healthy -------------------------------------------------------------------------------- /10_docker_tricks/1_healthcheck/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker-compose up -------------------------------------------------------------------------------- /10_docker_tricks/2_multistage_builds/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM maven:3.5-jdk-8 as builder 2 | WORKDIR / 3 | COPY . / 4 | RUN mvn clean package 5 | 6 | FROM openjdk:8-jdk-alpine 7 | LABEL maintainer="j.innerbichler@gmail.com" 8 | COPY --from=builder /target/docker-build-demo-0.0.1-SNAPSHOT.jar app.jar 9 | EXPOSE 8080 10 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] -------------------------------------------------------------------------------- /10_docker_tricks/2_multistage_builds/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.johannesinnerbichler 7 | docker-build-demo 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | docker-build-demo 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.5.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-test 36 | test 37 | 38 | 39 | 40 | 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-maven-plugin 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /10_docker_tricks/2_multistage_builds/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker build -t my-app . 4 | docker run -it --rm --name my-running-app my-app -------------------------------------------------------------------------------- /10_docker_tricks/2_multistage_builds/src/main/java/com/johannesinnerbichler/dockerbuilddemo/DockerBuildDemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.dockerbuilddemo; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DockerBuildDemoApplication { 8 | 9 | public static void main(String[] args) { 10 | System.out.println("It's working. Starting Spring Application..."); 11 | SpringApplication.run(DockerBuildDemoApplication.class, args); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /10_docker_tricks/2_multistage_builds/src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jinnerbichler/blog/db95432aea12d1ccf4319d9db891483ca06aaeb0/10_docker_tricks/2_multistage_builds/src/main/resources/application.properties -------------------------------------------------------------------------------- /10_docker_tricks/2_multistage_builds/src/test/java/com/johannesinnerbichler/dockerbuilddemo/DockerBuildDemoApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.dockerbuilddemo; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class DockerBuildDemoApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /10_docker_tricks/3_network_security/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | 5 | maildev: 6 | image: djfarrelly/maildev:1.0.0-rc2 7 | ports: 8 | - "8082:80" 9 | - "25" 10 | networks: 11 | - frontend 12 | 13 | pgweb: 14 | image: sosedoff/pgweb 15 | restart: on-failure 16 | ports: 17 | - "8081:8081" 18 | environment: 19 | - DATABASE_URL=postgres://admin:password@db:5432/postgres?sslmode=disable 20 | networks: 21 | - frontend 22 | - db-backend 23 | 24 | db: 25 | image: postgres:10 26 | environment: 27 | POSTGRES_USER: admin 28 | POSTGRES_PASSWORD: password 29 | networks: 30 | - db-backend 31 | 32 | networks: 33 | db-backend: 34 | frontend: -------------------------------------------------------------------------------- /10_docker_tricks/3_network_security/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker-compose up 4 | -------------------------------------------------------------------------------- /10_docker_tricks/4_database_init/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | pgweb: 5 | image: sosedoff/pgweb 6 | restart: on-failure 7 | ports: 8 | - "8081:8081" 9 | environment: 10 | - DATABASE_URL=postgres://admin:password@db:5432/persons?sslmode=disable 11 | db: 12 | image: postgres:10 13 | ports: 14 | - "5432:5432" 15 | environment: 16 | POSTGRES_USER: admin 17 | POSTGRES_PASSWORD: password 18 | POSTGRES_DB: persons 19 | volumes: 20 | - ./init.sql:/docker-entrypoint-initdb.d/init.sql -------------------------------------------------------------------------------- /10_docker_tricks/4_database_init/init.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE Persons ( 2 | PersonID int, 3 | LastName varchar(255), 4 | FirstName varchar(255), 5 | Address varchar(255), 6 | City varchar(255) 7 | ); 8 | 9 | INSERT INTO Persons VALUES (1, 'Johannes', 'Innerbichler', 'Salzburg'); -------------------------------------------------------------------------------- /10_docker_tricks/4_database_init/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker-compose up 4 | -------------------------------------------------------------------------------- /10_docker_tricks/5_ps_output/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # more info: https://container42.com/2016/03/27/docker-quicktip-7-psformat/ 4 | docker run busybox echo "hello from busybox" 5 | 6 | docker ps -a --format "table {{.Names}}\\t{{.Image}}\\t{{.Status}}" 7 | 8 | -------------------------------------------------------------------------------- /10_docker_tricks/6_docker_in_docker/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | dind: 5 | image: docker 6 | volumes: 7 | - /var/run/docker.sock:/var/run/docker.sock 8 | entrypoint: ["docker", "run", "busybox", "echo", "\"hello from busybox\""] -------------------------------------------------------------------------------- /10_docker_tricks/6_docker_in_docker/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker-compose up -------------------------------------------------------------------------------- /10_docker_tricks/7_onbuild/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3-onbuild 2 | CMD [ "python", "./main.py" ] -------------------------------------------------------------------------------- /10_docker_tricks/7_onbuild/DockerfileOnBuild: -------------------------------------------------------------------------------- 1 | FROM python:3.6 2 | 3 | RUN mkdir -p /usr/src/app 4 | WORKDIR /usr/src/app 5 | 6 | ONBUILD COPY requirements.txt /usr/src/app/ 7 | ONBUILD RUN pip install --no-cache-dir -r requirements.txt 8 | 9 | ONBUILD COPY . /usr/src/app -------------------------------------------------------------------------------- /10_docker_tricks/7_onbuild/main.py: -------------------------------------------------------------------------------- 1 | import django 2 | 3 | print('It is working. Django version', django.__version__, 'is installed.') 4 | -------------------------------------------------------------------------------- /10_docker_tricks/7_onbuild/requirements.txt: -------------------------------------------------------------------------------- 1 | django -------------------------------------------------------------------------------- /10_docker_tricks/7_onbuild/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker build -t my-onbuild-app . 4 | docker run -it --rm --name my-running-app my-onbuild-app -------------------------------------------------------------------------------- /10_docker_tricks/8_non_root/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.15.3 2 | 3 | # setup configuration 4 | COPY ./nginx.conf /etc/nginx/nginx.conf 5 | 6 | # set proper access right 7 | RUN touch /var/run/nginx.pid && \ 8 | chown -R www-data:www-data /var/run/nginx.pid && \ 9 | chown -R www-data:www-data /var/cache/nginx 10 | 11 | # change user 12 | USER www-data 13 | 14 | # copy static html file 15 | COPY index.html /var/www/htdocs/ -------------------------------------------------------------------------------- /10_docker_tricks/8_non_root/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | nginx: 5 | build: . 6 | ports: 7 | - "80:8080" -------------------------------------------------------------------------------- /10_docker_tricks/8_non_root/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | No Root 6 | 7 | 8 | 9 | 10 |

Running without root ;)

11 | 12 | 13 | -------------------------------------------------------------------------------- /10_docker_tricks/8_non_root/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | error_log /var/log/nginx/error.log warn; 3 | pid /var/run/nginx.pid; 4 | 5 | events { 6 | worker_connections 1024; 7 | } 8 | 9 | http { 10 | include /etc/nginx/mime.types; 11 | default_type application/octet-stream; 12 | 13 | sendfile on; 14 | 15 | keepalive_timeout 65; 16 | 17 | server { 18 | listen 8080; 19 | server_name localhost; 20 | location / { 21 | root /var/www/htdocs; 22 | index index.html index.htm; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /10_docker_tricks/8_non_root/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker-compose up --build -------------------------------------------------------------------------------- /10_docker_tricks/9_apt_get/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:14.04 2 | 3 | RUN apt-get update && apt-get install -y curl 4 | 5 | ENTRYPOINT ["curl", "example.com"] -------------------------------------------------------------------------------- /10_docker_tricks/9_apt_get/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | docker build -t my-app . 4 | docker run -it --rm --name my-running-app my-app 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Code base for blog articles at https://medium.com/@jinnerbichler 2 | 3 | Details can be found in respective folders. 4 | -------------------------------------------------------------------------------- /k8s_keycloak/.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | 3 | target -------------------------------------------------------------------------------- /k8s_keycloak/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM openjdk:8-jdk-alpine 2 | VOLUME /tmp 3 | ARG JAR_FILE 4 | COPY ${JAR_FILE} app.jar 5 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] -------------------------------------------------------------------------------- /k8s_keycloak/kubernetes/app-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: person-app 5 | labels: 6 | name: person-app 7 | app: person-app 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: person-app 13 | template: 14 | metadata: 15 | name: person-app 16 | labels: 17 | app: person-app 18 | name: person-app 19 | spec: 20 | restartPolicy: Always 21 | containers: 22 | - name: keycloak 23 | image: jinnerbichler/keycloak-k8s:latest 24 | imagePullPolicy: IfNotPresent 25 | ports: 26 | - containerPort: 8080 27 | protocol: TCP 28 | resources: 29 | requests: 30 | cpu: 200m 31 | memory: 256Mi 32 | limits: 33 | cpu: 400m 34 | memory: 512Mi 35 | 36 | --- 37 | 38 | apiVersion: v1 39 | kind: Service 40 | metadata: 41 | name: person-app 42 | labels: 43 | app: person-app 44 | name: person-app 45 | spec: 46 | type: NodePort 47 | ports: 48 | - name: http 49 | protocol: TCP 50 | port: 8080 51 | nodePort: 30081 52 | selector: 53 | app: person-app 54 | name: person-app -------------------------------------------------------------------------------- /k8s_keycloak/kubernetes/keycloak-deployment.yml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: keycloak 5 | labels: 6 | name: keycloak 7 | app: keycloak 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: keycloak 13 | template: 14 | metadata: 15 | name: keycloak 16 | labels: 17 | app: keycloak 18 | name: keycloak 19 | spec: 20 | restartPolicy: Always 21 | containers: 22 | - name: keycloak 23 | image: jboss/keycloak:3.4.3.Final 24 | imagePullPolicy: IfNotPresent 25 | ports: 26 | - containerPort: 8080 27 | protocol: TCP 28 | resources: 29 | requests: 30 | cpu: 200m 31 | memory: 256Mi 32 | limits: 33 | cpu: 400m 34 | memory: 512Mi 35 | env: 36 | - name: KEYCLOAK_LOGLEVEL 37 | value: "DEBUG" 38 | - name: PROXY_ADDRESS_FORWARDING 39 | value: "true" 40 | - name: KEYCLOAK_USER 41 | value: "admin" 42 | - name: KEYCLOAK_PASSWORD 43 | value: "password" 44 | - name: POSTGRES_USER 45 | value: "admin" 46 | - name: POSTGRES_PASSWORD 47 | value: "password" 48 | - name: POSTGRES_PORT_5432_TCP_ADDR 49 | value: "keycloak-db-postgresql" 50 | - name: POSTGRES_PORT_5432_TCP_PORT 51 | value: "5432" 52 | - name: POSTGRES_DATABASE 53 | value: "keycloak-db" 54 | 55 | --- 56 | 57 | apiVersion: v1 58 | kind: Service 59 | metadata: 60 | name: keycloak 61 | labels: 62 | app: keycloak 63 | name: keycloak 64 | spec: 65 | type: NodePort 66 | ports: 67 | - name: http 68 | protocol: TCP 69 | port: 8080 70 | nodePort: 30080 71 | selector: 72 | app: keycloak 73 | name: keycloak -------------------------------------------------------------------------------- /k8s_keycloak/persons-application.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /k8s_keycloak/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.johannesinnerbichler 7 | keycloak-k8s 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | person-app 12 | Example project for integrating Keycloak with Spring Boot applications on Kubernetes. 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.5.3.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 3.1.0.Final 26 | jinnerbichler 27 | 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-freemarker 33 | 34 | 35 | org.keycloak 36 | keycloak-spring-boot-starter 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-web 41 | 42 | 43 | org.springframework.boot 44 | spring-boot-starter-security 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.keycloak.bom 57 | keycloak-adapter-bom 58 | ${keycloak.version} 59 | pom 60 | import 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.springframework.boot 69 | spring-boot-maven-plugin 70 | 71 | 72 | com.spotify 73 | dockerfile-maven-plugin 74 | 1.3.6 75 | 76 | ${docker.image.prefix}/${project.artifactId} 77 | 78 | target/${project.build.finalName}.jar 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /k8s_keycloak/readme.md: -------------------------------------------------------------------------------- 1 | ## Setup Prerequisites 2 | 3 | This project shows a simple Spring Boot application with Keycloak. Both, the application and Keycloak (including the database), will be deployed to a Kubernetes cluster. 4 | 5 | The Kubernetes cluster is created via Minikube, which provides tools for creating clusters on a local machine easily. Keycloak, the database, and the Spring Boot application are deployed to the newly created cluster. 6 | The following versions are used throughout the example: 7 | 8 | * __Minikube__: v0.25.0 9 | * __Docker__: 18.03.1-ce 10 | * __Kubectl__: v1.10.1 11 | * __Kubernetes__: v1.9.0 12 | * __Helm__: v2.8.2 13 | * __Spring Boot__: 1.5.3.RELEASE 14 | * __Keycloak__: 3.4.3.Final 15 | 16 | More details on the setup and the example application can be found in the corresponding [blog article](https://medium.com/@jinnerbichler/securing-spring-boot-applications-with-keycloak-on-kubernetes-76cdb6b8d674). -------------------------------------------------------------------------------- /k8s_keycloak/src/main/java/com/johannesinnerbichler/personapp/PersonApplication.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.personapp; 2 | 3 | import org.keycloak.adapters.KeycloakConfigResolver; 4 | import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; 5 | import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents; 6 | import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; 7 | import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; 8 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 9 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 10 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 11 | import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; 12 | import org.springframework.security.core.session.SessionRegistryImpl; 13 | import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; 14 | import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.boot.SpringApplication; 17 | import org.springframework.boot.autoconfigure.SpringBootApplication; 18 | import org.springframework.context.annotation.Bean; 19 | import org.springframework.context.annotation.ComponentScan; 20 | import org.springframework.context.annotation.Configuration; 21 | import org.springframework.stereotype.Controller; 22 | import org.springframework.ui.Model; 23 | import org.springframework.web.bind.annotation.GetMapping; 24 | 25 | import javax.servlet.ServletException; 26 | import javax.servlet.http.HttpServletRequest; 27 | import java.util.Arrays; 28 | 29 | @SpringBootApplication 30 | public class PersonApplication { 31 | 32 | public static void main(String[] args) { 33 | SpringApplication.run(PersonApplication.class, args); 34 | } 35 | } 36 | 37 | @Controller 38 | class PersonController { 39 | 40 | @GetMapping(path = "/persons") 41 | public String getPersons(Model model) { 42 | model.addAttribute("persons", Arrays.asList("John", "David", "Peter")); 43 | return "persons"; 44 | } 45 | 46 | @GetMapping(path = "/logout") 47 | public String logout(HttpServletRequest request) throws ServletException { 48 | request.logout(); 49 | return "/"; 50 | } 51 | } 52 | 53 | @Configuration 54 | @EnableWebSecurity 55 | @ComponentScan(basePackageClasses = KeycloakSecurityComponents.class) 56 | class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { 57 | 58 | /** 59 | * Registers the KeycloakAuthenticationProvider with the authentication manager. 60 | */ 61 | @Autowired 62 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 63 | KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider(); 64 | 65 | // adding proper authority mapper for prefixing role with "ROLE_" 66 | keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); 67 | 68 | auth.authenticationProvider(keycloakAuthenticationProvider); 69 | } 70 | 71 | /** 72 | * Provide a session authentication strategy bean which should be of type 73 | * RegisterSessionAuthenticationStrategy for public or confidential applications 74 | * and NullAuthenticatedSessionStrategy for bearer-only applications. 75 | */ 76 | @Bean 77 | @Override 78 | protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { 79 | return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); 80 | } 81 | 82 | /** 83 | * Use properties in application.properties instead of keycloak.json 84 | */ 85 | @Bean 86 | public KeycloakConfigResolver KeycloakConfigResolver() { 87 | return new KeycloakSpringBootConfigResolver(); 88 | } 89 | 90 | /** 91 | * Secure appropriate endpoints 92 | */ 93 | @Override 94 | protected void configure(HttpSecurity http) throws Exception { 95 | super.configure(http); 96 | http 97 | .authorizeRequests() 98 | .antMatchers("/persons*").hasRole("user") // only user with role user are allowed to access 99 | .anyRequest().permitAll(); 100 | } 101 | } 102 | 103 | -------------------------------------------------------------------------------- /k8s_keycloak/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | keycloak.auth-server-url=http://192.168.99.100:30080/auth/ 2 | keycloak.resource=persons-app 3 | keycloak.realm=master 4 | keycloak.public-client=true 5 | keycloak.principal-attribute=preferred_username 6 | -------------------------------------------------------------------------------- /k8s_keycloak/src/main/resources/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Landing page 6 | 7 | 8 | 9 | All persons 10 | 11 | 12 | -------------------------------------------------------------------------------- /k8s_keycloak/src/main/resources/templates/persons.ftl: -------------------------------------------------------------------------------- 1 | <#import "/spring.ftl" as spring> 2 | 3 | 4 |

Persons

5 | 10 |
11 | Logout 12 | -------------------------------------------------------------------------------- /k8s_keycloak/util.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | set -e # Exits immediately if a command exits with a non-zero status. 5 | 6 | if [[ "$1" = "keycloak-db" ]]; then 7 | 8 | helm install --name keycloak-db \ 9 | --set postgresUser=admin \ 10 | --set postgresPassword=password \ 11 | --set postgresDatabase=keycloak-db \ 12 | stable/postgresql 13 | 14 | elif [ "$1" == "keycloak-start" ]; then 15 | 16 | kubectl apply -f ./kubernetes/keycloak-deployment.yml 17 | 18 | elif [ "$1" == "keycloak-open" ]; then 19 | 20 | minikube service keycloak 21 | 22 | elif [ "$1" == "keycloak-url" ]; then 23 | 24 | minikube service keycloak --url 25 | 26 | elif [ "$1" == "keycloak-logs" ]; then 27 | 28 | POD_NAME=$(kubectl get pods -l name=keycloak -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}') 29 | kubectl logs -f ${POD_NAME} 30 | 31 | elif [ "$1" == "app-open" ]; then 32 | 33 | minikube service person-app 34 | 35 | elif [ "$1" == "app-url" ]; then 36 | 37 | minikube service person-app --url 38 | 39 | elif [ "$1" == "app-logs" ]; then 40 | 41 | POD_NAME=$(kubectl get pods -l name=person-app -o go-template --template '{{range .items}}{{.metadata.name}}{{"\n"}}{{end}}') 42 | kubectl logs -f ${POD_NAME} 43 | 44 | fi 45 | 46 | fi -------------------------------------------------------------------------------- /keycloak_4_spring_boot_2/keycloak/config/PersonRealm-realm.json: -------------------------------------------------------------------------------- 1 | { 2 | "id" : "PersonRealm", 3 | "realm" : "PersonRealm", 4 | "notBefore" : 0, 5 | "revokeRefreshToken" : false, 6 | "refreshTokenMaxReuse" : 0, 7 | "accessTokenLifespan" : 300, 8 | "accessTokenLifespanForImplicitFlow" : 900, 9 | "ssoSessionIdleTimeout" : 1800, 10 | "ssoSessionMaxLifespan" : 36000, 11 | "offlineSessionIdleTimeout" : 2592000, 12 | "accessCodeLifespan" : 60, 13 | "accessCodeLifespanUserAction" : 300, 14 | "accessCodeLifespanLogin" : 1800, 15 | "actionTokenGeneratedByAdminLifespan" : 43200, 16 | "actionTokenGeneratedByUserLifespan" : 300, 17 | "enabled" : true, 18 | "sslRequired" : "external", 19 | "registrationAllowed" : false, 20 | "registrationEmailAsUsername" : false, 21 | "rememberMe" : false, 22 | "verifyEmail" : false, 23 | "loginWithEmailAllowed" : true, 24 | "duplicateEmailsAllowed" : false, 25 | "resetPasswordAllowed" : false, 26 | "editUsernameAllowed" : false, 27 | "bruteForceProtected" : false, 28 | "permanentLockout" : false, 29 | "maxFailureWaitSeconds" : 900, 30 | "minimumQuickLoginWaitSeconds" : 60, 31 | "waitIncrementSeconds" : 60, 32 | "quickLoginCheckMilliSeconds" : 1000, 33 | "maxDeltaTimeSeconds" : 43200, 34 | "failureFactor" : 30, 35 | "roles" : { 36 | "realm" : [ { 37 | "id" : "f1fd854e-ef55-4df3-b256-8e39cd69a589", 38 | "name" : "uma_authorization", 39 | "description" : "${role_uma_authorization}", 40 | "composite" : false, 41 | "clientRole" : false, 42 | "containerId" : "PersonRealm" 43 | }, { 44 | "id" : "e427f7a9-4add-4c6f-a951-77b1b57a463b", 45 | "name" : "offline_access", 46 | "description" : "${role_offline-access}", 47 | "composite" : false, 48 | "clientRole" : false, 49 | "containerId" : "PersonRealm" 50 | }, { 51 | "id" : "be37d4f9-7ee8-4be2-b1a1-15481aef4024", 52 | "name" : "user", 53 | "composite" : false, 54 | "clientRole" : false, 55 | "containerId" : "PersonRealm" 56 | } ], 57 | "client" : { 58 | "realm-management" : [ { 59 | "id" : "9c5314b9-c1d9-449d-b5f6-b6cde96d616d", 60 | "name" : "view-identity-providers", 61 | "description" : "${role_view-identity-providers}", 62 | "composite" : false, 63 | "clientRole" : true, 64 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 65 | }, { 66 | "id" : "f1f305da-12a7-4906-a77f-8954a39a5cb3", 67 | "name" : "manage-users", 68 | "description" : "${role_manage-users}", 69 | "composite" : false, 70 | "clientRole" : true, 71 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 72 | }, { 73 | "id" : "5d44e28d-cf22-4c5e-9517-0f42d02a883c", 74 | "name" : "impersonation", 75 | "description" : "${role_impersonation}", 76 | "composite" : false, 77 | "clientRole" : true, 78 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 79 | }, { 80 | "id" : "0088b2ac-8c27-4274-9b56-1a505def98fc", 81 | "name" : "create-client", 82 | "description" : "${role_create-client}", 83 | "composite" : false, 84 | "clientRole" : true, 85 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 86 | }, { 87 | "id" : "83c7d7da-fcda-4fb6-a705-a14f1a7b9fe5", 88 | "name" : "query-realms", 89 | "description" : "${role_query-realms}", 90 | "composite" : false, 91 | "clientRole" : true, 92 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 93 | }, { 94 | "id" : "f90b735e-abcb-445a-9ef0-a13a9a57e08c", 95 | "name" : "view-clients", 96 | "description" : "${role_view-clients}", 97 | "composite" : true, 98 | "composites" : { 99 | "client" : { 100 | "realm-management" : [ "query-clients" ] 101 | } 102 | }, 103 | "clientRole" : true, 104 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 105 | }, { 106 | "id" : "fc487a40-cdaa-42dd-bd50-2477a3d7239e", 107 | "name" : "view-authorization", 108 | "description" : "${role_view-authorization}", 109 | "composite" : false, 110 | "clientRole" : true, 111 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 112 | }, { 113 | "id" : "3f4e2fd9-2372-4424-87e5-e547bc6d211b", 114 | "name" : "query-users", 115 | "description" : "${role_query-users}", 116 | "composite" : false, 117 | "clientRole" : true, 118 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 119 | }, { 120 | "id" : "d8412b94-0806-4f4b-be37-3454829b8aa4", 121 | "name" : "manage-realm", 122 | "description" : "${role_manage-realm}", 123 | "composite" : false, 124 | "clientRole" : true, 125 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 126 | }, { 127 | "id" : "ffd68f72-06eb-4ef9-9662-74bdd4b9a46a", 128 | "name" : "manage-identity-providers", 129 | "description" : "${role_manage-identity-providers}", 130 | "composite" : false, 131 | "clientRole" : true, 132 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 133 | }, { 134 | "id" : "7367b94d-064c-4418-922f-7828c5c3d333", 135 | "name" : "query-groups", 136 | "description" : "${role_query-groups}", 137 | "composite" : false, 138 | "clientRole" : true, 139 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 140 | }, { 141 | "id" : "551bd221-bffa-4d27-841f-dfc1c89010fb", 142 | "name" : "realm-admin", 143 | "description" : "${role_realm-admin}", 144 | "composite" : true, 145 | "composites" : { 146 | "client" : { 147 | "realm-management" : [ "view-identity-providers", "manage-users", "impersonation", "create-client", "query-realms", "view-clients", "view-authorization", "query-users", "manage-realm", "manage-identity-providers", "query-groups", "manage-clients", "view-events", "view-users", "manage-events", "view-realm", "manage-authorization", "query-clients" ] 148 | } 149 | }, 150 | "clientRole" : true, 151 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 152 | }, { 153 | "id" : "1eb333d2-96e1-49ec-a7e4-10f2c74f730a", 154 | "name" : "manage-clients", 155 | "description" : "${role_manage-clients}", 156 | "composite" : false, 157 | "clientRole" : true, 158 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 159 | }, { 160 | "id" : "318990a0-75e9-417f-bf00-2cfc93f1b2bf", 161 | "name" : "view-events", 162 | "description" : "${role_view-events}", 163 | "composite" : false, 164 | "clientRole" : true, 165 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 166 | }, { 167 | "id" : "573c2f39-49c3-4375-bcc1-9ce5e4f4759a", 168 | "name" : "view-users", 169 | "description" : "${role_view-users}", 170 | "composite" : true, 171 | "composites" : { 172 | "client" : { 173 | "realm-management" : [ "query-users", "query-groups" ] 174 | } 175 | }, 176 | "clientRole" : true, 177 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 178 | }, { 179 | "id" : "375038ea-c600-43cc-bf98-80d52a147ff8", 180 | "name" : "manage-events", 181 | "description" : "${role_manage-events}", 182 | "composite" : false, 183 | "clientRole" : true, 184 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 185 | }, { 186 | "id" : "b9d47a12-99f5-42b6-9465-9a4246c741f9", 187 | "name" : "view-realm", 188 | "description" : "${role_view-realm}", 189 | "composite" : false, 190 | "clientRole" : true, 191 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 192 | }, { 193 | "id" : "401d748c-3f89-4eb7-8a1d-a222f31fd27b", 194 | "name" : "manage-authorization", 195 | "description" : "${role_manage-authorization}", 196 | "composite" : false, 197 | "clientRole" : true, 198 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 199 | }, { 200 | "id" : "3d3b7c47-9f5e-4c62-94d3-43b93ae5f248", 201 | "name" : "query-clients", 202 | "description" : "${role_query-clients}", 203 | "composite" : false, 204 | "clientRole" : true, 205 | "containerId" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9" 206 | } ], 207 | "security-admin-console" : [ ], 208 | "admin-cli" : [ ], 209 | "persons-app" : [ ], 210 | "broker" : [ { 211 | "id" : "1b8bce57-194a-46b5-8315-6846c7501efc", 212 | "name" : "read-token", 213 | "description" : "${role_read-token}", 214 | "composite" : false, 215 | "clientRole" : true, 216 | "containerId" : "b34e5ac9-79a5-4242-81b2-2fdfa3847386" 217 | } ], 218 | "account" : [ { 219 | "id" : "58928f97-e7e3-486f-b091-028ec718dcd1", 220 | "name" : "manage-account-links", 221 | "description" : "${role_manage-account-links}", 222 | "composite" : false, 223 | "clientRole" : true, 224 | "containerId" : "53955858-c44e-462e-bb17-b9377998d1c1" 225 | }, { 226 | "id" : "a0f4c87e-49fd-4d21-a715-d922a0ef5dab", 227 | "name" : "view-profile", 228 | "description" : "${role_view-profile}", 229 | "composite" : false, 230 | "clientRole" : true, 231 | "containerId" : "53955858-c44e-462e-bb17-b9377998d1c1" 232 | }, { 233 | "id" : "9a96bbe2-ecd3-436c-8023-4e85e6352f42", 234 | "name" : "manage-account", 235 | "description" : "${role_manage-account}", 236 | "composite" : true, 237 | "composites" : { 238 | "client" : { 239 | "account" : [ "manage-account-links" ] 240 | } 241 | }, 242 | "clientRole" : true, 243 | "containerId" : "53955858-c44e-462e-bb17-b9377998d1c1" 244 | } ] 245 | } 246 | }, 247 | "groups" : [ ], 248 | "defaultRoles" : [ "uma_authorization", "offline_access" ], 249 | "requiredCredentials" : [ "password" ], 250 | "otpPolicyType" : "totp", 251 | "otpPolicyAlgorithm" : "HmacSHA1", 252 | "otpPolicyInitialCounter" : 0, 253 | "otpPolicyDigits" : 6, 254 | "otpPolicyLookAheadWindow" : 1, 255 | "otpPolicyPeriod" : 30, 256 | "otpSupportedApplications" : [ "FreeOTP", "Google Authenticator" ], 257 | "scopeMappings" : [ { 258 | "clientScope" : "offline_access", 259 | "roles" : [ "offline_access" ] 260 | } ], 261 | "clients" : [ { 262 | "id" : "53955858-c44e-462e-bb17-b9377998d1c1", 263 | "clientId" : "account", 264 | "name" : "${client_account}", 265 | "baseUrl" : "/auth/realms/PersonRealm/account", 266 | "surrogateAuthRequired" : false, 267 | "enabled" : true, 268 | "clientAuthenticatorType" : "client-secret", 269 | "secret" : "**********", 270 | "defaultRoles" : [ "view-profile", "manage-account" ], 271 | "redirectUris" : [ "/auth/realms/PersonRealm/account/*" ], 272 | "webOrigins" : [ ], 273 | "notBefore" : 0, 274 | "bearerOnly" : false, 275 | "consentRequired" : false, 276 | "standardFlowEnabled" : true, 277 | "implicitFlowEnabled" : false, 278 | "directAccessGrantsEnabled" : false, 279 | "serviceAccountsEnabled" : false, 280 | "publicClient" : false, 281 | "frontchannelLogout" : false, 282 | "protocol" : "openid-connect", 283 | "attributes" : { }, 284 | "authenticationFlowBindingOverrides" : { }, 285 | "fullScopeAllowed" : false, 286 | "nodeReRegistrationTimeout" : 0, 287 | "defaultClientScopes" : [ "role_list", "profile", "email" ], 288 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 289 | }, { 290 | "id" : "00561324-be76-43e0-860d-6131e6a111df", 291 | "clientId" : "admin-cli", 292 | "name" : "${client_admin-cli}", 293 | "surrogateAuthRequired" : false, 294 | "enabled" : true, 295 | "clientAuthenticatorType" : "client-secret", 296 | "secret" : "**********", 297 | "redirectUris" : [ ], 298 | "webOrigins" : [ ], 299 | "notBefore" : 0, 300 | "bearerOnly" : false, 301 | "consentRequired" : false, 302 | "standardFlowEnabled" : false, 303 | "implicitFlowEnabled" : false, 304 | "directAccessGrantsEnabled" : true, 305 | "serviceAccountsEnabled" : false, 306 | "publicClient" : true, 307 | "frontchannelLogout" : false, 308 | "protocol" : "openid-connect", 309 | "attributes" : { }, 310 | "authenticationFlowBindingOverrides" : { }, 311 | "fullScopeAllowed" : false, 312 | "nodeReRegistrationTimeout" : 0, 313 | "defaultClientScopes" : [ "role_list", "profile", "email" ], 314 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 315 | }, { 316 | "id" : "b34e5ac9-79a5-4242-81b2-2fdfa3847386", 317 | "clientId" : "broker", 318 | "name" : "${client_broker}", 319 | "surrogateAuthRequired" : false, 320 | "enabled" : true, 321 | "clientAuthenticatorType" : "client-secret", 322 | "secret" : "**********", 323 | "redirectUris" : [ ], 324 | "webOrigins" : [ ], 325 | "notBefore" : 0, 326 | "bearerOnly" : false, 327 | "consentRequired" : false, 328 | "standardFlowEnabled" : true, 329 | "implicitFlowEnabled" : false, 330 | "directAccessGrantsEnabled" : false, 331 | "serviceAccountsEnabled" : false, 332 | "publicClient" : false, 333 | "frontchannelLogout" : false, 334 | "protocol" : "openid-connect", 335 | "attributes" : { }, 336 | "authenticationFlowBindingOverrides" : { }, 337 | "fullScopeAllowed" : false, 338 | "nodeReRegistrationTimeout" : 0, 339 | "defaultClientScopes" : [ "role_list", "profile", "email" ], 340 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 341 | }, { 342 | "id" : "bef95718-8080-465c-b242-94730834379f", 343 | "clientId" : "persons-app", 344 | "baseUrl" : "http://localhost:8080/", 345 | "surrogateAuthRequired" : false, 346 | "enabled" : true, 347 | "clientAuthenticatorType" : "client-secret", 348 | "secret" : "**********", 349 | "redirectUris" : [ "http://localhost:8080/*" ], 350 | "webOrigins" : [ ], 351 | "notBefore" : 0, 352 | "bearerOnly" : false, 353 | "consentRequired" : false, 354 | "standardFlowEnabled" : true, 355 | "implicitFlowEnabled" : false, 356 | "directAccessGrantsEnabled" : true, 357 | "serviceAccountsEnabled" : false, 358 | "publicClient" : true, 359 | "frontchannelLogout" : false, 360 | "protocol" : "openid-connect", 361 | "attributes" : { 362 | "saml.assertion.signature" : "false", 363 | "saml.force.post.binding" : "false", 364 | "saml.multivalued.roles" : "false", 365 | "saml.encrypt" : "false", 366 | "saml.server.signature" : "false", 367 | "saml.server.signature.keyinfo.ext" : "false", 368 | "exclude.session.state.from.auth.response" : "false", 369 | "saml_force_name_id_format" : "false", 370 | "saml.client.signature" : "false", 371 | "tls.client.certificate.bound.access.tokens" : "false", 372 | "saml.authnstatement" : "false", 373 | "display.on.consent.screen" : "false", 374 | "saml.onetimeuse.condition" : "false" 375 | }, 376 | "authenticationFlowBindingOverrides" : { }, 377 | "fullScopeAllowed" : true, 378 | "nodeReRegistrationTimeout" : -1, 379 | "defaultClientScopes" : [ "role_list", "profile", "email" ], 380 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 381 | }, { 382 | "id" : "bf8bb9d8-0a7b-44aa-8605-4e118682a7c9", 383 | "clientId" : "realm-management", 384 | "name" : "${client_realm-management}", 385 | "surrogateAuthRequired" : false, 386 | "enabled" : true, 387 | "clientAuthenticatorType" : "client-secret", 388 | "secret" : "**********", 389 | "redirectUris" : [ ], 390 | "webOrigins" : [ ], 391 | "notBefore" : 0, 392 | "bearerOnly" : true, 393 | "consentRequired" : false, 394 | "standardFlowEnabled" : true, 395 | "implicitFlowEnabled" : false, 396 | "directAccessGrantsEnabled" : false, 397 | "serviceAccountsEnabled" : false, 398 | "publicClient" : false, 399 | "frontchannelLogout" : false, 400 | "protocol" : "openid-connect", 401 | "attributes" : { }, 402 | "authenticationFlowBindingOverrides" : { }, 403 | "fullScopeAllowed" : false, 404 | "nodeReRegistrationTimeout" : 0, 405 | "defaultClientScopes" : [ "role_list", "profile", "email" ], 406 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 407 | }, { 408 | "id" : "b40d57ce-7f22-40eb-89a7-d8272c614bd7", 409 | "clientId" : "security-admin-console", 410 | "name" : "${client_security-admin-console}", 411 | "baseUrl" : "/auth/admin/PersonRealm/console/index.html", 412 | "surrogateAuthRequired" : false, 413 | "enabled" : true, 414 | "clientAuthenticatorType" : "client-secret", 415 | "secret" : "**********", 416 | "redirectUris" : [ "/auth/admin/PersonRealm/console/*" ], 417 | "webOrigins" : [ ], 418 | "notBefore" : 0, 419 | "bearerOnly" : false, 420 | "consentRequired" : false, 421 | "standardFlowEnabled" : true, 422 | "implicitFlowEnabled" : false, 423 | "directAccessGrantsEnabled" : false, 424 | "serviceAccountsEnabled" : false, 425 | "publicClient" : true, 426 | "frontchannelLogout" : false, 427 | "protocol" : "openid-connect", 428 | "attributes" : { }, 429 | "authenticationFlowBindingOverrides" : { }, 430 | "fullScopeAllowed" : false, 431 | "nodeReRegistrationTimeout" : 0, 432 | "protocolMappers" : [ { 433 | "id" : "b486d4cf-2fcc-4dde-960c-cfceafe91f06", 434 | "name" : "locale", 435 | "protocol" : "openid-connect", 436 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 437 | "consentRequired" : false, 438 | "config" : { 439 | "userinfo.token.claim" : "true", 440 | "user.attribute" : "locale", 441 | "id.token.claim" : "true", 442 | "access.token.claim" : "true", 443 | "claim.name" : "locale", 444 | "jsonType.label" : "String" 445 | } 446 | } ], 447 | "defaultClientScopes" : [ "role_list", "profile", "email" ], 448 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 449 | } ], 450 | "clientScopes" : [ { 451 | "id" : "1cb966fd-2a2d-4b3f-850e-ae541bbf44b1", 452 | "name" : "offline_access", 453 | "description" : "OpenID Connect built-in scope: offline_access", 454 | "protocol" : "openid-connect", 455 | "attributes" : { 456 | "consent.screen.text" : "${offlineAccessScopeConsentText}", 457 | "display.on.consent.screen" : "true" 458 | } 459 | }, { 460 | "id" : "0cdbb297-b565-4048-b11d-8d53dd55d887", 461 | "name" : "role_list", 462 | "description" : "SAML role list", 463 | "protocol" : "saml", 464 | "attributes" : { 465 | "consent.screen.text" : "${samlRoleListScopeConsentText}", 466 | "display.on.consent.screen" : "true" 467 | }, 468 | "protocolMappers" : [ { 469 | "id" : "1982e790-d3dc-46e5-8a84-eed22f88e0f9", 470 | "name" : "role list", 471 | "protocol" : "saml", 472 | "protocolMapper" : "saml-role-list-mapper", 473 | "consentRequired" : false, 474 | "config" : { 475 | "single" : "false", 476 | "attribute.nameformat" : "Basic", 477 | "attribute.name" : "Role" 478 | } 479 | } ] 480 | }, { 481 | "id" : "b12748f6-57df-4c27-80ec-2f05a8af43be", 482 | "name" : "profile", 483 | "description" : "OpenID Connect built-in scope: profile", 484 | "protocol" : "openid-connect", 485 | "attributes" : { 486 | "consent.screen.text" : "${profileScopeConsentText}", 487 | "display.on.consent.screen" : "true" 488 | }, 489 | "protocolMappers" : [ { 490 | "id" : "703e93ee-35bd-46a9-89b2-adaa47447c43", 491 | "name" : "given name", 492 | "protocol" : "openid-connect", 493 | "protocolMapper" : "oidc-usermodel-property-mapper", 494 | "consentRequired" : false, 495 | "config" : { 496 | "userinfo.token.claim" : "true", 497 | "user.attribute" : "firstName", 498 | "id.token.claim" : "true", 499 | "access.token.claim" : "true", 500 | "claim.name" : "given_name", 501 | "jsonType.label" : "String" 502 | } 503 | }, { 504 | "id" : "e924738f-ae01-4e04-a33b-f9d31c609d8a", 505 | "name" : "zoneinfo", 506 | "protocol" : "openid-connect", 507 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 508 | "consentRequired" : false, 509 | "config" : { 510 | "userinfo.token.claim" : "true", 511 | "user.attribute" : "zoneinfo", 512 | "id.token.claim" : "true", 513 | "access.token.claim" : "true", 514 | "claim.name" : "zoneinfo", 515 | "jsonType.label" : "String" 516 | } 517 | }, { 518 | "id" : "280677f2-c9a9-4876-94fe-add64181467c", 519 | "name" : "picture", 520 | "protocol" : "openid-connect", 521 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 522 | "consentRequired" : false, 523 | "config" : { 524 | "userinfo.token.claim" : "true", 525 | "user.attribute" : "picture", 526 | "id.token.claim" : "true", 527 | "access.token.claim" : "true", 528 | "claim.name" : "picture", 529 | "jsonType.label" : "String" 530 | } 531 | }, { 532 | "id" : "23631684-ffb2-4127-be27-96f0c4761d0d", 533 | "name" : "birthdate", 534 | "protocol" : "openid-connect", 535 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 536 | "consentRequired" : false, 537 | "config" : { 538 | "userinfo.token.claim" : "true", 539 | "user.attribute" : "birthdate", 540 | "id.token.claim" : "true", 541 | "access.token.claim" : "true", 542 | "claim.name" : "birthdate", 543 | "jsonType.label" : "String" 544 | } 545 | }, { 546 | "id" : "0331ba55-8552-46d9-a55b-e9b0475e142f", 547 | "name" : "nickname", 548 | "protocol" : "openid-connect", 549 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 550 | "consentRequired" : false, 551 | "config" : { 552 | "userinfo.token.claim" : "true", 553 | "user.attribute" : "nickname", 554 | "id.token.claim" : "true", 555 | "access.token.claim" : "true", 556 | "claim.name" : "nickname", 557 | "jsonType.label" : "String" 558 | } 559 | }, { 560 | "id" : "45a14c9a-923a-47bb-a794-767ec624c1ed", 561 | "name" : "profile", 562 | "protocol" : "openid-connect", 563 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 564 | "consentRequired" : false, 565 | "config" : { 566 | "userinfo.token.claim" : "true", 567 | "user.attribute" : "profile", 568 | "id.token.claim" : "true", 569 | "access.token.claim" : "true", 570 | "claim.name" : "profile", 571 | "jsonType.label" : "String" 572 | } 573 | }, { 574 | "id" : "180f1743-31d2-41bd-8bfe-6855fc3818e5", 575 | "name" : "website", 576 | "protocol" : "openid-connect", 577 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 578 | "consentRequired" : false, 579 | "config" : { 580 | "userinfo.token.claim" : "true", 581 | "user.attribute" : "website", 582 | "id.token.claim" : "true", 583 | "access.token.claim" : "true", 584 | "claim.name" : "website", 585 | "jsonType.label" : "String" 586 | } 587 | }, { 588 | "id" : "9fb04bdb-2c2e-4e17-914c-01963f978097", 589 | "name" : "gender", 590 | "protocol" : "openid-connect", 591 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 592 | "consentRequired" : false, 593 | "config" : { 594 | "userinfo.token.claim" : "true", 595 | "user.attribute" : "gender", 596 | "id.token.claim" : "true", 597 | "access.token.claim" : "true", 598 | "claim.name" : "gender", 599 | "jsonType.label" : "String" 600 | } 601 | }, { 602 | "id" : "210ef4e2-c552-447b-8c35-0388612a8a7d", 603 | "name" : "username", 604 | "protocol" : "openid-connect", 605 | "protocolMapper" : "oidc-usermodel-property-mapper", 606 | "consentRequired" : false, 607 | "config" : { 608 | "userinfo.token.claim" : "true", 609 | "user.attribute" : "username", 610 | "id.token.claim" : "true", 611 | "access.token.claim" : "true", 612 | "claim.name" : "preferred_username", 613 | "jsonType.label" : "String" 614 | } 615 | }, { 616 | "id" : "bb71ec7d-06f1-409d-bb41-f85156061d08", 617 | "name" : "middle name", 618 | "protocol" : "openid-connect", 619 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 620 | "consentRequired" : false, 621 | "config" : { 622 | "userinfo.token.claim" : "true", 623 | "user.attribute" : "middleName", 624 | "id.token.claim" : "true", 625 | "access.token.claim" : "true", 626 | "claim.name" : "middle_name", 627 | "jsonType.label" : "String" 628 | } 629 | }, { 630 | "id" : "01027a38-0ec8-4447-8cce-cf4b2f5ae712", 631 | "name" : "updated at", 632 | "protocol" : "openid-connect", 633 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 634 | "consentRequired" : false, 635 | "config" : { 636 | "userinfo.token.claim" : "true", 637 | "user.attribute" : "updatedAt", 638 | "id.token.claim" : "true", 639 | "access.token.claim" : "true", 640 | "claim.name" : "updated_at", 641 | "jsonType.label" : "String" 642 | } 643 | }, { 644 | "id" : "8c851fa5-8727-45d6-b4cc-5fb75b902127", 645 | "name" : "locale", 646 | "protocol" : "openid-connect", 647 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 648 | "consentRequired" : false, 649 | "config" : { 650 | "userinfo.token.claim" : "true", 651 | "user.attribute" : "locale", 652 | "id.token.claim" : "true", 653 | "access.token.claim" : "true", 654 | "claim.name" : "locale", 655 | "jsonType.label" : "String" 656 | } 657 | }, { 658 | "id" : "0eedaa1b-0a0b-491d-bb49-e63ab26734f9", 659 | "name" : "family name", 660 | "protocol" : "openid-connect", 661 | "protocolMapper" : "oidc-usermodel-property-mapper", 662 | "consentRequired" : false, 663 | "config" : { 664 | "userinfo.token.claim" : "true", 665 | "user.attribute" : "lastName", 666 | "id.token.claim" : "true", 667 | "access.token.claim" : "true", 668 | "claim.name" : "family_name", 669 | "jsonType.label" : "String" 670 | } 671 | }, { 672 | "id" : "03adb547-2127-41e2-9101-19a4646bc314", 673 | "name" : "full name", 674 | "protocol" : "openid-connect", 675 | "protocolMapper" : "oidc-full-name-mapper", 676 | "consentRequired" : false, 677 | "config" : { 678 | "id.token.claim" : "true", 679 | "access.token.claim" : "true", 680 | "userinfo.token.claim" : "true" 681 | } 682 | } ] 683 | }, { 684 | "id" : "444173d1-a4cd-4adc-a831-842ddcae18a5", 685 | "name" : "email", 686 | "description" : "OpenID Connect built-in scope: email", 687 | "protocol" : "openid-connect", 688 | "attributes" : { 689 | "consent.screen.text" : "${emailScopeConsentText}", 690 | "display.on.consent.screen" : "true" 691 | }, 692 | "protocolMappers" : [ { 693 | "id" : "3bb21539-0281-4bf4-a57b-ad3e715658df", 694 | "name" : "email", 695 | "protocol" : "openid-connect", 696 | "protocolMapper" : "oidc-usermodel-property-mapper", 697 | "consentRequired" : false, 698 | "config" : { 699 | "userinfo.token.claim" : "true", 700 | "user.attribute" : "email", 701 | "id.token.claim" : "true", 702 | "access.token.claim" : "true", 703 | "claim.name" : "email", 704 | "jsonType.label" : "String" 705 | } 706 | }, { 707 | "id" : "a5c03d59-f8d4-43da-8949-73ede4cb307a", 708 | "name" : "email verified", 709 | "protocol" : "openid-connect", 710 | "protocolMapper" : "oidc-usermodel-property-mapper", 711 | "consentRequired" : false, 712 | "config" : { 713 | "userinfo.token.claim" : "true", 714 | "user.attribute" : "emailVerified", 715 | "id.token.claim" : "true", 716 | "access.token.claim" : "true", 717 | "claim.name" : "email_verified", 718 | "jsonType.label" : "boolean" 719 | } 720 | } ] 721 | }, { 722 | "id" : "c72035d3-f82b-4316-8fb1-82c6316a954d", 723 | "name" : "address", 724 | "description" : "OpenID Connect built-in scope: address", 725 | "protocol" : "openid-connect", 726 | "attributes" : { 727 | "consent.screen.text" : "${addressScopeConsentText}", 728 | "display.on.consent.screen" : "true" 729 | }, 730 | "protocolMappers" : [ { 731 | "id" : "379c75c6-4393-412d-9a47-a004172b4f37", 732 | "name" : "address", 733 | "protocol" : "openid-connect", 734 | "protocolMapper" : "oidc-address-mapper", 735 | "consentRequired" : false, 736 | "config" : { 737 | "user.attribute.formatted" : "formatted", 738 | "user.attribute.country" : "country", 739 | "user.attribute.postal_code" : "postal_code", 740 | "userinfo.token.claim" : "true", 741 | "user.attribute.street" : "street", 742 | "id.token.claim" : "true", 743 | "user.attribute.region" : "region", 744 | "access.token.claim" : "true", 745 | "user.attribute.locality" : "locality" 746 | } 747 | } ] 748 | }, { 749 | "id" : "48563fc3-c999-4d5e-9ecd-d6fd503e017f", 750 | "name" : "phone", 751 | "description" : "OpenID Connect built-in scope: phone", 752 | "protocol" : "openid-connect", 753 | "attributes" : { 754 | "consent.screen.text" : "${phoneScopeConsentText}", 755 | "display.on.consent.screen" : "true" 756 | }, 757 | "protocolMappers" : [ { 758 | "id" : "b9814882-f42d-4c25-92c8-53d9b6f8e031", 759 | "name" : "phone number verified", 760 | "protocol" : "openid-connect", 761 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 762 | "consentRequired" : false, 763 | "config" : { 764 | "userinfo.token.claim" : "true", 765 | "user.attribute" : "phoneNumberVerified", 766 | "id.token.claim" : "true", 767 | "access.token.claim" : "true", 768 | "claim.name" : "phone_number_verified", 769 | "jsonType.label" : "boolean" 770 | } 771 | }, { 772 | "id" : "058ef5e4-698c-40e7-ac7f-8ab20edb0b6c", 773 | "name" : "phone number", 774 | "protocol" : "openid-connect", 775 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 776 | "consentRequired" : false, 777 | "config" : { 778 | "userinfo.token.claim" : "true", 779 | "user.attribute" : "phoneNumber", 780 | "id.token.claim" : "true", 781 | "access.token.claim" : "true", 782 | "claim.name" : "phone_number", 783 | "jsonType.label" : "String" 784 | } 785 | } ] 786 | } ], 787 | "defaultDefaultClientScopes" : [ "role_list", "profile", "email" ], 788 | "defaultOptionalClientScopes" : [ "offline_access", "address", "phone" ], 789 | "browserSecurityHeaders" : { 790 | "xContentTypeOptions" : "nosniff", 791 | "xRobotsTag" : "none", 792 | "xFrameOptions" : "SAMEORIGIN", 793 | "xXSSProtection" : "1; mode=block", 794 | "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", 795 | "strictTransportSecurity" : "max-age=31536000; includeSubDomains" 796 | }, 797 | "smtpServer" : { }, 798 | "eventsEnabled" : false, 799 | "eventsListeners" : [ "jboss-logging" ], 800 | "enabledEventTypes" : [ ], 801 | "adminEventsEnabled" : false, 802 | "adminEventsDetailsEnabled" : false, 803 | "components" : { 804 | "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { 805 | "id" : "9ed2a7d8-6222-4035-aa72-939034d70ec7", 806 | "name" : "Allowed Client Scopes", 807 | "providerId" : "allowed-client-templates", 808 | "subType" : "authenticated", 809 | "subComponents" : { }, 810 | "config" : { 811 | "allow-default-scopes" : [ "true" ] 812 | } 813 | }, { 814 | "id" : "2af3bafd-c4c5-46cf-b3d2-ab011d94b699", 815 | "name" : "Trusted Hosts", 816 | "providerId" : "trusted-hosts", 817 | "subType" : "anonymous", 818 | "subComponents" : { }, 819 | "config" : { 820 | "host-sending-registration-request-must-match" : [ "true" ], 821 | "client-uris-must-match" : [ "true" ] 822 | } 823 | }, { 824 | "id" : "b045a99f-467c-4ff9-9b87-aaf6c6fb5b0f", 825 | "name" : "Full Scope Disabled", 826 | "providerId" : "scope", 827 | "subType" : "anonymous", 828 | "subComponents" : { }, 829 | "config" : { } 830 | }, { 831 | "id" : "11d6c898-835a-479f-9f45-fbf44d2735e2", 832 | "name" : "Allowed Protocol Mapper Types", 833 | "providerId" : "allowed-protocol-mappers", 834 | "subType" : "authenticated", 835 | "subComponents" : { }, 836 | "config" : { 837 | "allowed-protocol-mapper-types" : [ "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", "saml-user-property-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-usermodel-property-mapper", "oidc-full-name-mapper" ] 838 | } 839 | }, { 840 | "id" : "145d2faa-e533-4601-88aa-2fea7e0ba2b1", 841 | "name" : "Allowed Protocol Mapper Types", 842 | "providerId" : "allowed-protocol-mappers", 843 | "subType" : "anonymous", 844 | "subComponents" : { }, 845 | "config" : { 846 | "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-user-property-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-address-mapper" ] 847 | } 848 | }, { 849 | "id" : "e79f1e93-d630-4329-b9d6-f0a09cf64311", 850 | "name" : "Max Clients Limit", 851 | "providerId" : "max-clients", 852 | "subType" : "anonymous", 853 | "subComponents" : { }, 854 | "config" : { 855 | "max-clients" : [ "200" ] 856 | } 857 | }, { 858 | "id" : "a185eed3-2eb9-48cc-a316-84ab9009affd", 859 | "name" : "Allowed Client Scopes", 860 | "providerId" : "allowed-client-templates", 861 | "subType" : "anonymous", 862 | "subComponents" : { }, 863 | "config" : { 864 | "allow-default-scopes" : [ "true" ] 865 | } 866 | }, { 867 | "id" : "06fc217f-2339-428a-88ce-9a9addca99c8", 868 | "name" : "Consent Required", 869 | "providerId" : "consent-required", 870 | "subType" : "anonymous", 871 | "subComponents" : { }, 872 | "config" : { } 873 | } ], 874 | "org.keycloak.keys.KeyProvider" : [ { 875 | "id" : "660d172e-2602-4c60-8a4e-dda577889ea6", 876 | "name" : "hmac-generated", 877 | "providerId" : "hmac-generated", 878 | "subComponents" : { }, 879 | "config" : { 880 | "kid" : [ "9e5a2be1-41cf-451c-9e74-e96b24945d41" ], 881 | "secret" : [ "QlJz9cfoUP2kOWfjZmIW41l4exXIylpQJIC-Rue8j8g" ], 882 | "priority" : [ "100" ] 883 | } 884 | }, { 885 | "id" : "69972cdf-bb31-43ea-bfa9-8091edcc2669", 886 | "name" : "aes-generated", 887 | "providerId" : "aes-generated", 888 | "subComponents" : { }, 889 | "config" : { 890 | "kid" : [ "e790563c-82a4-4990-baa7-412e01c019cc" ], 891 | "secret" : [ "iDOwuVebs_SrcZfWddo3iw" ], 892 | "priority" : [ "100" ] 893 | } 894 | }, { 895 | "id" : "a098753f-1121-4cfe-956f-f483cb741603", 896 | "name" : "rsa-generated", 897 | "providerId" : "rsa-generated", 898 | "subComponents" : { }, 899 | "config" : { 900 | "privateKey" : [ "MIIEogIBAAKCAQEAigava4XHe0clhOr4FV+DY9vusim5ErvpIwRcIWYWuzTCmSx/RyfIxe/meupyTSp1/cgRd06V0zHUbAtxNJ5m4ShLOmGP2dwEl+SqOT/QFG4kU/2zQFvj+6+38HimMeBU0S2VJPo70drj0O7OpMSOarxy5AMGj8eMZz+vRkOS94Ma1dL78p8DMeRYVhcm19Vx59baWBvMW7kNymrDPfgrzZsPkEkPg+IOXl1AQ4ziIa9xI38J2Z+C+J8t+yoPO7/kAbvwQIpJU+v5CjrObu15I7PMzxthc+ZIvWhhI8W+vytCCvVQXkLbtnJSYjz3eFhqcIF66TEGrjDumFZOG5fVwQIDAQABAoIBAFPohoHmHQP7l3p7YX+UxgpR7IUQyjryU2N/RgbjyhPamiaGH4YBUJPMKKA2oG/6zSoPk1alRn3SgCGCvzpOxZpBZaJDJzE5CO3SDA2rlnKlFp6cz3jjo/AgvcCJh/cwOj/D5zRIj08fM3mTg7o056NJlsq4cCe+FsO5unMLp2+hrHfSeW3+wyeRhUlGRSgk5VdvZnk2Z4Of92RpoT9bIMDW3m6aCwadeJkIHkVIyAy+T1yIj5CrHQegcQxLn5jFyOknJj2UPgGyEg5LUQvFZEoWgpg/wqHiZdccrP6AKBQy/O/xqG47fwPByJHLmK4ybjvp/XxNBZ+KUynTvQlLscECgYEA/JmXDkIjS0CLcHf1WBj0SmJLiVy5rNIN5s3v9Gh2f9s6dJ7tgDudHMA2dkfKOezsetdF2kesPFN+xhxkIo7ao0PpwplLnVIxhTO3W79xODZp+BYXTIIl2istPX5Q8+LlCMZlTipXRDYAXk9NSi3oEthhdM6StK64qjD73fXg4CkCgYEAi+JL0TVXzH1RI2A+5lF6V7Rk/RLEQX156csbECme8huEH7eYbMDubdBX3ywbFvJqYQBU8Yr7C99M55rw2Qr04cDLr544YksYPCBLqmnk2SNzWTF3hHY/BFCv6pYcblsnEmGBemFjTE1P3SMyvmCrpas1H2zXw9/KziC3ygpZm9kCgYAH4suieFIdwVAZHMWeEHlf8R2mlix9xrkEYZ2CJdi9ORzkEyoa/MF06lNI8gjQMiNX2myl2eL4pyqoCK7fnVIaEr6zgpGnwa8mF208AggI1zoLsrTbgJyp6Psqlkz0sDqyQW9cN1ouGPl9+D/Tdwdtvy+bs+9EkMfXGFxkm45/sQKBgFLA/p920kk8ferSvoNdAmauZuw81PP1elEwggMuzERouOJWqAr2nFdE4Sc7HY+WvA5Etvvqf5hHc2S1CfUtATAo8ZckoDCuQlkXtgvL98Hpsgy7MfygQ6mW3muGgK1cqaG7I3E1+huixTOK5jMwV3t77MJ5jq/nTkBhpLkXJGoJAoGAJk0uIgJfFcuYUSyhKvKyniHGQ4KFR2vTiiiwXqHfrmhzrTkok+8iR2Vq4ST8Hzkamm3GpIsBw807WP0XCsnPDdXu/k0vJ9TyH95KGIWCZApp2XXq1uHvGfF+0kaOFVf8QYqHNsxwm9yytpsNX3ExGxCt4WwY/RYpHrpzL6Ftw1M=" ], 901 | "certificate" : [ "MIICpTCCAY0CBgFkADdOLzANBgkqhkiG9w0BAQsFADAWMRQwEgYDVQQDDAtQZXJzb25SZWFsbTAeFw0xODA2MTQyMTMxMjFaFw0yODA2MTQyMTMzMDFaMBYxFDASBgNVBAMMC1BlcnNvblJlYWxtMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAigava4XHe0clhOr4FV+DY9vusim5ErvpIwRcIWYWuzTCmSx/RyfIxe/meupyTSp1/cgRd06V0zHUbAtxNJ5m4ShLOmGP2dwEl+SqOT/QFG4kU/2zQFvj+6+38HimMeBU0S2VJPo70drj0O7OpMSOarxy5AMGj8eMZz+vRkOS94Ma1dL78p8DMeRYVhcm19Vx59baWBvMW7kNymrDPfgrzZsPkEkPg+IOXl1AQ4ziIa9xI38J2Z+C+J8t+yoPO7/kAbvwQIpJU+v5CjrObu15I7PMzxthc+ZIvWhhI8W+vytCCvVQXkLbtnJSYjz3eFhqcIF66TEGrjDumFZOG5fVwQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQB/txYzi8urNj9XjpEiXj6z7m2P9CzDAU9fs5X81p6cdt+UeVwJG2bQpbr+uuMN3HVkYlcBSbkDtanc3WGyER/p90sqBLd+wJl7k16LDMawU+FypSFwm7ZQT8Cp+yeYzyS0QvFHrKgZeZZJoIDtyuZOYzLVHDE0vEe0qPMAU6R99xAbIOJs+aqNM9YWVA7eBD0EMncozmXCZ3Prbln+uth38h2WwsK1X4lylGB08vleXMOtKaAgIB9RlCjDWiMbjQNQiNwU761AvCmP42LxPwBZy7fDVl7UhtOCGTwHKwp0egtA0ohKMlAJ0uULgAASVay5u9gYUUFOLAJqvzsRvLaM" ], 902 | "priority" : [ "100" ] 903 | } 904 | } ] 905 | }, 906 | "internationalizationEnabled" : false, 907 | "supportedLocales" : [ ], 908 | "authenticationFlows" : [ { 909 | "id" : "99ed1d67-28d3-49a3-823f-c1c8d8eb5d4f", 910 | "alias" : "Handle Existing Account", 911 | "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", 912 | "providerId" : "basic-flow", 913 | "topLevel" : false, 914 | "builtIn" : true, 915 | "authenticationExecutions" : [ { 916 | "authenticator" : "idp-confirm-link", 917 | "requirement" : "REQUIRED", 918 | "priority" : 10, 919 | "userSetupAllowed" : false, 920 | "autheticatorFlow" : false 921 | }, { 922 | "authenticator" : "idp-email-verification", 923 | "requirement" : "ALTERNATIVE", 924 | "priority" : 20, 925 | "userSetupAllowed" : false, 926 | "autheticatorFlow" : false 927 | }, { 928 | "requirement" : "ALTERNATIVE", 929 | "priority" : 30, 930 | "flowAlias" : "Verify Existing Account by Re-authentication", 931 | "userSetupAllowed" : false, 932 | "autheticatorFlow" : true 933 | } ] 934 | }, { 935 | "id" : "5237f9d3-c505-48d7-b2b5-4ba5845b7981", 936 | "alias" : "Verify Existing Account by Re-authentication", 937 | "description" : "Reauthentication of existing account", 938 | "providerId" : "basic-flow", 939 | "topLevel" : false, 940 | "builtIn" : true, 941 | "authenticationExecutions" : [ { 942 | "authenticator" : "idp-username-password-form", 943 | "requirement" : "REQUIRED", 944 | "priority" : 10, 945 | "userSetupAllowed" : false, 946 | "autheticatorFlow" : false 947 | }, { 948 | "authenticator" : "auth-otp-form", 949 | "requirement" : "OPTIONAL", 950 | "priority" : 20, 951 | "userSetupAllowed" : false, 952 | "autheticatorFlow" : false 953 | } ] 954 | }, { 955 | "id" : "9d1402bf-5dc2-4de2-9aed-d97c4ba0ef5e", 956 | "alias" : "browser", 957 | "description" : "browser based authentication", 958 | "providerId" : "basic-flow", 959 | "topLevel" : true, 960 | "builtIn" : true, 961 | "authenticationExecutions" : [ { 962 | "authenticator" : "auth-cookie", 963 | "requirement" : "ALTERNATIVE", 964 | "priority" : 10, 965 | "userSetupAllowed" : false, 966 | "autheticatorFlow" : false 967 | }, { 968 | "authenticator" : "auth-spnego", 969 | "requirement" : "DISABLED", 970 | "priority" : 20, 971 | "userSetupAllowed" : false, 972 | "autheticatorFlow" : false 973 | }, { 974 | "authenticator" : "identity-provider-redirector", 975 | "requirement" : "ALTERNATIVE", 976 | "priority" : 25, 977 | "userSetupAllowed" : false, 978 | "autheticatorFlow" : false 979 | }, { 980 | "requirement" : "ALTERNATIVE", 981 | "priority" : 30, 982 | "flowAlias" : "forms", 983 | "userSetupAllowed" : false, 984 | "autheticatorFlow" : true 985 | } ] 986 | }, { 987 | "id" : "b498dc60-21bb-471d-a757-1ac99aae0c20", 988 | "alias" : "clients", 989 | "description" : "Base authentication for clients", 990 | "providerId" : "client-flow", 991 | "topLevel" : true, 992 | "builtIn" : true, 993 | "authenticationExecutions" : [ { 994 | "authenticator" : "client-secret", 995 | "requirement" : "ALTERNATIVE", 996 | "priority" : 10, 997 | "userSetupAllowed" : false, 998 | "autheticatorFlow" : false 999 | }, { 1000 | "authenticator" : "client-jwt", 1001 | "requirement" : "ALTERNATIVE", 1002 | "priority" : 20, 1003 | "userSetupAllowed" : false, 1004 | "autheticatorFlow" : false 1005 | }, { 1006 | "authenticator" : "client-secret-jwt", 1007 | "requirement" : "ALTERNATIVE", 1008 | "priority" : 30, 1009 | "userSetupAllowed" : false, 1010 | "autheticatorFlow" : false 1011 | } ] 1012 | }, { 1013 | "id" : "cb77f85f-12b2-44d2-bf10-1c35a61b97b6", 1014 | "alias" : "direct grant", 1015 | "description" : "OpenID Connect Resource Owner Grant", 1016 | "providerId" : "basic-flow", 1017 | "topLevel" : true, 1018 | "builtIn" : true, 1019 | "authenticationExecutions" : [ { 1020 | "authenticator" : "direct-grant-validate-username", 1021 | "requirement" : "REQUIRED", 1022 | "priority" : 10, 1023 | "userSetupAllowed" : false, 1024 | "autheticatorFlow" : false 1025 | }, { 1026 | "authenticator" : "direct-grant-validate-password", 1027 | "requirement" : "REQUIRED", 1028 | "priority" : 20, 1029 | "userSetupAllowed" : false, 1030 | "autheticatorFlow" : false 1031 | }, { 1032 | "authenticator" : "direct-grant-validate-otp", 1033 | "requirement" : "OPTIONAL", 1034 | "priority" : 30, 1035 | "userSetupAllowed" : false, 1036 | "autheticatorFlow" : false 1037 | } ] 1038 | }, { 1039 | "id" : "316f698b-f622-415b-a2b5-a3eedc7e64a9", 1040 | "alias" : "docker auth", 1041 | "description" : "Used by Docker clients to authenticate against the IDP", 1042 | "providerId" : "basic-flow", 1043 | "topLevel" : true, 1044 | "builtIn" : true, 1045 | "authenticationExecutions" : [ { 1046 | "authenticator" : "docker-http-basic-authenticator", 1047 | "requirement" : "REQUIRED", 1048 | "priority" : 10, 1049 | "userSetupAllowed" : false, 1050 | "autheticatorFlow" : false 1051 | } ] 1052 | }, { 1053 | "id" : "d1201cb0-c1e6-4ffe-a9c9-62bbacb81841", 1054 | "alias" : "first broker login", 1055 | "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", 1056 | "providerId" : "basic-flow", 1057 | "topLevel" : true, 1058 | "builtIn" : true, 1059 | "authenticationExecutions" : [ { 1060 | "authenticatorConfig" : "review profile config", 1061 | "authenticator" : "idp-review-profile", 1062 | "requirement" : "REQUIRED", 1063 | "priority" : 10, 1064 | "userSetupAllowed" : false, 1065 | "autheticatorFlow" : false 1066 | }, { 1067 | "authenticatorConfig" : "create unique user config", 1068 | "authenticator" : "idp-create-user-if-unique", 1069 | "requirement" : "ALTERNATIVE", 1070 | "priority" : 20, 1071 | "userSetupAllowed" : false, 1072 | "autheticatorFlow" : false 1073 | }, { 1074 | "requirement" : "ALTERNATIVE", 1075 | "priority" : 30, 1076 | "flowAlias" : "Handle Existing Account", 1077 | "userSetupAllowed" : false, 1078 | "autheticatorFlow" : true 1079 | } ] 1080 | }, { 1081 | "id" : "90436c35-2dd0-4630-a7a8-c37ee59ccfef", 1082 | "alias" : "forms", 1083 | "description" : "Username, password, otp and other auth forms.", 1084 | "providerId" : "basic-flow", 1085 | "topLevel" : false, 1086 | "builtIn" : true, 1087 | "authenticationExecutions" : [ { 1088 | "authenticator" : "auth-username-password-form", 1089 | "requirement" : "REQUIRED", 1090 | "priority" : 10, 1091 | "userSetupAllowed" : false, 1092 | "autheticatorFlow" : false 1093 | }, { 1094 | "authenticator" : "auth-otp-form", 1095 | "requirement" : "OPTIONAL", 1096 | "priority" : 20, 1097 | "userSetupAllowed" : false, 1098 | "autheticatorFlow" : false 1099 | } ] 1100 | }, { 1101 | "id" : "09f41d31-78e1-413e-98d8-67a7b4d711c4", 1102 | "alias" : "registration", 1103 | "description" : "registration flow", 1104 | "providerId" : "basic-flow", 1105 | "topLevel" : true, 1106 | "builtIn" : true, 1107 | "authenticationExecutions" : [ { 1108 | "authenticator" : "registration-page-form", 1109 | "requirement" : "REQUIRED", 1110 | "priority" : 10, 1111 | "flowAlias" : "registration form", 1112 | "userSetupAllowed" : false, 1113 | "autheticatorFlow" : true 1114 | } ] 1115 | }, { 1116 | "id" : "9f4e77bc-8220-4d03-95f2-ab378213adee", 1117 | "alias" : "registration form", 1118 | "description" : "registration form", 1119 | "providerId" : "form-flow", 1120 | "topLevel" : false, 1121 | "builtIn" : true, 1122 | "authenticationExecutions" : [ { 1123 | "authenticator" : "registration-user-creation", 1124 | "requirement" : "REQUIRED", 1125 | "priority" : 20, 1126 | "userSetupAllowed" : false, 1127 | "autheticatorFlow" : false 1128 | }, { 1129 | "authenticator" : "registration-profile-action", 1130 | "requirement" : "REQUIRED", 1131 | "priority" : 40, 1132 | "userSetupAllowed" : false, 1133 | "autheticatorFlow" : false 1134 | }, { 1135 | "authenticator" : "registration-password-action", 1136 | "requirement" : "REQUIRED", 1137 | "priority" : 50, 1138 | "userSetupAllowed" : false, 1139 | "autheticatorFlow" : false 1140 | }, { 1141 | "authenticator" : "registration-recaptcha-action", 1142 | "requirement" : "DISABLED", 1143 | "priority" : 60, 1144 | "userSetupAllowed" : false, 1145 | "autheticatorFlow" : false 1146 | } ] 1147 | }, { 1148 | "id" : "ab6a2908-4541-4bf6-a665-9d169a3bfc15", 1149 | "alias" : "reset credentials", 1150 | "description" : "Reset credentials for a user if they forgot their password or something", 1151 | "providerId" : "basic-flow", 1152 | "topLevel" : true, 1153 | "builtIn" : true, 1154 | "authenticationExecutions" : [ { 1155 | "authenticator" : "reset-credentials-choose-user", 1156 | "requirement" : "REQUIRED", 1157 | "priority" : 10, 1158 | "userSetupAllowed" : false, 1159 | "autheticatorFlow" : false 1160 | }, { 1161 | "authenticator" : "reset-credential-email", 1162 | "requirement" : "REQUIRED", 1163 | "priority" : 20, 1164 | "userSetupAllowed" : false, 1165 | "autheticatorFlow" : false 1166 | }, { 1167 | "authenticator" : "reset-password", 1168 | "requirement" : "REQUIRED", 1169 | "priority" : 30, 1170 | "userSetupAllowed" : false, 1171 | "autheticatorFlow" : false 1172 | }, { 1173 | "authenticator" : "reset-otp", 1174 | "requirement" : "OPTIONAL", 1175 | "priority" : 40, 1176 | "userSetupAllowed" : false, 1177 | "autheticatorFlow" : false 1178 | } ] 1179 | }, { 1180 | "id" : "3d43bb68-5329-41e9-8844-98d41f36fdad", 1181 | "alias" : "saml ecp", 1182 | "description" : "SAML ECP Profile Authentication Flow", 1183 | "providerId" : "basic-flow", 1184 | "topLevel" : true, 1185 | "builtIn" : true, 1186 | "authenticationExecutions" : [ { 1187 | "authenticator" : "http-basic-authenticator", 1188 | "requirement" : "REQUIRED", 1189 | "priority" : 10, 1190 | "userSetupAllowed" : false, 1191 | "autheticatorFlow" : false 1192 | } ] 1193 | } ], 1194 | "authenticatorConfig" : [ { 1195 | "id" : "6089728e-fb33-4485-8452-a29020d52c41", 1196 | "alias" : "create unique user config", 1197 | "config" : { 1198 | "require.password.update.after.registration" : "false" 1199 | } 1200 | }, { 1201 | "id" : "918eabe4-8722-426b-b181-18b9e8592494", 1202 | "alias" : "review profile config", 1203 | "config" : { 1204 | "update.profile.on.first.login" : "missing" 1205 | } 1206 | } ], 1207 | "requiredActions" : [ { 1208 | "alias" : "CONFIGURE_TOTP", 1209 | "name" : "Configure OTP", 1210 | "providerId" : "CONFIGURE_TOTP", 1211 | "enabled" : true, 1212 | "defaultAction" : false, 1213 | "config" : { } 1214 | }, { 1215 | "alias" : "UPDATE_PASSWORD", 1216 | "name" : "Update Password", 1217 | "providerId" : "UPDATE_PASSWORD", 1218 | "enabled" : true, 1219 | "defaultAction" : false, 1220 | "config" : { } 1221 | }, { 1222 | "alias" : "UPDATE_PROFILE", 1223 | "name" : "Update Profile", 1224 | "providerId" : "UPDATE_PROFILE", 1225 | "enabled" : true, 1226 | "defaultAction" : false, 1227 | "config" : { } 1228 | }, { 1229 | "alias" : "VERIFY_EMAIL", 1230 | "name" : "Verify Email", 1231 | "providerId" : "VERIFY_EMAIL", 1232 | "enabled" : true, 1233 | "defaultAction" : false, 1234 | "config" : { } 1235 | }, { 1236 | "alias" : "terms_and_conditions", 1237 | "name" : "Terms and Conditions", 1238 | "providerId" : "terms_and_conditions", 1239 | "enabled" : false, 1240 | "defaultAction" : false, 1241 | "config" : { } 1242 | } ], 1243 | "browserFlow" : "browser", 1244 | "registrationFlow" : "registration", 1245 | "directGrantFlow" : "direct grant", 1246 | "resetCredentialsFlow" : "reset credentials", 1247 | "clientAuthenticationFlow" : "clients", 1248 | "dockerAuthenticationFlow" : "docker auth", 1249 | "attributes" : { 1250 | "_browser_header.xXSSProtection" : "1; mode=block", 1251 | "_browser_header.strictTransportSecurity" : "max-age=31536000; includeSubDomains", 1252 | "_browser_header.xFrameOptions" : "SAMEORIGIN", 1253 | "quickLoginCheckMilliSeconds" : "1000", 1254 | "permanentLockout" : "false", 1255 | "_browser_header.xRobotsTag" : "none", 1256 | "maxFailureWaitSeconds" : "900", 1257 | "minimumQuickLoginWaitSeconds" : "60", 1258 | "failureFactor" : "30", 1259 | "actionTokenGeneratedByUserLifespan" : "300", 1260 | "maxDeltaTimeSeconds" : "43200", 1261 | "_browser_header.xContentTypeOptions" : "nosniff", 1262 | "actionTokenGeneratedByAdminLifespan" : "43200", 1263 | "bruteForceProtected" : "false", 1264 | "_browser_header.contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", 1265 | "waitIncrementSeconds" : "60" 1266 | }, 1267 | "keycloakVersion" : "4.0.0.Final", 1268 | "userManagedAccessAllowed" : false 1269 | } -------------------------------------------------------------------------------- /keycloak_4_spring_boot_2/keycloak/config/PersonRealm-users-0.json: -------------------------------------------------------------------------------- 1 | { 2 | "realm" : "PersonRealm", 3 | "users" : [ { 4 | "id" : "bc68a03e-4c6e-47bc-8409-9b973e4b78e0", 5 | "createdTimestamp" : 1529012775558, 6 | "username" : "username", 7 | "enabled" : true, 8 | "totp" : false, 9 | "emailVerified" : false, 10 | "credentials" : [ { 11 | "type" : "password", 12 | "hashedSaltedValue" : "9DaXQqtjc+BXofTxzNy8I7kn9pX1Fgwa1z6hJzYBDHVL6TE8hLwNPg/rj9PoP6n4VSjA1xSlsxePmubEarXAdA==", 13 | "salt" : "LVYQP+OtLcJUC2Abc/nP6A==", 14 | "hashIterations" : 27500, 15 | "counter" : 0, 16 | "algorithm" : "pbkdf2-sha256", 17 | "digits" : 0, 18 | "period" : 0, 19 | "createdDate" : 1529012789604, 20 | "config" : { } 21 | } ], 22 | "disableableCredentialTypes" : [ "password" ], 23 | "requiredActions" : [], 24 | "realmRoles" : [ "uma_authorization", "offline_access", "user" ], 25 | "clientRoles" : { 26 | "account" : [ "view-profile", "manage-account" ] 27 | }, 28 | "notBefore" : 0, 29 | "groups" : [ ] 30 | } ] 31 | } -------------------------------------------------------------------------------- /keycloak_4_spring_boot_2/keycloak/config/master-realm.json: -------------------------------------------------------------------------------- 1 | { 2 | "id" : "master", 3 | "realm" : "master", 4 | "displayName" : "Keycloak", 5 | "displayNameHtml" : "
Keycloak
", 6 | "notBefore" : 0, 7 | "revokeRefreshToken" : false, 8 | "refreshTokenMaxReuse" : 0, 9 | "accessTokenLifespan" : 60, 10 | "accessTokenLifespanForImplicitFlow" : 900, 11 | "ssoSessionIdleTimeout" : 1800, 12 | "ssoSessionMaxLifespan" : 36000, 13 | "offlineSessionIdleTimeout" : 2592000, 14 | "accessCodeLifespan" : 60, 15 | "accessCodeLifespanUserAction" : 300, 16 | "accessCodeLifespanLogin" : 1800, 17 | "actionTokenGeneratedByAdminLifespan" : 43200, 18 | "actionTokenGeneratedByUserLifespan" : 300, 19 | "enabled" : true, 20 | "sslRequired" : "external", 21 | "registrationAllowed" : false, 22 | "registrationEmailAsUsername" : false, 23 | "rememberMe" : false, 24 | "verifyEmail" : false, 25 | "loginWithEmailAllowed" : true, 26 | "duplicateEmailsAllowed" : false, 27 | "resetPasswordAllowed" : false, 28 | "editUsernameAllowed" : false, 29 | "bruteForceProtected" : false, 30 | "permanentLockout" : false, 31 | "maxFailureWaitSeconds" : 900, 32 | "minimumQuickLoginWaitSeconds" : 60, 33 | "waitIncrementSeconds" : 60, 34 | "quickLoginCheckMilliSeconds" : 1000, 35 | "maxDeltaTimeSeconds" : 43200, 36 | "failureFactor" : 30, 37 | "roles" : { 38 | "realm" : [ { 39 | "id" : "f6df0ecb-6001-401b-aa1c-a66fc0435d5a", 40 | "name" : "admin", 41 | "description" : "${role_admin}", 42 | "composite" : true, 43 | "composites" : { 44 | "realm" : [ "create-realm" ], 45 | "client" : { 46 | "PersonRealm-realm" : [ "view-realm", "manage-realm", "view-events", "query-groups", "create-client", "query-clients", "query-realms", "manage-events", "view-authorization", "manage-authorization", "view-clients", "manage-clients", "manage-identity-providers", "view-users", "impersonation", "query-users", "manage-users", "view-identity-providers" ], 47 | "master-realm" : [ "manage-users", "view-events", "view-authorization", "query-groups", "view-clients", "view-users", "query-realms", "manage-events", "query-clients", "query-users", "impersonation", "manage-clients", "view-realm", "create-client", "manage-realm", "view-identity-providers", "manage-identity-providers", "manage-authorization" ] 48 | } 49 | }, 50 | "clientRole" : false, 51 | "containerId" : "master" 52 | }, { 53 | "id" : "30cceaad-d831-4739-8b8b-2fab441846e8", 54 | "name" : "create-realm", 55 | "description" : "${role_create-realm}", 56 | "composite" : false, 57 | "clientRole" : false, 58 | "containerId" : "master" 59 | }, { 60 | "id" : "7e9e45b6-5da0-420b-a3e9-f02c64ed0641", 61 | "name" : "offline_access", 62 | "description" : "${role_offline-access}", 63 | "composite" : false, 64 | "clientRole" : false, 65 | "containerId" : "master" 66 | }, { 67 | "id" : "75ba68c4-bd9a-41bf-83eb-c9fd92643482", 68 | "name" : "uma_authorization", 69 | "description" : "${role_uma_authorization}", 70 | "composite" : false, 71 | "clientRole" : false, 72 | "containerId" : "master" 73 | } ], 74 | "client" : { 75 | "PersonRealm-realm" : [ { 76 | "id" : "f7b4da1c-5d59-486f-8a0e-33158721417a", 77 | "name" : "view-authorization", 78 | "description" : "${role_view-authorization}", 79 | "composite" : false, 80 | "clientRole" : true, 81 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 82 | }, { 83 | "id" : "36e19d18-69bb-4a67-9edb-ffa8a1db1dbd", 84 | "name" : "manage-authorization", 85 | "description" : "${role_manage-authorization}", 86 | "composite" : false, 87 | "clientRole" : true, 88 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 89 | }, { 90 | "id" : "fc86107c-cad3-41ac-9500-ad3fc3515785", 91 | "name" : "view-realm", 92 | "description" : "${role_view-realm}", 93 | "composite" : false, 94 | "clientRole" : true, 95 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 96 | }, { 97 | "id" : "b4357313-17c7-47f2-bee9-d9c7aa2a813d", 98 | "name" : "view-clients", 99 | "description" : "${role_view-clients}", 100 | "composite" : true, 101 | "composites" : { 102 | "client" : { 103 | "PersonRealm-realm" : [ "query-clients" ] 104 | } 105 | }, 106 | "clientRole" : true, 107 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 108 | }, { 109 | "id" : "4fdc558e-17fd-4ae0-ac63-25505f75f3ea", 110 | "name" : "manage-clients", 111 | "description" : "${role_manage-clients}", 112 | "composite" : false, 113 | "clientRole" : true, 114 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 115 | }, { 116 | "id" : "684da6c6-42e7-4651-ac1a-d87be8e389b4", 117 | "name" : "manage-realm", 118 | "description" : "${role_manage-realm}", 119 | "composite" : false, 120 | "clientRole" : true, 121 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 122 | }, { 123 | "id" : "052e85c4-6c93-427b-adf3-175a97f2862d", 124 | "name" : "view-events", 125 | "description" : "${role_view-events}", 126 | "composite" : false, 127 | "clientRole" : true, 128 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 129 | }, { 130 | "id" : "6999fbeb-b6b5-41ae-982f-9fdf6ec3440b", 131 | "name" : "query-groups", 132 | "description" : "${role_query-groups}", 133 | "composite" : false, 134 | "clientRole" : true, 135 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 136 | }, { 137 | "id" : "2cf64307-03a7-4ec8-8a68-377c96941f14", 138 | "name" : "manage-identity-providers", 139 | "description" : "${role_manage-identity-providers}", 140 | "composite" : false, 141 | "clientRole" : true, 142 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 143 | }, { 144 | "id" : "fd3f2065-4aae-423e-81b1-841970230c9d", 145 | "name" : "create-client", 146 | "description" : "${role_create-client}", 147 | "composite" : false, 148 | "clientRole" : true, 149 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 150 | }, { 151 | "id" : "847bdf78-3339-4c87-a60c-2552bc670dc1", 152 | "name" : "query-clients", 153 | "description" : "${role_query-clients}", 154 | "composite" : false, 155 | "clientRole" : true, 156 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 157 | }, { 158 | "id" : "6cd127e2-5d73-4362-9185-5b6cc202ce96", 159 | "name" : "view-users", 160 | "description" : "${role_view-users}", 161 | "composite" : true, 162 | "composites" : { 163 | "client" : { 164 | "PersonRealm-realm" : [ "query-users", "query-groups" ] 165 | } 166 | }, 167 | "clientRole" : true, 168 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 169 | }, { 170 | "id" : "aa5300a5-951e-434a-ac34-bfc08ecca837", 171 | "name" : "query-realms", 172 | "description" : "${role_query-realms}", 173 | "composite" : false, 174 | "clientRole" : true, 175 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 176 | }, { 177 | "id" : "ea1602f8-747e-4fe3-8ec4-87ad09b7c618", 178 | "name" : "impersonation", 179 | "description" : "${role_impersonation}", 180 | "composite" : false, 181 | "clientRole" : true, 182 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 183 | }, { 184 | "id" : "b634a11d-7ec7-4140-b35b-ddf1da4e3d9f", 185 | "name" : "query-users", 186 | "description" : "${role_query-users}", 187 | "composite" : false, 188 | "clientRole" : true, 189 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 190 | }, { 191 | "id" : "37398f2d-aab8-41e9-9199-6e324030697c", 192 | "name" : "manage-users", 193 | "description" : "${role_manage-users}", 194 | "composite" : false, 195 | "clientRole" : true, 196 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 197 | }, { 198 | "id" : "f75f92c9-b52b-4f06-902d-b8feff6a13ee", 199 | "name" : "view-identity-providers", 200 | "description" : "${role_view-identity-providers}", 201 | "composite" : false, 202 | "clientRole" : true, 203 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 204 | }, { 205 | "id" : "adf091c2-e7df-4df2-8087-cb15aca2efc3", 206 | "name" : "manage-events", 207 | "description" : "${role_manage-events}", 208 | "composite" : false, 209 | "clientRole" : true, 210 | "containerId" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd" 211 | } ], 212 | "security-admin-console" : [ ], 213 | "admin-cli" : [ ], 214 | "broker" : [ { 215 | "id" : "b40d4af2-4d25-4a6f-bd9e-c41fba1a3d8e", 216 | "name" : "read-token", 217 | "description" : "${role_read-token}", 218 | "composite" : false, 219 | "clientRole" : true, 220 | "containerId" : "74eca6d3-3afd-4fee-9c02-983f175a39ec" 221 | } ], 222 | "master-realm" : [ { 223 | "id" : "0760ce96-4c27-4c7e-a37e-196ad11727e4", 224 | "name" : "manage-users", 225 | "description" : "${role_manage-users}", 226 | "composite" : false, 227 | "clientRole" : true, 228 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 229 | }, { 230 | "id" : "795f8d81-db01-4dd2-a012-bc844777bacb", 231 | "name" : "view-events", 232 | "description" : "${role_view-events}", 233 | "composite" : false, 234 | "clientRole" : true, 235 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 236 | }, { 237 | "id" : "9b1a0ea9-a0aa-4c2f-8067-7e52c4fe1620", 238 | "name" : "query-users", 239 | "description" : "${role_query-users}", 240 | "composite" : false, 241 | "clientRole" : true, 242 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 243 | }, { 244 | "id" : "fc845391-9d81-4849-be6a-71b4412f54d2", 245 | "name" : "impersonation", 246 | "description" : "${role_impersonation}", 247 | "composite" : false, 248 | "clientRole" : true, 249 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 250 | }, { 251 | "id" : "6fe49e43-38b8-498f-878a-0ff098f454b2", 252 | "name" : "manage-clients", 253 | "description" : "${role_manage-clients}", 254 | "composite" : false, 255 | "clientRole" : true, 256 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 257 | }, { 258 | "id" : "a6cbc3ea-821f-42ff-9213-c3278a2179db", 259 | "name" : "view-realm", 260 | "description" : "${role_view-realm}", 261 | "composite" : false, 262 | "clientRole" : true, 263 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 264 | }, { 265 | "id" : "3b33157c-41f5-48ca-8500-72c4f633474e", 266 | "name" : "view-authorization", 267 | "description" : "${role_view-authorization}", 268 | "composite" : false, 269 | "clientRole" : true, 270 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 271 | }, { 272 | "id" : "bd1940bf-391c-4939-ae1e-d62fa506f672", 273 | "name" : "create-client", 274 | "description" : "${role_create-client}", 275 | "composite" : false, 276 | "clientRole" : true, 277 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 278 | }, { 279 | "id" : "8162e52a-b3e2-4e41-bcfd-739398f7754d", 280 | "name" : "query-groups", 281 | "description" : "${role_query-groups}", 282 | "composite" : false, 283 | "clientRole" : true, 284 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 285 | }, { 286 | "id" : "fac80180-677f-4b73-9e74-d79c1958d095", 287 | "name" : "view-clients", 288 | "description" : "${role_view-clients}", 289 | "composite" : true, 290 | "composites" : { 291 | "client" : { 292 | "master-realm" : [ "query-clients" ] 293 | } 294 | }, 295 | "clientRole" : true, 296 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 297 | }, { 298 | "id" : "d30bc182-6715-47f9-93a7-eeadba874ba7", 299 | "name" : "view-users", 300 | "description" : "${role_view-users}", 301 | "composite" : true, 302 | "composites" : { 303 | "client" : { 304 | "master-realm" : [ "query-users", "query-groups" ] 305 | } 306 | }, 307 | "clientRole" : true, 308 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 309 | }, { 310 | "id" : "89b023be-03a4-4e79-97cb-7d69075926b4", 311 | "name" : "manage-realm", 312 | "description" : "${role_manage-realm}", 313 | "composite" : false, 314 | "clientRole" : true, 315 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 316 | }, { 317 | "id" : "7fd982e4-86b4-4e2f-92ac-556a4ea4b63d", 318 | "name" : "view-identity-providers", 319 | "description" : "${role_view-identity-providers}", 320 | "composite" : false, 321 | "clientRole" : true, 322 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 323 | }, { 324 | "id" : "bf027ad1-3f87-4c4f-a756-78c0cf090176", 325 | "name" : "query-realms", 326 | "description" : "${role_query-realms}", 327 | "composite" : false, 328 | "clientRole" : true, 329 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 330 | }, { 331 | "id" : "218249c2-b4b8-4543-99c9-622dda61230f", 332 | "name" : "manage-events", 333 | "description" : "${role_manage-events}", 334 | "composite" : false, 335 | "clientRole" : true, 336 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 337 | }, { 338 | "id" : "3f34d131-fa3e-45e7-8cd8-b49688f3fe6b", 339 | "name" : "query-clients", 340 | "description" : "${role_query-clients}", 341 | "composite" : false, 342 | "clientRole" : true, 343 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 344 | }, { 345 | "id" : "f3771c0a-5438-4358-9199-0cc451c99b33", 346 | "name" : "manage-identity-providers", 347 | "description" : "${role_manage-identity-providers}", 348 | "composite" : false, 349 | "clientRole" : true, 350 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 351 | }, { 352 | "id" : "e96b23ab-1496-4dc3-bf32-e120d7063ab8", 353 | "name" : "manage-authorization", 354 | "description" : "${role_manage-authorization}", 355 | "composite" : false, 356 | "clientRole" : true, 357 | "containerId" : "4b4b0523-297d-4f01-b13e-0322e6f07692" 358 | } ], 359 | "account" : [ { 360 | "id" : "3fd5901a-47de-494a-a84e-b7bac78155a9", 361 | "name" : "manage-account-links", 362 | "description" : "${role_manage-account-links}", 363 | "composite" : false, 364 | "clientRole" : true, 365 | "containerId" : "f216945d-7af3-4695-8daf-eb042a8c626b" 366 | }, { 367 | "id" : "eaa552ac-4ba6-48f8-913c-c20a07feaf0f", 368 | "name" : "view-profile", 369 | "description" : "${role_view-profile}", 370 | "composite" : false, 371 | "clientRole" : true, 372 | "containerId" : "f216945d-7af3-4695-8daf-eb042a8c626b" 373 | }, { 374 | "id" : "7021dfe7-b545-4352-9183-8642e05a1199", 375 | "name" : "manage-account", 376 | "description" : "${role_manage-account}", 377 | "composite" : true, 378 | "composites" : { 379 | "client" : { 380 | "account" : [ "manage-account-links" ] 381 | } 382 | }, 383 | "clientRole" : true, 384 | "containerId" : "f216945d-7af3-4695-8daf-eb042a8c626b" 385 | } ] 386 | } 387 | }, 388 | "groups" : [ ], 389 | "defaultRoles" : [ "offline_access", "uma_authorization" ], 390 | "requiredCredentials" : [ "password" ], 391 | "otpPolicyType" : "totp", 392 | "otpPolicyAlgorithm" : "HmacSHA1", 393 | "otpPolicyInitialCounter" : 0, 394 | "otpPolicyDigits" : 6, 395 | "otpPolicyLookAheadWindow" : 1, 396 | "otpPolicyPeriod" : 30, 397 | "otpSupportedApplications" : [ "FreeOTP", "Google Authenticator" ], 398 | "scopeMappings" : [ { 399 | "clientScope" : "offline_access", 400 | "roles" : [ "offline_access" ] 401 | } ], 402 | "clients" : [ { 403 | "id" : "f216945d-7af3-4695-8daf-eb042a8c626b", 404 | "clientId" : "account", 405 | "name" : "${client_account}", 406 | "baseUrl" : "/auth/realms/master/account", 407 | "surrogateAuthRequired" : false, 408 | "enabled" : true, 409 | "clientAuthenticatorType" : "client-secret", 410 | "secret" : "ade754c4-c4c0-4be1-9923-f7a2efbcc1bc", 411 | "defaultRoles" : [ "view-profile", "manage-account" ], 412 | "redirectUris" : [ "/auth/realms/master/account/*" ], 413 | "webOrigins" : [ ], 414 | "notBefore" : 0, 415 | "bearerOnly" : false, 416 | "consentRequired" : false, 417 | "standardFlowEnabled" : true, 418 | "implicitFlowEnabled" : false, 419 | "directAccessGrantsEnabled" : false, 420 | "serviceAccountsEnabled" : false, 421 | "publicClient" : false, 422 | "frontchannelLogout" : false, 423 | "protocol" : "openid-connect", 424 | "attributes" : { }, 425 | "authenticationFlowBindingOverrides" : { }, 426 | "fullScopeAllowed" : false, 427 | "nodeReRegistrationTimeout" : 0, 428 | "defaultClientScopes" : [ "role_list", "profile", "email" ], 429 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 430 | }, { 431 | "id" : "e15b4b6d-db59-4b76-8255-e7badba48bdb", 432 | "clientId" : "admin-cli", 433 | "name" : "${client_admin-cli}", 434 | "surrogateAuthRequired" : false, 435 | "enabled" : true, 436 | "clientAuthenticatorType" : "client-secret", 437 | "secret" : "45c9742c-fb8b-410e-bef4-670988a12e4b", 438 | "redirectUris" : [ ], 439 | "webOrigins" : [ ], 440 | "notBefore" : 0, 441 | "bearerOnly" : false, 442 | "consentRequired" : false, 443 | "standardFlowEnabled" : false, 444 | "implicitFlowEnabled" : false, 445 | "directAccessGrantsEnabled" : true, 446 | "serviceAccountsEnabled" : false, 447 | "publicClient" : true, 448 | "frontchannelLogout" : false, 449 | "protocol" : "openid-connect", 450 | "attributes" : { }, 451 | "authenticationFlowBindingOverrides" : { }, 452 | "fullScopeAllowed" : false, 453 | "nodeReRegistrationTimeout" : 0, 454 | "defaultClientScopes" : [ "role_list", "profile", "email" ], 455 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 456 | }, { 457 | "id" : "74eca6d3-3afd-4fee-9c02-983f175a39ec", 458 | "clientId" : "broker", 459 | "name" : "${client_broker}", 460 | "surrogateAuthRequired" : false, 461 | "enabled" : true, 462 | "clientAuthenticatorType" : "client-secret", 463 | "secret" : "211eea52-5cda-4f1f-8519-7e6119697056", 464 | "redirectUris" : [ ], 465 | "webOrigins" : [ ], 466 | "notBefore" : 0, 467 | "bearerOnly" : false, 468 | "consentRequired" : false, 469 | "standardFlowEnabled" : true, 470 | "implicitFlowEnabled" : false, 471 | "directAccessGrantsEnabled" : false, 472 | "serviceAccountsEnabled" : false, 473 | "publicClient" : false, 474 | "frontchannelLogout" : false, 475 | "protocol" : "openid-connect", 476 | "attributes" : { }, 477 | "authenticationFlowBindingOverrides" : { }, 478 | "fullScopeAllowed" : false, 479 | "nodeReRegistrationTimeout" : 0, 480 | "defaultClientScopes" : [ "role_list", "profile", "email" ], 481 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 482 | }, { 483 | "id" : "4b4b0523-297d-4f01-b13e-0322e6f07692", 484 | "clientId" : "master-realm", 485 | "name" : "master Realm", 486 | "surrogateAuthRequired" : false, 487 | "enabled" : true, 488 | "clientAuthenticatorType" : "client-secret", 489 | "secret" : "f0d5009f-ffe9-439a-868c-b1df94175294", 490 | "redirectUris" : [ ], 491 | "webOrigins" : [ ], 492 | "notBefore" : 0, 493 | "bearerOnly" : true, 494 | "consentRequired" : false, 495 | "standardFlowEnabled" : true, 496 | "implicitFlowEnabled" : false, 497 | "directAccessGrantsEnabled" : false, 498 | "serviceAccountsEnabled" : false, 499 | "publicClient" : false, 500 | "frontchannelLogout" : false, 501 | "attributes" : { }, 502 | "authenticationFlowBindingOverrides" : { }, 503 | "fullScopeAllowed" : true, 504 | "nodeReRegistrationTimeout" : 0, 505 | "defaultClientScopes" : [ "role_list", "profile", "email" ], 506 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 507 | }, { 508 | "id" : "7b932c60-7f2e-4537-91f8-8b64bd4a07cd", 509 | "clientId" : "PersonRealm-realm", 510 | "name" : "PersonRealm Realm", 511 | "surrogateAuthRequired" : false, 512 | "enabled" : true, 513 | "clientAuthenticatorType" : "client-secret", 514 | "secret" : "1ede8419-4dbe-4c0c-9891-0db584e49dec", 515 | "redirectUris" : [ ], 516 | "webOrigins" : [ ], 517 | "notBefore" : 0, 518 | "bearerOnly" : true, 519 | "consentRequired" : false, 520 | "standardFlowEnabled" : true, 521 | "implicitFlowEnabled" : false, 522 | "directAccessGrantsEnabled" : false, 523 | "serviceAccountsEnabled" : false, 524 | "publicClient" : false, 525 | "frontchannelLogout" : false, 526 | "attributes" : { }, 527 | "authenticationFlowBindingOverrides" : { }, 528 | "fullScopeAllowed" : true, 529 | "nodeReRegistrationTimeout" : 0, 530 | "defaultClientScopes" : [ "role_list", "profile", "email" ], 531 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 532 | }, { 533 | "id" : "c8b8170c-a8a7-44a5-b125-ab1b4995c1db", 534 | "clientId" : "security-admin-console", 535 | "name" : "${client_security-admin-console}", 536 | "baseUrl" : "/auth/admin/master/console/index.html", 537 | "surrogateAuthRequired" : false, 538 | "enabled" : true, 539 | "clientAuthenticatorType" : "client-secret", 540 | "secret" : "05dabda0-c95c-4d30-952f-ca58c6688fc6", 541 | "redirectUris" : [ "/auth/admin/master/console/*" ], 542 | "webOrigins" : [ ], 543 | "notBefore" : 0, 544 | "bearerOnly" : false, 545 | "consentRequired" : false, 546 | "standardFlowEnabled" : true, 547 | "implicitFlowEnabled" : false, 548 | "directAccessGrantsEnabled" : false, 549 | "serviceAccountsEnabled" : false, 550 | "publicClient" : true, 551 | "frontchannelLogout" : false, 552 | "protocol" : "openid-connect", 553 | "attributes" : { }, 554 | "authenticationFlowBindingOverrides" : { }, 555 | "fullScopeAllowed" : false, 556 | "nodeReRegistrationTimeout" : 0, 557 | "protocolMappers" : [ { 558 | "id" : "4734497d-9ae0-4c93-9394-7f994a9c5632", 559 | "name" : "locale", 560 | "protocol" : "openid-connect", 561 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 562 | "consentRequired" : false, 563 | "config" : { 564 | "userinfo.token.claim" : "true", 565 | "user.attribute" : "locale", 566 | "id.token.claim" : "true", 567 | "access.token.claim" : "true", 568 | "claim.name" : "locale", 569 | "jsonType.label" : "String" 570 | } 571 | } ], 572 | "defaultClientScopes" : [ "role_list", "profile", "email" ], 573 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 574 | } ], 575 | "clientScopes" : [ { 576 | "id" : "7c617354-b8ad-4863-b6b2-8f3028a2a977", 577 | "name" : "phone", 578 | "description" : "OpenID Connect built-in scope: phone", 579 | "protocol" : "openid-connect", 580 | "attributes" : { 581 | "consent.screen.text" : "${phoneScopeConsentText}", 582 | "display.on.consent.screen" : "true" 583 | }, 584 | "protocolMappers" : [ { 585 | "id" : "46fee28a-291c-449a-be68-001a57a443e2", 586 | "name" : "phone number verified", 587 | "protocol" : "openid-connect", 588 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 589 | "consentRequired" : false, 590 | "config" : { 591 | "userinfo.token.claim" : "true", 592 | "user.attribute" : "phoneNumberVerified", 593 | "id.token.claim" : "true", 594 | "access.token.claim" : "true", 595 | "claim.name" : "phone_number_verified", 596 | "jsonType.label" : "boolean" 597 | } 598 | }, { 599 | "id" : "09aead2d-71c1-4eed-9f10-66fa9121b34f", 600 | "name" : "phone number", 601 | "protocol" : "openid-connect", 602 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 603 | "consentRequired" : false, 604 | "config" : { 605 | "userinfo.token.claim" : "true", 606 | "user.attribute" : "phoneNumber", 607 | "id.token.claim" : "true", 608 | "access.token.claim" : "true", 609 | "claim.name" : "phone_number", 610 | "jsonType.label" : "String" 611 | } 612 | } ] 613 | }, { 614 | "id" : "956a3712-5658-4278-bf8b-7b70a8de093c", 615 | "name" : "address", 616 | "description" : "OpenID Connect built-in scope: address", 617 | "protocol" : "openid-connect", 618 | "attributes" : { 619 | "consent.screen.text" : "${addressScopeConsentText}", 620 | "display.on.consent.screen" : "true" 621 | }, 622 | "protocolMappers" : [ { 623 | "id" : "d696a932-e960-4d77-a98a-9b9329a6e473", 624 | "name" : "address", 625 | "protocol" : "openid-connect", 626 | "protocolMapper" : "oidc-address-mapper", 627 | "consentRequired" : false, 628 | "config" : { 629 | "user.attribute.formatted" : "formatted", 630 | "user.attribute.country" : "country", 631 | "user.attribute.postal_code" : "postal_code", 632 | "userinfo.token.claim" : "true", 633 | "user.attribute.street" : "street", 634 | "id.token.claim" : "true", 635 | "user.attribute.region" : "region", 636 | "access.token.claim" : "true", 637 | "user.attribute.locality" : "locality" 638 | } 639 | } ] 640 | }, { 641 | "id" : "47db2c12-c9f2-4347-b177-7fd2f7ec20cb", 642 | "name" : "email", 643 | "description" : "OpenID Connect built-in scope: email", 644 | "protocol" : "openid-connect", 645 | "attributes" : { 646 | "consent.screen.text" : "${emailScopeConsentText}", 647 | "display.on.consent.screen" : "true" 648 | }, 649 | "protocolMappers" : [ { 650 | "id" : "da6ffb3c-7191-46c4-a1e2-85b8dc36e98d", 651 | "name" : "email", 652 | "protocol" : "openid-connect", 653 | "protocolMapper" : "oidc-usermodel-property-mapper", 654 | "consentRequired" : false, 655 | "config" : { 656 | "userinfo.token.claim" : "true", 657 | "user.attribute" : "email", 658 | "id.token.claim" : "true", 659 | "access.token.claim" : "true", 660 | "claim.name" : "email", 661 | "jsonType.label" : "String" 662 | } 663 | }, { 664 | "id" : "705385e0-69a4-4278-83c5-8e2892ebb143", 665 | "name" : "email verified", 666 | "protocol" : "openid-connect", 667 | "protocolMapper" : "oidc-usermodel-property-mapper", 668 | "consentRequired" : false, 669 | "config" : { 670 | "userinfo.token.claim" : "true", 671 | "user.attribute" : "emailVerified", 672 | "id.token.claim" : "true", 673 | "access.token.claim" : "true", 674 | "claim.name" : "email_verified", 675 | "jsonType.label" : "boolean" 676 | } 677 | } ] 678 | }, { 679 | "id" : "e3eee2ef-7bdc-4823-af4a-4ddc220cff61", 680 | "name" : "profile", 681 | "description" : "OpenID Connect built-in scope: profile", 682 | "protocol" : "openid-connect", 683 | "attributes" : { 684 | "consent.screen.text" : "${profileScopeConsentText}", 685 | "display.on.consent.screen" : "true" 686 | }, 687 | "protocolMappers" : [ { 688 | "id" : "33dae257-bcc1-419f-b5a2-db2a2068b70d", 689 | "name" : "nickname", 690 | "protocol" : "openid-connect", 691 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 692 | "consentRequired" : false, 693 | "config" : { 694 | "userinfo.token.claim" : "true", 695 | "user.attribute" : "nickname", 696 | "id.token.claim" : "true", 697 | "access.token.claim" : "true", 698 | "claim.name" : "nickname", 699 | "jsonType.label" : "String" 700 | } 701 | }, { 702 | "id" : "8105d39d-a87c-45a7-8833-a3c45bc6f45d", 703 | "name" : "full name", 704 | "protocol" : "openid-connect", 705 | "protocolMapper" : "oidc-full-name-mapper", 706 | "consentRequired" : false, 707 | "config" : { 708 | "id.token.claim" : "true", 709 | "access.token.claim" : "true", 710 | "userinfo.token.claim" : "true" 711 | } 712 | }, { 713 | "id" : "dd726b9a-6f57-43e2-8464-c41d820f3858", 714 | "name" : "family name", 715 | "protocol" : "openid-connect", 716 | "protocolMapper" : "oidc-usermodel-property-mapper", 717 | "consentRequired" : false, 718 | "config" : { 719 | "userinfo.token.claim" : "true", 720 | "user.attribute" : "lastName", 721 | "id.token.claim" : "true", 722 | "access.token.claim" : "true", 723 | "claim.name" : "family_name", 724 | "jsonType.label" : "String" 725 | } 726 | }, { 727 | "id" : "253c4da1-f113-40e2-9984-23638f2ed786", 728 | "name" : "picture", 729 | "protocol" : "openid-connect", 730 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 731 | "consentRequired" : false, 732 | "config" : { 733 | "userinfo.token.claim" : "true", 734 | "user.attribute" : "picture", 735 | "id.token.claim" : "true", 736 | "access.token.claim" : "true", 737 | "claim.name" : "picture", 738 | "jsonType.label" : "String" 739 | } 740 | }, { 741 | "id" : "82fcbd47-c87e-46d5-ac1f-a52ea5bff22d", 742 | "name" : "website", 743 | "protocol" : "openid-connect", 744 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 745 | "consentRequired" : false, 746 | "config" : { 747 | "userinfo.token.claim" : "true", 748 | "user.attribute" : "website", 749 | "id.token.claim" : "true", 750 | "access.token.claim" : "true", 751 | "claim.name" : "website", 752 | "jsonType.label" : "String" 753 | } 754 | }, { 755 | "id" : "1e5e9e68-f04b-4480-9bc8-44202424d5c7", 756 | "name" : "updated at", 757 | "protocol" : "openid-connect", 758 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 759 | "consentRequired" : false, 760 | "config" : { 761 | "userinfo.token.claim" : "true", 762 | "user.attribute" : "updatedAt", 763 | "id.token.claim" : "true", 764 | "access.token.claim" : "true", 765 | "claim.name" : "updated_at", 766 | "jsonType.label" : "String" 767 | } 768 | }, { 769 | "id" : "4a7da284-5d52-41c7-96e5-fa2dcf02f09d", 770 | "name" : "locale", 771 | "protocol" : "openid-connect", 772 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 773 | "consentRequired" : false, 774 | "config" : { 775 | "userinfo.token.claim" : "true", 776 | "user.attribute" : "locale", 777 | "id.token.claim" : "true", 778 | "access.token.claim" : "true", 779 | "claim.name" : "locale", 780 | "jsonType.label" : "String" 781 | } 782 | }, { 783 | "id" : "da98c273-8d11-4c6f-b249-321f8e724dbf", 784 | "name" : "given name", 785 | "protocol" : "openid-connect", 786 | "protocolMapper" : "oidc-usermodel-property-mapper", 787 | "consentRequired" : false, 788 | "config" : { 789 | "userinfo.token.claim" : "true", 790 | "user.attribute" : "firstName", 791 | "id.token.claim" : "true", 792 | "access.token.claim" : "true", 793 | "claim.name" : "given_name", 794 | "jsonType.label" : "String" 795 | } 796 | }, { 797 | "id" : "652c8229-fc70-4595-8be3-4ca7f9e289d3", 798 | "name" : "username", 799 | "protocol" : "openid-connect", 800 | "protocolMapper" : "oidc-usermodel-property-mapper", 801 | "consentRequired" : false, 802 | "config" : { 803 | "userinfo.token.claim" : "true", 804 | "user.attribute" : "username", 805 | "id.token.claim" : "true", 806 | "access.token.claim" : "true", 807 | "claim.name" : "preferred_username", 808 | "jsonType.label" : "String" 809 | } 810 | }, { 811 | "id" : "b2f773d3-d58e-4078-96e3-75b8171fb431", 812 | "name" : "middle name", 813 | "protocol" : "openid-connect", 814 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 815 | "consentRequired" : false, 816 | "config" : { 817 | "userinfo.token.claim" : "true", 818 | "user.attribute" : "middleName", 819 | "id.token.claim" : "true", 820 | "access.token.claim" : "true", 821 | "claim.name" : "middle_name", 822 | "jsonType.label" : "String" 823 | } 824 | }, { 825 | "id" : "9292c0fe-6640-4d44-8c28-ccf99442f83a", 826 | "name" : "zoneinfo", 827 | "protocol" : "openid-connect", 828 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 829 | "consentRequired" : false, 830 | "config" : { 831 | "userinfo.token.claim" : "true", 832 | "user.attribute" : "zoneinfo", 833 | "id.token.claim" : "true", 834 | "access.token.claim" : "true", 835 | "claim.name" : "zoneinfo", 836 | "jsonType.label" : "String" 837 | } 838 | }, { 839 | "id" : "301fab17-c053-4fd3-8eac-93dd69869b22", 840 | "name" : "gender", 841 | "protocol" : "openid-connect", 842 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 843 | "consentRequired" : false, 844 | "config" : { 845 | "userinfo.token.claim" : "true", 846 | "user.attribute" : "gender", 847 | "id.token.claim" : "true", 848 | "access.token.claim" : "true", 849 | "claim.name" : "gender", 850 | "jsonType.label" : "String" 851 | } 852 | }, { 853 | "id" : "8e1a1961-a4a6-49f0-a2c1-3eaeff83b530", 854 | "name" : "profile", 855 | "protocol" : "openid-connect", 856 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 857 | "consentRequired" : false, 858 | "config" : { 859 | "userinfo.token.claim" : "true", 860 | "user.attribute" : "profile", 861 | "id.token.claim" : "true", 862 | "access.token.claim" : "true", 863 | "claim.name" : "profile", 864 | "jsonType.label" : "String" 865 | } 866 | }, { 867 | "id" : "27516982-fcb1-4f0a-bfbb-f3c293ab14b8", 868 | "name" : "birthdate", 869 | "protocol" : "openid-connect", 870 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 871 | "consentRequired" : false, 872 | "config" : { 873 | "userinfo.token.claim" : "true", 874 | "user.attribute" : "birthdate", 875 | "id.token.claim" : "true", 876 | "access.token.claim" : "true", 877 | "claim.name" : "birthdate", 878 | "jsonType.label" : "String" 879 | } 880 | } ] 881 | }, { 882 | "id" : "22cd0a2f-1079-49a1-93ad-e8d67e823cbe", 883 | "name" : "role_list", 884 | "description" : "SAML role list", 885 | "protocol" : "saml", 886 | "attributes" : { 887 | "consent.screen.text" : "${samlRoleListScopeConsentText}", 888 | "display.on.consent.screen" : "true" 889 | }, 890 | "protocolMappers" : [ { 891 | "id" : "49c318ba-9199-4a18-82b4-322863a6b93c", 892 | "name" : "role list", 893 | "protocol" : "saml", 894 | "protocolMapper" : "saml-role-list-mapper", 895 | "consentRequired" : false, 896 | "config" : { 897 | "single" : "false", 898 | "attribute.nameformat" : "Basic", 899 | "attribute.name" : "Role" 900 | } 901 | } ] 902 | }, { 903 | "id" : "041ae8c3-6d65-4215-b48e-f7b97bf5ce89", 904 | "name" : "offline_access", 905 | "description" : "OpenID Connect built-in scope: offline_access", 906 | "protocol" : "openid-connect", 907 | "attributes" : { 908 | "consent.screen.text" : "${offlineAccessScopeConsentText}", 909 | "display.on.consent.screen" : "true" 910 | } 911 | } ], 912 | "defaultDefaultClientScopes" : [ "role_list", "profile", "email" ], 913 | "defaultOptionalClientScopes" : [ "offline_access", "address", "phone" ], 914 | "browserSecurityHeaders" : { 915 | "xContentTypeOptions" : "nosniff", 916 | "xRobotsTag" : "none", 917 | "xFrameOptions" : "SAMEORIGIN", 918 | "xXSSProtection" : "1; mode=block", 919 | "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", 920 | "strictTransportSecurity" : "max-age=31536000; includeSubDomains" 921 | }, 922 | "smtpServer" : { }, 923 | "eventsEnabled" : false, 924 | "eventsListeners" : [ "jboss-logging" ], 925 | "enabledEventTypes" : [ ], 926 | "adminEventsEnabled" : false, 927 | "adminEventsDetailsEnabled" : false, 928 | "components" : { 929 | "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { 930 | "id" : "ac1053b0-0d47-45c8-b686-58edee9569ac", 931 | "name" : "Allowed Client Scopes", 932 | "providerId" : "allowed-client-templates", 933 | "subType" : "authenticated", 934 | "subComponents" : { }, 935 | "config" : { 936 | "allow-default-scopes" : [ "true" ] 937 | } 938 | }, { 939 | "id" : "1f3078a7-5253-4486-9e0b-75c4fbe48212", 940 | "name" : "Max Clients Limit", 941 | "providerId" : "max-clients", 942 | "subType" : "anonymous", 943 | "subComponents" : { }, 944 | "config" : { 945 | "max-clients" : [ "200" ] 946 | } 947 | }, { 948 | "id" : "9dfccd04-e04c-45e8-b0e5-e6d50dc74716", 949 | "name" : "Allowed Client Scopes", 950 | "providerId" : "allowed-client-templates", 951 | "subType" : "anonymous", 952 | "subComponents" : { }, 953 | "config" : { 954 | "allow-default-scopes" : [ "true" ] 955 | } 956 | }, { 957 | "id" : "c3b67cef-318b-4fbb-a506-2931dc2b9748", 958 | "name" : "Allowed Protocol Mapper Types", 959 | "providerId" : "allowed-protocol-mappers", 960 | "subType" : "anonymous", 961 | "subComponents" : { }, 962 | "config" : { 963 | "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-user-property-mapper", "oidc-address-mapper", "oidc-usermodel-attribute-mapper", "saml-role-list-mapper", "saml-user-attribute-mapper" ] 964 | } 965 | }, { 966 | "id" : "7578bcbb-657d-44dc-87a0-24100684eb63", 967 | "name" : "Full Scope Disabled", 968 | "providerId" : "scope", 969 | "subType" : "anonymous", 970 | "subComponents" : { }, 971 | "config" : { } 972 | }, { 973 | "id" : "e95afe7b-b56d-458c-9226-f276145086d4", 974 | "name" : "Allowed Protocol Mapper Types", 975 | "providerId" : "allowed-protocol-mappers", 976 | "subType" : "authenticated", 977 | "subComponents" : { }, 978 | "config" : { 979 | "allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-full-name-mapper", "oidc-address-mapper" ] 980 | } 981 | }, { 982 | "id" : "013d1eea-dd7d-4b0d-8567-062d816b73f8", 983 | "name" : "Consent Required", 984 | "providerId" : "consent-required", 985 | "subType" : "anonymous", 986 | "subComponents" : { }, 987 | "config" : { } 988 | }, { 989 | "id" : "35807724-673b-4322-8bfd-4f18ff9f34b0", 990 | "name" : "Trusted Hosts", 991 | "providerId" : "trusted-hosts", 992 | "subType" : "anonymous", 993 | "subComponents" : { }, 994 | "config" : { 995 | "host-sending-registration-request-must-match" : [ "true" ], 996 | "client-uris-must-match" : [ "true" ] 997 | } 998 | } ], 999 | "org.keycloak.keys.KeyProvider" : [ { 1000 | "id" : "ae30e5ec-9564-464f-8199-c029bb93bbaa", 1001 | "name" : "hmac-generated", 1002 | "providerId" : "hmac-generated", 1003 | "subComponents" : { }, 1004 | "config" : { 1005 | "kid" : [ "1e8fddac-27a7-4922-9146-be334a5a7176" ], 1006 | "secret" : [ "HubGcrE0NT4wY2pMl91-yHbqcjjoipKgyli6aNXWlFE" ], 1007 | "priority" : [ "100" ] 1008 | } 1009 | }, { 1010 | "id" : "e65e8ce5-79c6-4c01-9955-77fe5337caca", 1011 | "name" : "aes-generated", 1012 | "providerId" : "aes-generated", 1013 | "subComponents" : { }, 1014 | "config" : { 1015 | "kid" : [ "e0f9c277-999e-45a1-8abd-c7b4136f9f09" ], 1016 | "secret" : [ "bXck72kOkcgWN-1YW1L65Q" ], 1017 | "priority" : [ "100" ] 1018 | } 1019 | }, { 1020 | "id" : "5afaa16f-eb46-473b-916b-2084a32d5c97", 1021 | "name" : "rsa-generated", 1022 | "providerId" : "rsa-generated", 1023 | "subComponents" : { }, 1024 | "config" : { 1025 | "privateKey" : [ "MIIEowIBAAKCAQEAnEnAYX+w56CXEyyeH4JgDwuSjWt5bw7phxOczutaQ22ZDYZNwxyl6GaEG8uGw4FS3dGPkeGUpW3ukZV8GJhxs2eJPnvmDBqC2CLQYr2DtGjYPPrxd1eZ/6nOX4xlOJZaociLTJfKCNXTmpynyHMGsmVVy5QQiaeSa7e3+etfsD9igfsJPx6E1647LSJaIaDVHT0GuL9Hl9JMeQOIEh7wxswxfYHI2Qi5/fyAzpQqeZkC0bkrkLdFamZVhcqrtU8x/nN5XlnkQHe/ow/9O9NQLuzn7kPWkUuFl0w+axygQnHgA8di6uBsU94b6xuVik88xB3vSFV+USnDTKVkUg9nVQIDAQABAoIBAG8m/M3a1ORHkGqwptzeCpdosZgmwby8rFXHGxUGybF+9wVpaVDExTIeBwMFoxjUlyzvZ95mwyNMpgmgeRu8/9CKaE+qKpidGkXBrNcs1civcGseRjGMehgcmovV+/9c36SETp3wrl3ORaqGk8W6GR8zdutMqN5d8YLurMfwIKPlsVZK0RVrTB80fYECw8U9vBjD73Cacou+5kQAy9IcF1gn+SoomGQURFi2oVkCQlPDL1iDQvkI/hQSFUHBPAtTPQ2t4IZR+yLfu3ADmxbq8XH1mvdeiOXQccOeqYe5ZRKi+hX+WtA9Dqx2EQIR1EiyEV6bv84yIDXYHfzSyrXoMEECgYEA5cCjdhu96L9XRGZ00wWvtZphQ/cNffUy6fhnvbGjbb1FNrEhmm5vfU1nVU0060G6p8x25jW6eLgeT1V0OLq0DLuec4lXbt8OhqVhh8pvXvSOy/C+HBixWMDPJZ4TnQ75p/yZ2MC3fVQEgMHiNaYO0VZ7qyshDNzeidPuwsfqx/0CgYEAriSRD7yzXxraEwJ6OYBxubOb0TtJFePzucsZ9mjrVCzCWFgJkDtnh1Y9FS+xBW1gyFe1CudiTcAneuGCICw0yZPAdUsdc3m3LgeP4dDWPJ9bFVx0mgf6onv+agrJVyV/KEJzA5Co0wB7qtMWhJmNpGcMPq1K3GFSREOvhsQSYDkCgYEAhV0PBY4Q7Lu00lWO1rdkSUw1zZfo0waz6TByN6CXtym4tYiYcuZL/TYjF1bbsvvSd3iuQ+9IMK7fmTmHXy6xOPrnfTVp9UexTONO+928TCg1g5hZIkILH/O7yqA5zl9U9/ge7bzgRfWxL3Rb9LxRuZ4z5yX/51GGNAc7fwFA/ZkCgYAPVPTYl9qLAwg0KEGuklpw6RlM4JVcsgchUnpksXQWoyIxOP8OjcxdpAAYv2wseCbPPLmZzilfgw12yif0wS+cl7+YFBbxtcOk79GBJivWhok0ZkF11kIA0D3kBDMZ0xlQ6BjMNY5HlYFN1uvinMpVsSTo18UBhigCDpuDl/uuMQKBgCR9U6oYGBvU0jEzcn/XBe3xrf3+/0a3hKiLqnG7d3oj2zuZo4Y5nqY1LNIbroIcSsieGqD0zBiPE01EdwUAdrPicEH/8mr1BWnK9GdbdUc8SVCRNj66hnCMTsTAZbRDXnyafaOzvYWeEPMa48BC8N5tH/bYFpjNLkFJyX7jiZFJ" ], 1026 | "certificate" : [ "MIICmzCCAYMCBgFkADdJeTANBgkqhkiG9w0BAQsFADARMQ8wDQYDVQQDDAZtYXN0ZXIwHhcNMTgwNjE0MjEzMTIwWhcNMjgwNjE0MjEzMzAwWjARMQ8wDQYDVQQDDAZtYXN0ZXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCcScBhf7DnoJcTLJ4fgmAPC5KNa3lvDumHE5zO61pDbZkNhk3DHKXoZoQby4bDgVLd0Y+R4ZSlbe6RlXwYmHGzZ4k+e+YMGoLYItBivYO0aNg8+vF3V5n/qc5fjGU4llqhyItMl8oI1dOanKfIcwayZVXLlBCJp5Jrt7f561+wP2KB+wk/HoTXrjstIlohoNUdPQa4v0eX0kx5A4gSHvDGzDF9gcjZCLn9/IDOlCp5mQLRuSuQt0VqZlWFyqu1TzH+c3leWeRAd7+jD/0701Au7OfuQ9aRS4WXTD5rHKBCceADx2Lq4GxT3hvrG5WKTzzEHe9IVX5RKcNMpWRSD2dVAgMBAAEwDQYJKoZIhvcNAQELBQADggEBADYbmgYTRxUGEuJaQh3tPBnPmRn/vMN3JRRjCLeJ1Yg0T7PdQ3GCFa09uIJhiox1SXCDnd9csz+JmXCwamU21RkykfBneEICZ1nRh4fdtWWXsJVelSTLxZk2h1+8/xpz/HK29Dah5eAmp00QhBDPj6POmAx0YwUqMdQFtrG17Dr3lYzZFchJuCHoUBnIZT9yLbfq+znZlAb+Wtczu3B2Hw+ZBRKsan9C/GywQQuwGCYTcJMTrT7fzwuLtTEmcvcQCBjh9eUxcVSktW4DkP1RXcF3jFfrGtuWIoaTZi8bcw2ylmkmczRGbjM2Gy2R/uI/9Bpya5t6SAbVLZIAoz+R1kk=" ], 1027 | "priority" : [ "100" ] 1028 | } 1029 | } ] 1030 | }, 1031 | "internationalizationEnabled" : false, 1032 | "supportedLocales" : [ ], 1033 | "authenticationFlows" : [ { 1034 | "id" : "61a1b04f-4cda-4d04-9f99-9ccafb0ec25d", 1035 | "alias" : "Handle Existing Account", 1036 | "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", 1037 | "providerId" : "basic-flow", 1038 | "topLevel" : false, 1039 | "builtIn" : true, 1040 | "authenticationExecutions" : [ { 1041 | "authenticator" : "idp-confirm-link", 1042 | "requirement" : "REQUIRED", 1043 | "priority" : 10, 1044 | "userSetupAllowed" : false, 1045 | "autheticatorFlow" : false 1046 | }, { 1047 | "authenticator" : "idp-email-verification", 1048 | "requirement" : "ALTERNATIVE", 1049 | "priority" : 20, 1050 | "userSetupAllowed" : false, 1051 | "autheticatorFlow" : false 1052 | }, { 1053 | "requirement" : "ALTERNATIVE", 1054 | "priority" : 30, 1055 | "flowAlias" : "Verify Existing Account by Re-authentication", 1056 | "userSetupAllowed" : false, 1057 | "autheticatorFlow" : true 1058 | } ] 1059 | }, { 1060 | "id" : "0122afb1-77ec-4b00-93a5-434a765ed1a2", 1061 | "alias" : "Verify Existing Account by Re-authentication", 1062 | "description" : "Reauthentication of existing account", 1063 | "providerId" : "basic-flow", 1064 | "topLevel" : false, 1065 | "builtIn" : true, 1066 | "authenticationExecutions" : [ { 1067 | "authenticator" : "idp-username-password-form", 1068 | "requirement" : "REQUIRED", 1069 | "priority" : 10, 1070 | "userSetupAllowed" : false, 1071 | "autheticatorFlow" : false 1072 | }, { 1073 | "authenticator" : "auth-otp-form", 1074 | "requirement" : "OPTIONAL", 1075 | "priority" : 20, 1076 | "userSetupAllowed" : false, 1077 | "autheticatorFlow" : false 1078 | } ] 1079 | }, { 1080 | "id" : "783fff67-0563-4937-a8b7-3dfc292c1dd8", 1081 | "alias" : "browser", 1082 | "description" : "browser based authentication", 1083 | "providerId" : "basic-flow", 1084 | "topLevel" : true, 1085 | "builtIn" : true, 1086 | "authenticationExecutions" : [ { 1087 | "authenticator" : "auth-cookie", 1088 | "requirement" : "ALTERNATIVE", 1089 | "priority" : 10, 1090 | "userSetupAllowed" : false, 1091 | "autheticatorFlow" : false 1092 | }, { 1093 | "authenticator" : "auth-spnego", 1094 | "requirement" : "DISABLED", 1095 | "priority" : 20, 1096 | "userSetupAllowed" : false, 1097 | "autheticatorFlow" : false 1098 | }, { 1099 | "authenticator" : "identity-provider-redirector", 1100 | "requirement" : "ALTERNATIVE", 1101 | "priority" : 25, 1102 | "userSetupAllowed" : false, 1103 | "autheticatorFlow" : false 1104 | }, { 1105 | "requirement" : "ALTERNATIVE", 1106 | "priority" : 30, 1107 | "flowAlias" : "forms", 1108 | "userSetupAllowed" : false, 1109 | "autheticatorFlow" : true 1110 | } ] 1111 | }, { 1112 | "id" : "ab20292d-e385-4bc6-a61a-6d80b5b2350f", 1113 | "alias" : "clients", 1114 | "description" : "Base authentication for clients", 1115 | "providerId" : "client-flow", 1116 | "topLevel" : true, 1117 | "builtIn" : true, 1118 | "authenticationExecutions" : [ { 1119 | "authenticator" : "client-secret", 1120 | "requirement" : "ALTERNATIVE", 1121 | "priority" : 10, 1122 | "userSetupAllowed" : false, 1123 | "autheticatorFlow" : false 1124 | }, { 1125 | "authenticator" : "client-jwt", 1126 | "requirement" : "ALTERNATIVE", 1127 | "priority" : 20, 1128 | "userSetupAllowed" : false, 1129 | "autheticatorFlow" : false 1130 | }, { 1131 | "authenticator" : "client-secret-jwt", 1132 | "requirement" : "ALTERNATIVE", 1133 | "priority" : 30, 1134 | "userSetupAllowed" : false, 1135 | "autheticatorFlow" : false 1136 | } ] 1137 | }, { 1138 | "id" : "4166bae5-3edf-4965-85ac-be094f4c1a7e", 1139 | "alias" : "direct grant", 1140 | "description" : "OpenID Connect Resource Owner Grant", 1141 | "providerId" : "basic-flow", 1142 | "topLevel" : true, 1143 | "builtIn" : true, 1144 | "authenticationExecutions" : [ { 1145 | "authenticator" : "direct-grant-validate-username", 1146 | "requirement" : "REQUIRED", 1147 | "priority" : 10, 1148 | "userSetupAllowed" : false, 1149 | "autheticatorFlow" : false 1150 | }, { 1151 | "authenticator" : "direct-grant-validate-password", 1152 | "requirement" : "REQUIRED", 1153 | "priority" : 20, 1154 | "userSetupAllowed" : false, 1155 | "autheticatorFlow" : false 1156 | }, { 1157 | "authenticator" : "direct-grant-validate-otp", 1158 | "requirement" : "OPTIONAL", 1159 | "priority" : 30, 1160 | "userSetupAllowed" : false, 1161 | "autheticatorFlow" : false 1162 | } ] 1163 | }, { 1164 | "id" : "cfabe9ae-6534-4fc6-a12c-9e5528a11b94", 1165 | "alias" : "docker auth", 1166 | "description" : "Used by Docker clients to authenticate against the IDP", 1167 | "providerId" : "basic-flow", 1168 | "topLevel" : true, 1169 | "builtIn" : true, 1170 | "authenticationExecutions" : [ { 1171 | "authenticator" : "docker-http-basic-authenticator", 1172 | "requirement" : "REQUIRED", 1173 | "priority" : 10, 1174 | "userSetupAllowed" : false, 1175 | "autheticatorFlow" : false 1176 | } ] 1177 | }, { 1178 | "id" : "8ed0f2e4-6c13-48c1-9e5b-de66c31585bc", 1179 | "alias" : "first broker login", 1180 | "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", 1181 | "providerId" : "basic-flow", 1182 | "topLevel" : true, 1183 | "builtIn" : true, 1184 | "authenticationExecutions" : [ { 1185 | "authenticatorConfig" : "review profile config", 1186 | "authenticator" : "idp-review-profile", 1187 | "requirement" : "REQUIRED", 1188 | "priority" : 10, 1189 | "userSetupAllowed" : false, 1190 | "autheticatorFlow" : false 1191 | }, { 1192 | "authenticatorConfig" : "create unique user config", 1193 | "authenticator" : "idp-create-user-if-unique", 1194 | "requirement" : "ALTERNATIVE", 1195 | "priority" : 20, 1196 | "userSetupAllowed" : false, 1197 | "autheticatorFlow" : false 1198 | }, { 1199 | "requirement" : "ALTERNATIVE", 1200 | "priority" : 30, 1201 | "flowAlias" : "Handle Existing Account", 1202 | "userSetupAllowed" : false, 1203 | "autheticatorFlow" : true 1204 | } ] 1205 | }, { 1206 | "id" : "70ba014d-febc-4dc0-8933-162d5719fc45", 1207 | "alias" : "forms", 1208 | "description" : "Username, password, otp and other auth forms.", 1209 | "providerId" : "basic-flow", 1210 | "topLevel" : false, 1211 | "builtIn" : true, 1212 | "authenticationExecutions" : [ { 1213 | "authenticator" : "auth-username-password-form", 1214 | "requirement" : "REQUIRED", 1215 | "priority" : 10, 1216 | "userSetupAllowed" : false, 1217 | "autheticatorFlow" : false 1218 | }, { 1219 | "authenticator" : "auth-otp-form", 1220 | "requirement" : "OPTIONAL", 1221 | "priority" : 20, 1222 | "userSetupAllowed" : false, 1223 | "autheticatorFlow" : false 1224 | } ] 1225 | }, { 1226 | "id" : "9117514e-34ed-4713-975a-4bd1f1d8b87e", 1227 | "alias" : "registration", 1228 | "description" : "registration flow", 1229 | "providerId" : "basic-flow", 1230 | "topLevel" : true, 1231 | "builtIn" : true, 1232 | "authenticationExecutions" : [ { 1233 | "authenticator" : "registration-page-form", 1234 | "requirement" : "REQUIRED", 1235 | "priority" : 10, 1236 | "flowAlias" : "registration form", 1237 | "userSetupAllowed" : false, 1238 | "autheticatorFlow" : true 1239 | } ] 1240 | }, { 1241 | "id" : "0db3b011-5777-4c32-84a7-f68215b6d819", 1242 | "alias" : "registration form", 1243 | "description" : "registration form", 1244 | "providerId" : "form-flow", 1245 | "topLevel" : false, 1246 | "builtIn" : true, 1247 | "authenticationExecutions" : [ { 1248 | "authenticator" : "registration-user-creation", 1249 | "requirement" : "REQUIRED", 1250 | "priority" : 20, 1251 | "userSetupAllowed" : false, 1252 | "autheticatorFlow" : false 1253 | }, { 1254 | "authenticator" : "registration-profile-action", 1255 | "requirement" : "REQUIRED", 1256 | "priority" : 40, 1257 | "userSetupAllowed" : false, 1258 | "autheticatorFlow" : false 1259 | }, { 1260 | "authenticator" : "registration-password-action", 1261 | "requirement" : "REQUIRED", 1262 | "priority" : 50, 1263 | "userSetupAllowed" : false, 1264 | "autheticatorFlow" : false 1265 | }, { 1266 | "authenticator" : "registration-recaptcha-action", 1267 | "requirement" : "DISABLED", 1268 | "priority" : 60, 1269 | "userSetupAllowed" : false, 1270 | "autheticatorFlow" : false 1271 | } ] 1272 | }, { 1273 | "id" : "8c32835d-b47a-4692-b4f7-e381ce88cb3c", 1274 | "alias" : "reset credentials", 1275 | "description" : "Reset credentials for a user if they forgot their password or something", 1276 | "providerId" : "basic-flow", 1277 | "topLevel" : true, 1278 | "builtIn" : true, 1279 | "authenticationExecutions" : [ { 1280 | "authenticator" : "reset-credentials-choose-user", 1281 | "requirement" : "REQUIRED", 1282 | "priority" : 10, 1283 | "userSetupAllowed" : false, 1284 | "autheticatorFlow" : false 1285 | }, { 1286 | "authenticator" : "reset-credential-email", 1287 | "requirement" : "REQUIRED", 1288 | "priority" : 20, 1289 | "userSetupAllowed" : false, 1290 | "autheticatorFlow" : false 1291 | }, { 1292 | "authenticator" : "reset-password", 1293 | "requirement" : "REQUIRED", 1294 | "priority" : 30, 1295 | "userSetupAllowed" : false, 1296 | "autheticatorFlow" : false 1297 | }, { 1298 | "authenticator" : "reset-otp", 1299 | "requirement" : "OPTIONAL", 1300 | "priority" : 40, 1301 | "userSetupAllowed" : false, 1302 | "autheticatorFlow" : false 1303 | } ] 1304 | }, { 1305 | "id" : "43360983-3a87-4972-a1c7-8094ff7ecfc7", 1306 | "alias" : "saml ecp", 1307 | "description" : "SAML ECP Profile Authentication Flow", 1308 | "providerId" : "basic-flow", 1309 | "topLevel" : true, 1310 | "builtIn" : true, 1311 | "authenticationExecutions" : [ { 1312 | "authenticator" : "http-basic-authenticator", 1313 | "requirement" : "REQUIRED", 1314 | "priority" : 10, 1315 | "userSetupAllowed" : false, 1316 | "autheticatorFlow" : false 1317 | } ] 1318 | } ], 1319 | "authenticatorConfig" : [ { 1320 | "id" : "a8bc5248-6eec-4422-b49f-1bfb3864af24", 1321 | "alias" : "create unique user config", 1322 | "config" : { 1323 | "require.password.update.after.registration" : "false" 1324 | } 1325 | }, { 1326 | "id" : "0ba52bb9-2da6-4731-852b-22871ada8170", 1327 | "alias" : "review profile config", 1328 | "config" : { 1329 | "update.profile.on.first.login" : "missing" 1330 | } 1331 | } ], 1332 | "requiredActions" : [ { 1333 | "alias" : "CONFIGURE_TOTP", 1334 | "name" : "Configure OTP", 1335 | "providerId" : "CONFIGURE_TOTP", 1336 | "enabled" : true, 1337 | "defaultAction" : false, 1338 | "config" : { } 1339 | }, { 1340 | "alias" : "UPDATE_PASSWORD", 1341 | "name" : "Update Password", 1342 | "providerId" : "UPDATE_PASSWORD", 1343 | "enabled" : true, 1344 | "defaultAction" : false, 1345 | "config" : { } 1346 | }, { 1347 | "alias" : "UPDATE_PROFILE", 1348 | "name" : "Update Profile", 1349 | "providerId" : "UPDATE_PROFILE", 1350 | "enabled" : true, 1351 | "defaultAction" : false, 1352 | "config" : { } 1353 | }, { 1354 | "alias" : "VERIFY_EMAIL", 1355 | "name" : "Verify Email", 1356 | "providerId" : "VERIFY_EMAIL", 1357 | "enabled" : true, 1358 | "defaultAction" : false, 1359 | "config" : { } 1360 | }, { 1361 | "alias" : "terms_and_conditions", 1362 | "name" : "Terms and Conditions", 1363 | "providerId" : "terms_and_conditions", 1364 | "enabled" : false, 1365 | "defaultAction" : false, 1366 | "config" : { } 1367 | } ], 1368 | "browserFlow" : "browser", 1369 | "registrationFlow" : "registration", 1370 | "directGrantFlow" : "direct grant", 1371 | "resetCredentialsFlow" : "reset credentials", 1372 | "clientAuthenticationFlow" : "clients", 1373 | "dockerAuthenticationFlow" : "docker auth", 1374 | "attributes" : { 1375 | "_browser_header.xXSSProtection" : "1; mode=block", 1376 | "_browser_header.strictTransportSecurity" : "max-age=31536000; includeSubDomains", 1377 | "_browser_header.xFrameOptions" : "SAMEORIGIN", 1378 | "quickLoginCheckMilliSeconds" : "1000", 1379 | "permanentLockout" : "false", 1380 | "displayName" : "Keycloak", 1381 | "_browser_header.xRobotsTag" : "none", 1382 | "maxFailureWaitSeconds" : "900", 1383 | "displayNameHtml" : "
Keycloak
", 1384 | "minimumQuickLoginWaitSeconds" : "60", 1385 | "failureFactor" : "30", 1386 | "maxDeltaTimeSeconds" : "43200", 1387 | "_browser_header.xContentTypeOptions" : "nosniff", 1388 | "bruteForceProtected" : "false", 1389 | "_browser_header.contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", 1390 | "waitIncrementSeconds" : "60" 1391 | }, 1392 | "keycloakVersion" : "4.0.0.Final", 1393 | "userManagedAccessAllowed" : false 1394 | } -------------------------------------------------------------------------------- /keycloak_4_spring_boot_2/keycloak/config/master-users-0.json: -------------------------------------------------------------------------------- 1 | { 2 | "realm" : "master", 3 | "users" : [ { 4 | "id" : "f7329203-f7bb-4509-854b-95f493f95452", 5 | "createdTimestamp" : 1529011982038, 6 | "username" : "admin", 7 | "enabled" : true, 8 | "totp" : false, 9 | "emailVerified" : false, 10 | "credentials" : [ { 11 | "type" : "password", 12 | "hashedSaltedValue" : "EGJ14cgjk392xckQO6ZIJXbBFknVCRT4PJO32Rq015r5UEl1w4OiY9gLYzgqdLY1gpjZWhkraBkRi5FaOElJcw==", 13 | "salt" : "Qv0W3asckEj6fd80bMoyvQ==", 14 | "hashIterations" : 27500, 15 | "counter" : 0, 16 | "algorithm" : "pbkdf2-sha256", 17 | "digits" : 0, 18 | "period" : 0, 19 | "config" : { } 20 | } ], 21 | "disableableCredentialTypes" : [ "password" ], 22 | "requiredActions" : [ ], 23 | "realmRoles" : [ "admin", "offline_access", "uma_authorization" ], 24 | "clientRoles" : { 25 | "account" : [ "manage-account", "view-profile" ] 26 | }, 27 | "notBefore" : 0, 28 | "groups" : [ ] 29 | } ] 30 | } -------------------------------------------------------------------------------- /keycloak_4_spring_boot_2/keycloak/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | 5 | keycloak: 6 | image: jboss/keycloak:4.0.0.Final 7 | restart: on-failure 8 | command: 9 | - "-b" 10 | - "0.0.0.0" 11 | - "-Dkeycloak.migration.action=import" 12 | - "-Dkeycloak.migration.provider=dir" 13 | - "-Dkeycloak.migration.dir=/config/" 14 | - "-Dkeycloak.migration.strategy=IGNORE_EXISTING" 15 | volumes: 16 | - ./config:/config/ 17 | environment: 18 | - KEYCLOAK_USER=admin 19 | - KEYCLOAK_PASSWORD=password 20 | - DB_VENDOR=postgres 21 | - DB_USER=admin 22 | - DB_PASSWORD=password 23 | - DB_ADDR=keycloak-db 24 | - DB_PORT=5432 25 | - DB_DATABASE=keycloakdb 26 | ports: 27 | - "8081:8080" 28 | depends_on: 29 | - keycloak-db 30 | 31 | keycloak-db: 32 | image: postgres:10 33 | environment: 34 | POSTGRES_USER: admin 35 | POSTGRES_PASSWORD: password 36 | POSTGRES_DB: keycloakdb 37 | volumes: 38 | - pgdata:/var/lib/postgresql/data 39 | 40 | volumes: 41 | pgdata: -------------------------------------------------------------------------------- /keycloak_4_spring_boot_2/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.johannesinnerbichler 7 | keycloak-4-spring-boot-2 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | person-app 12 | Example project for integrating Keycloak with Spring Boot applications on Kubernetes. 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.3.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 4.0.0.Final 26 | jinnerbichler 27 | 28 | 29 | 30 | 31 | org.springframework.boot 32 | spring-boot-starter-freemarker 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-web 37 | 38 | 39 | org.springframework.boot 40 | spring-boot-starter-security 41 | 42 | 43 | org.keycloak 44 | keycloak-spring-boot-2-starter 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-test 49 | test 50 | 51 | 52 | 53 | 54 | 55 | 56 | org.keycloak.bom 57 | keycloak-adapter-bom 58 | ${keycloak.version} 59 | pom 60 | import 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | org.springframework.boot 69 | spring-boot-maven-plugin 70 | 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /keycloak_4_spring_boot_2/readme.md: -------------------------------------------------------------------------------- 1 | # Integrating Keycloak 4 with Spring Boot 2 Microservices 2 | 3 | This project shows a simple integration of Keycloak 4 in Spring Boot 2 applications. 4 | 5 | The following versions are used: 6 | 7 | * __Docker__: 18.03.1-ce 8 | * __Docker-compose__: 1.21.1 9 | * __Apache Maven__: 3.5.3 10 | * __Spring Boot__: 2.0.3.RELEASE 11 | * __Keycloak__: 4.0.0.Final 12 | 13 | ## Keycloak Setup 14 | 15 | First Keycloak and the database needs to be started via: 16 | 17 | ``` 18 | docker-compose -f keycloak/docker-compose.yml up 19 | ``` 20 | 21 | It imports a demo realm with an example user and sets the admin credentials to `admin:password`. You can visit the administration console at [http://localhost:8081/auth/](http://localhost:8081/auth/). 22 | 23 | ## Spring Boot Application 24 | 25 | After Keycloak started successfully, you can start the Spring Boot application in a separate terminal via 26 | 27 | ``` 28 | mvn package spring-boot:run 29 | ``` 30 | 31 | It is accessible on [http://localhost:8080](http://localhost:8080). After clicking on `All Persons`, the login page from Keycloak shows up. The credentials of the demo user are `username:password`. Signing in with that user should redirect you back to the application, where the restricted list of persons is shown. 32 | -------------------------------------------------------------------------------- /keycloak_4_spring_boot_2/src/main/java/com/johannesinnerbichler/personapp/PersonApplication.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.personapp; 2 | 3 | import org.keycloak.adapters.KeycloakConfigResolver; 4 | import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; 5 | import org.keycloak.adapters.springsecurity.KeycloakConfiguration; 6 | import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents; 7 | import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; 8 | import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; 9 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 10 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 11 | import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; 12 | import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; 13 | import org.springframework.security.core.session.SessionRegistryImpl; 14 | import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; 15 | import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.boot.SpringApplication; 18 | import org.springframework.boot.autoconfigure.SpringBootApplication; 19 | import org.springframework.context.annotation.Bean; 20 | import org.springframework.context.annotation.ComponentScan; 21 | import org.springframework.context.annotation.Configuration; 22 | import org.springframework.stereotype.Controller; 23 | import org.springframework.ui.Model; 24 | import org.springframework.web.bind.annotation.GetMapping; 25 | 26 | import javax.servlet.ServletException; 27 | import javax.servlet.http.HttpServletRequest; 28 | import java.util.Arrays; 29 | 30 | @SpringBootApplication 31 | public class PersonApplication { 32 | 33 | public static void main(String[] args) { 34 | SpringApplication.run(PersonApplication.class, args); 35 | } 36 | } 37 | 38 | @Controller 39 | class PersonController { 40 | 41 | @GetMapping(path = "/") 42 | public String getIndex() { 43 | return "index"; 44 | } 45 | 46 | @GetMapping(path = "/persons") 47 | public String getPersons(Model model) { 48 | model.addAttribute("persons", Arrays.asList("John", "David", "Peter")); 49 | return "persons"; 50 | } 51 | 52 | @GetMapping(path = "/logout") 53 | public String logout(HttpServletRequest request) throws ServletException { 54 | request.logout(); 55 | return "/"; 56 | } 57 | } 58 | 59 | @KeycloakConfiguration 60 | class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { 61 | 62 | /** 63 | * Registers the KeycloakAuthenticationProvider with the authentication manager. 64 | */ 65 | @Autowired 66 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 67 | KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider(); 68 | 69 | // adding proper authority mapper for prefixing role with "ROLE_" 70 | keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); 71 | 72 | auth.authenticationProvider(keycloakAuthenticationProvider); 73 | } 74 | 75 | /** 76 | * Provide a session authentication strategy bean which should be of type 77 | * RegisterSessionAuthenticationStrategy for public or confidential applications 78 | * and NullAuthenticatedSessionStrategy for bearer-only applications. 79 | */ 80 | @Bean 81 | @Override 82 | protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { 83 | return new RegisterSessionAuthenticationStrategy(new SessionRegistryImpl()); 84 | } 85 | 86 | /** 87 | * Use properties in application.properties instead of keycloak.json 88 | */ 89 | @Bean 90 | public KeycloakConfigResolver KeycloakConfigResolver() { 91 | return new KeycloakSpringBootConfigResolver(); 92 | } 93 | 94 | /** 95 | * Secure appropriate endpoints 96 | */ 97 | @Override 98 | protected void configure(HttpSecurity http) throws Exception { 99 | super.configure(http); 100 | http.authorizeRequests() 101 | .antMatchers("/persons*").hasRole("user") // only user with role user are allowed to access 102 | .anyRequest().permitAll(); 103 | } 104 | } 105 | 106 | -------------------------------------------------------------------------------- /keycloak_4_spring_boot_2/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | keycloak: 2 | auth-server-url: http://127.0.0.1:8081/auth/ 3 | resource: persons-app 4 | realm: PersonRealm 5 | public-client: true 6 | principal-attribute: preferred_username 7 | -------------------------------------------------------------------------------- /keycloak_4_spring_boot_2/src/main/resources/templates/index.ftl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Landing page 6 | 7 | 8 | 9 | All persons 10 | 11 | 12 | -------------------------------------------------------------------------------- /keycloak_4_spring_boot_2/src/main/resources/templates/persons.ftl: -------------------------------------------------------------------------------- 1 | <#import "/spring.ftl" as spring> 2 | 3 | 4 |

Persons

5 | 10 |
11 | Logout 12 | -------------------------------------------------------------------------------- /spring-data-jpa-encryption/.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | .sts4-cache 12 | 13 | ### IntelliJ IDEA ### 14 | .idea 15 | *.iws 16 | *.iml 17 | *.ipr 18 | 19 | ### NetBeans ### 20 | /nbproject/private/ 21 | /build/ 22 | /nbbuild/ 23 | /dist/ 24 | /nbdist/ 25 | /.nb-gradle/ -------------------------------------------------------------------------------- /spring-data-jpa-encryption/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM maven:3.5-jdk-8 as builder 2 | WORKDIR / 3 | COPY . / 4 | RUN mvn clean package 5 | 6 | FROM openjdk:8-jdk-alpine 7 | LABEL maintainer="j.innerbichler@gmail.com" 8 | COPY --from=builder /target/spring-data-jpa-encryption-0.0.1-SNAPSHOT.jar app.jar 9 | EXPOSE 8080 10 | ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/app.jar"] 11 | -------------------------------------------------------------------------------- /spring-data-jpa-encryption/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | db: 5 | image: postgres:10 6 | environment: 7 | POSTGRES_USER: admin 8 | POSTGRES_PASSWORD: password 9 | POSTGRES_DB: customerdb 10 | healthcheck: 11 | test: ["CMD-SHELL", "pg_isready -U postgres"] 12 | interval: 30s 13 | timeout: 30s 14 | retries: 3 15 | 16 | app: 17 | build: . 18 | restart: on-failure 19 | environment: 20 | POSTGRES_HOST: db 21 | POSTGRES_PORT: 5432 22 | POSTGRES_DB: customerdb 23 | POSTGRES_USER: admin 24 | POSTGRES_PASSWORD: password 25 | depends_on: 26 | - db 27 | 28 | pgweb: 29 | image: sosedoff/pgweb 30 | restart: on-failure 31 | ports: 32 | - "8081:8081" 33 | environment: 34 | - DATABASE_URL=postgres://admin:password@db:5432/customerdb?sslmode=disable 35 | depends_on: 36 | - db -------------------------------------------------------------------------------- /spring-data-jpa-encryption/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.johannesinnerbichler 7 | spring-data-jpa-encryption 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | database-encryption 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 2.0.2.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | 27 | 28 | 29 | org.springframework.boot 30 | spring-boot-starter-data-jpa 31 | 32 | 33 | org.springframework.boot 34 | spring-boot-starter-security 35 | 36 | 37 | com.h2database 38 | h2 39 | runtime 40 | 41 | 42 | 43 | org.postgresql 44 | postgresql 45 | 42.2.2 46 | 47 | 48 | 49 | org.bouncycastle 50 | bcpkix-jdk15on 51 | 1.59 52 | 53 | 54 | 55 | org.springframework.boot 56 | spring-boot-starter-test 57 | test 58 | 59 | 60 | org.springframework.security 61 | spring-security-test 62 | test 63 | 64 | 65 | 66 | 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-maven-plugin 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /spring-data-jpa-encryption/readme.md: -------------------------------------------------------------------------------- 1 | # GDPR Compliance with Spring Boot Applications and External Databases 2 | 3 | Additional details can be found on the corresponding [blog post](). 4 | 5 | Execute 6 | 7 | ``` 8 | docker-compose up --build 9 | ``` 10 | 11 | in order to build the application and execute the exemplary setup. -------------------------------------------------------------------------------- /spring-data-jpa-encryption/src/main/java/com/johannesinnerbichler/spring/data/jpa/encryption/JPAEncryptionApplication.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.spring.data.jpa.encryption; 2 | 3 | import com.johannesinnerbichler.spring.data.jpa.encryption.customer.Customer; 4 | import com.johannesinnerbichler.spring.data.jpa.encryption.customer.CustomerRepository; 5 | import org.slf4j.Logger; 6 | import org.slf4j.LoggerFactory; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.CommandLineRunner; 9 | import org.springframework.boot.SpringApplication; 10 | import org.springframework.boot.autoconfigure.SpringBootApplication; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.time.LocalDate; 14 | import java.time.LocalDateTime; 15 | 16 | @SpringBootApplication 17 | public class JPAEncryptionApplication { 18 | 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(JPAEncryptionApplication.class, args); 22 | } 23 | 24 | @Component 25 | public static class DataLoader implements CommandLineRunner { 26 | 27 | private final Logger logger = LoggerFactory.getLogger(DataLoader.class); 28 | 29 | @Autowired 30 | CustomerRepository customerRepository; 31 | 32 | @Override 33 | public void run(String... strings) { 34 | 35 | // save different customers (columns are encrypted before stored in database) 36 | Customer customer1 = new Customer(); 37 | customer1.setFirstName("Johannes"); 38 | customer1.setLastName("Innerbichler"); 39 | customer1.setEmail("j.innerbichler@gmail.com"); 40 | customer1.setBirthDate(LocalDate.of(1987, 6, 17)); 41 | customer1.setCreationDate(LocalDateTime.now()); 42 | customerRepository.save(customer1); 43 | logger.info("Stored customer one"); 44 | Customer customer2 = new Customer(); 45 | customer2.setFirstName("Jack"); 46 | customer2.setLastName("Black"); 47 | customer2.setEmail("jack@black.example"); 48 | customer2.setBirthDate(LocalDate.of(1984, 8, 17)); 49 | customer2.setCreationDate(LocalDateTime.now()); 50 | customerRepository.save(customer2); 51 | logger.info("Stored customer two"); 52 | 53 | // find customers by mail (columns are decrypted after being fetched from database) 54 | assert customerRepository.findOneByEmail("j.innerbichler@gmail.com") != null; 55 | logger.info("Found customer one"); 56 | assert customerRepository.findOneByEmail("jack@black.example") != null; 57 | logger.info("Found customer two"); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /spring-data-jpa-encryption/src/main/java/com/johannesinnerbichler/spring/data/jpa/encryption/converters/AbstractConverter.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.spring.data.jpa.encryption.converters; 2 | 3 | import org.springframework.security.crypto.encrypt.TextEncryptor; 4 | 5 | import javax.persistence.AttributeConverter; 6 | 7 | import static com.johannesinnerbichler.spring.data.jpa.encryption.converters.DatabaseEncryptionPasswordProperty.DATABASE_ENCRYPTION_PASSWORD; 8 | 9 | abstract class AbstractConverter implements AttributeConverter { 10 | 11 | @Override 12 | public String convertToDatabaseColumn(T attribute) { 13 | TextEncryptor encryptor = getEncryptor(); 14 | if (encryptor != null && attribute != null) 15 | return encrypt(encryptor, attribute); 16 | return entityAttributeToString(attribute); 17 | } 18 | 19 | @Override 20 | public T convertToEntityAttribute(String dbData) { 21 | TextEncryptor encryptor = getEncryptor(); 22 | if (encryptor != null && dbData != null) 23 | return decrypt(encryptor, dbData); 24 | return stringToEntityAttribute(dbData); 25 | } 26 | 27 | private TextEncryptor getEncryptor() { 28 | return DATABASE_ENCRYPTION_PASSWORD != null ? new AesEncryptor() : null; 29 | } 30 | 31 | abstract T stringToEntityAttribute(String data); 32 | 33 | abstract String entityAttributeToString(T attribute); 34 | 35 | private String encrypt(TextEncryptor encryptor, T attribute) { 36 | String attributeString = entityAttributeToString(attribute); 37 | return encryptor.encrypt(attributeString); 38 | } 39 | 40 | private T decrypt(TextEncryptor encryptor, String attributeString) { 41 | String decryptedAttributeString = encryptor.decrypt(attributeString); 42 | return stringToEntityAttribute(decryptedAttributeString); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /spring-data-jpa-encryption/src/main/java/com/johannesinnerbichler/spring/data/jpa/encryption/converters/AesEncryptor.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.spring.data.jpa.encryption.converters; 2 | 3 | import org.springframework.security.crypto.codec.Hex; 4 | import org.springframework.security.crypto.codec.Utf8; 5 | import org.springframework.security.crypto.encrypt.BouncyCastleAesCbcBytesEncryptor; 6 | import org.springframework.security.crypto.encrypt.BytesEncryptor; 7 | import org.springframework.security.crypto.encrypt.TextEncryptor; 8 | import org.springframework.security.crypto.keygen.BytesKeyGenerator; 9 | 10 | import java.util.Random; 11 | 12 | 13 | import static com.johannesinnerbichler.spring.data.jpa.encryption.converters.DatabaseEncryptionPasswordProperty.DATABASE_ENCRYPTION_PASSWORD; 14 | import static com.johannesinnerbichler.spring.data.jpa.encryption.converters.DatabaseEncryptionPasswordProperty.DATABASE_ENCRYPTION_SALT; 15 | 16 | final class AesEncryptor implements TextEncryptor { 17 | 18 | private final BytesEncryptor encryptor; 19 | 20 | AesEncryptor() { 21 | this.encryptor = new BouncyCastleAesCbcBytesEncryptor( 22 | DATABASE_ENCRYPTION_PASSWORD, 23 | DATABASE_ENCRYPTION_SALT, 24 | new PredictableRandomBytesKeyGenerator(16)); 25 | } 26 | 27 | public String encrypt(String text) { 28 | return new String(Hex.encode(encryptor.encrypt(Utf8.encode(text)))); 29 | } 30 | 31 | public String decrypt(String encryptedText) { 32 | return Utf8.decode(encryptor.decrypt(Hex.decode(encryptedText))); 33 | } 34 | 35 | /** 36 | * A BytesKeyGenerator that always generates the same sequence of values 37 | */ 38 | private static class PredictableRandomBytesKeyGenerator implements BytesKeyGenerator { 39 | 40 | private final Random random; 41 | 42 | private final int keyLength; 43 | 44 | PredictableRandomBytesKeyGenerator(int keyLength) { 45 | this.random = new Random(1); // always use the same seed 46 | this.keyLength = keyLength; 47 | } 48 | 49 | public int getKeyLength() { 50 | return keyLength; 51 | } 52 | 53 | public byte[] generateKey() { 54 | byte[] bytes = new byte[keyLength]; 55 | random.nextBytes(bytes); 56 | return bytes; 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /spring-data-jpa-encryption/src/main/java/com/johannesinnerbichler/spring/data/jpa/encryption/converters/DatabaseEncryptionPasswordProperty.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.spring.data.jpa.encryption.converters; 2 | 3 | import org.springframework.beans.factory.annotation.Value; 4 | import org.springframework.stereotype.Component; 5 | 6 | @Component 7 | public class DatabaseEncryptionPasswordProperty { 8 | 9 | public static String DATABASE_ENCRYPTION_PASSWORD; 10 | public static String DATABASE_ENCRYPTION_SALT; 11 | 12 | @Value("${innerbichler.database.encryption.password}") 13 | public void setPassword(String databaseEncryptionPassword) { 14 | DATABASE_ENCRYPTION_PASSWORD = databaseEncryptionPassword; 15 | } 16 | 17 | @Value("${innerbichler.database.encryption.salt}") 18 | public void setSalt(String databaseEncryptionSalt) { 19 | DATABASE_ENCRYPTION_SALT = databaseEncryptionSalt; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /spring-data-jpa-encryption/src/main/java/com/johannesinnerbichler/spring/data/jpa/encryption/converters/LocalDateConverter.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.spring.data.jpa.encryption.converters; 2 | 3 | import javax.persistence.Converter; 4 | import java.time.LocalDate; 5 | 6 | import static java.time.format.DateTimeFormatter.ISO_DATE; 7 | 8 | @Converter 9 | public class LocalDateConverter extends AbstractConverter { 10 | @Override 11 | LocalDate stringToEntityAttribute(String data) { 12 | if (data == null) 13 | return null; 14 | return LocalDate.parse(data, ISO_DATE); 15 | } 16 | 17 | @Override 18 | String entityAttributeToString(LocalDate attr) { 19 | if (attr == null) 20 | return null; 21 | return attr.format(ISO_DATE); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /spring-data-jpa-encryption/src/main/java/com/johannesinnerbichler/spring/data/jpa/encryption/converters/LocalDateTimeConverter.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.spring.data.jpa.encryption.converters; 2 | 3 | import javax.persistence.Converter; 4 | import java.time.LocalDateTime; 5 | 6 | import static java.time.format.DateTimeFormatter.ISO_DATE_TIME; 7 | 8 | @Converter 9 | public class LocalDateTimeConverter extends AbstractConverter { 10 | @Override 11 | LocalDateTime stringToEntityAttribute(String data) { 12 | if (data == null) 13 | return null; 14 | return LocalDateTime.parse(data, ISO_DATE_TIME); 15 | } 16 | 17 | @Override 18 | String entityAttributeToString(LocalDateTime attr) { 19 | if (attr == null) 20 | return null; 21 | return attr.format(ISO_DATE_TIME); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /spring-data-jpa-encryption/src/main/java/com/johannesinnerbichler/spring/data/jpa/encryption/converters/StringConverter.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.spring.data.jpa.encryption.converters; 2 | 3 | import javax.persistence.Converter; 4 | 5 | @Converter 6 | public class StringConverter extends AbstractConverter { 7 | 8 | @Override 9 | String stringToEntityAttribute(String data) { 10 | return data; 11 | } 12 | 13 | @Override 14 | String entityAttributeToString(String attr) { 15 | return attr; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /spring-data-jpa-encryption/src/main/java/com/johannesinnerbichler/spring/data/jpa/encryption/customer/Customer.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.spring.data.jpa.encryption.customer; 2 | 3 | 4 | import com.johannesinnerbichler.spring.data.jpa.encryption.converters.LocalDateConverter; 5 | import com.johannesinnerbichler.spring.data.jpa.encryption.converters.LocalDateTimeConverter; 6 | import com.johannesinnerbichler.spring.data.jpa.encryption.converters.StringConverter; 7 | 8 | import javax.persistence.*; 9 | 10 | import java.time.LocalDate; 11 | import java.time.LocalDateTime; 12 | 13 | import static javax.persistence.GenerationType.IDENTITY; 14 | 15 | @Entity 16 | @Table(name = "customer") 17 | public class Customer { 18 | 19 | @Id 20 | @GeneratedValue(strategy = IDENTITY) 21 | @Column(name = "id") 22 | private Long id; 23 | 24 | @Column(name = "first_name") 25 | @Convert(converter = StringConverter.class) 26 | private String firstName; 27 | 28 | @Column(name = "last_name") 29 | @Convert(converter = StringConverter.class) 30 | private String lastName; 31 | 32 | @Column(name = "email") 33 | @Convert(converter = StringConverter.class) 34 | private String email; 35 | 36 | @Column(name = "birth_date") 37 | @Convert(converter = LocalDateConverter.class) 38 | private LocalDate birthDate; 39 | 40 | @Column(name = "creation_date") 41 | @Convert(converter = LocalDateTimeConverter.class) 42 | private LocalDateTime creationDate; 43 | 44 | public Long getId() { 45 | return id; 46 | } 47 | 48 | public void setId(Long id) { 49 | this.id = id; 50 | } 51 | 52 | public String getFirstName() { 53 | return firstName; 54 | } 55 | 56 | public void setFirstName(String firstName) { 57 | this.firstName = firstName; 58 | } 59 | 60 | public String getLastName() { 61 | return lastName; 62 | } 63 | 64 | public void setLastName(String lastName) { 65 | this.lastName = lastName; 66 | } 67 | 68 | public String getEmail() { 69 | return email; 70 | } 71 | 72 | public void setEmail(String email) { 73 | this.email = email; 74 | } 75 | 76 | public LocalDate getBirthDate() { 77 | return birthDate; 78 | } 79 | 80 | public void setBirthDate(LocalDate birthDate) { 81 | this.birthDate = birthDate; 82 | } 83 | 84 | public LocalDateTime getCreationDate() { 85 | return creationDate; 86 | } 87 | 88 | public void setCreationDate(LocalDateTime creationDate) { 89 | this.creationDate = creationDate; 90 | } 91 | } -------------------------------------------------------------------------------- /spring-data-jpa-encryption/src/main/java/com/johannesinnerbichler/spring/data/jpa/encryption/customer/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.spring.data.jpa.encryption.customer; 2 | 3 | import org.springframework.data.jpa.repository.JpaRepository; 4 | 5 | public interface CustomerRepository extends JpaRepository { 6 | Customer findOneByEmail(String email); 7 | } -------------------------------------------------------------------------------- /spring-data-jpa-encryption/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: ${PORT:8080} 3 | 4 | spring: 5 | jpa: 6 | database-platform: org.hibernate.dialect.PostgreSQLDialect 7 | hibernate: 8 | ddl-auto: update 9 | properties: 10 | hibernate: 11 | temp: 12 | use_jdbc_metadata_defaults: false # Fix "Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented." 13 | datasource: 14 | driverClassName: org.postgresql.Driver 15 | url: jdbc:postgresql://${POSTGRES_HOST:localhost}:${POSTGRES_PORT:5432}/${POSTGRES_DB:customer} 16 | username: ${POSTGRES_USER:admin} 17 | password: ${POSTGRES_PASSWORD:password} 18 | 19 | innerbichler: 20 | database: 21 | encryption: 22 | password: ${ENCRYPTION_PASSWORD:superSecretPassword} 23 | salt: ${ENCRYPTION_SALT:deadbeef} 24 | 25 | --- 26 | 27 | spring: 28 | profiles: test 29 | jpa: 30 | database-platform: org.hibernate.dialect.H2Dialect 31 | hibernate: 32 | ddl-auto: update 33 | datasource: 34 | url: jdbc:h2:mem:AZ;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE 35 | username: sa 36 | password: 37 | driver-class-name: org.h2.Driver -------------------------------------------------------------------------------- /spring-data-jpa-encryption/src/test/java/com/johannesinnerbichler/springdata/jpa/encryption/customer/CustomerRepositoryTest.java: -------------------------------------------------------------------------------- 1 | package com.johannesinnerbichler.springdata.jpa.encryption.customer; 2 | 3 | import com.johannesinnerbichler.spring.data.jpa.encryption.JPAEncryptionApplication; 4 | import com.johannesinnerbichler.spring.data.jpa.encryption.converters.DatabaseEncryptionPasswordProperty; 5 | import com.johannesinnerbichler.spring.data.jpa.encryption.customer.Customer; 6 | import com.johannesinnerbichler.spring.data.jpa.encryption.customer.CustomerRepository; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; 12 | import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager; 13 | import org.springframework.boot.test.context.SpringBootTest; 14 | import org.springframework.test.context.ActiveProfiles; 15 | import org.springframework.test.context.junit4.SpringRunner; 16 | 17 | import static com.johannesinnerbichler.springdata.jpa.encryption.customer.CustomerRepositoryTest.Helper.disableDatabaseEncryption; 18 | import static com.johannesinnerbichler.springdata.jpa.encryption.customer.CustomerRepositoryTest.Helper.enableDatabaseEncryption; 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | 21 | @DataJpaTest 22 | @ActiveProfiles("test") 23 | @RunWith(SpringRunner.class) 24 | @SpringBootTest(classes = JPAEncryptionApplication.class) 25 | public class CustomerRepositoryTest { 26 | 27 | @Autowired 28 | private CustomerRepository customerRepository; 29 | 30 | @Autowired 31 | private TestEntityManager testEntityManager; 32 | 33 | private Customer customer; 34 | 35 | @Before 36 | public void setUp() { 37 | enableDatabaseEncryption(testEntityManager); 38 | customer = new Customer(); 39 | } 40 | 41 | @Test 42 | public void save_should_persist_customer_with_auto_incremented_id() { 43 | Customer firstPersist = customerRepository.save(customer); 44 | Customer secondCustomer = new Customer(); 45 | 46 | Customer secondPersist = customerRepository.save(secondCustomer); 47 | 48 | assertThat(secondPersist.getId()).isEqualTo(firstPersist.getId() + 1); 49 | } 50 | 51 | @Test 52 | public void save_should_verify_that_encryption_is_enabled_on_first_name_field() { 53 | String plainFirstName = "Johannes"; 54 | customer.setFirstName(plainFirstName); 55 | Customer savedCustomerWithEncryptionEnabled = customerRepository.save(customer); 56 | disableDatabaseEncryption(testEntityManager); 57 | 58 | Customer customerRetrievedWithoutEncryptionEnabled = testEntityManager.find(Customer.class, savedCustomerWithEncryptionEnabled.getId()); 59 | 60 | assertThat(customerRetrievedWithoutEncryptionEnabled.getFirstName()) 61 | .isNotEqualTo(plainFirstName) 62 | .isEqualTo("73d51abbd89cb8196f0efb6892f94d684b9bb00e302a79defe4bc621a65f1f0f"); 63 | } 64 | 65 | @Test 66 | public void save_should_verify_that_encryption_is_enabled_on_last_name_field() { 67 | String plainLastName = "Innerbichler"; 68 | customer.setLastName(plainLastName); 69 | Customer savedCustomerWithEncryptionEnabled = customerRepository.save(customer); 70 | disableDatabaseEncryption(testEntityManager); 71 | 72 | Customer customerRetrievedWithoutEncryptionEnabled = testEntityManager.find(Customer.class, savedCustomerWithEncryptionEnabled.getId()); 73 | 74 | assertThat(customerRetrievedWithoutEncryptionEnabled.getLastName()) 75 | .isNotEqualTo(plainLastName) 76 | .isEqualTo("73d51abbd89cb8196f0efb6892f94d68b406039fa8488b90b4dce1374348607f"); 77 | } 78 | 79 | @Test 80 | public void save_should_verify_that_encryption_is_enabled_on_email_field() { 81 | String plainEmail = "j.innerbichler@gmail.com"; 82 | customer.setEmail(plainEmail); 83 | Customer savedCustomerWithEncryptionEnabled = customerRepository.save(customer); 84 | disableDatabaseEncryption(testEntityManager); 85 | 86 | Customer customerRetrievedWithoutEncryptionEnabled = testEntityManager.find(Customer.class, savedCustomerWithEncryptionEnabled.getId()); 87 | 88 | assertThat(customerRetrievedWithoutEncryptionEnabled.getEmail()) 89 | .isNotEqualTo(plainEmail) 90 | .isEqualTo("73d51abbd89cb8196f0efb6892f94d68894ed82ec367a8c562cfd884c93a5578bd96a01b8c0607f80adda09c5805d297"); 91 | } 92 | 93 | final static class Helper { 94 | 95 | static void enableDatabaseEncryption(TestEntityManager testEntityManager) { 96 | DatabaseEncryptionPasswordProperty.DATABASE_ENCRYPTION_PASSWORD = "MySuperSecretKey"; 97 | DatabaseEncryptionPasswordProperty.DATABASE_ENCRYPTION_SALT= "deadbeef"; 98 | testEntityManager.clear(); 99 | } 100 | 101 | static void disableDatabaseEncryption(TestEntityManager testEntityManager) { 102 | DatabaseEncryptionPasswordProperty.DATABASE_ENCRYPTION_PASSWORD = null; 103 | DatabaseEncryptionPasswordProperty.DATABASE_ENCRYPTION_SALT= "deadbeef"; 104 | testEntityManager.clear(); 105 | } 106 | } 107 | 108 | } --------------------------------------------------------------------------------