├── .gitignore ├── admin-service ├── .gitignore ├── .mvn │ └── wrapper │ │ ├── maven-wrapper.jar │ │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src │ ├── main │ ├── java │ │ └── demo │ │ │ └── admin │ │ │ ├── AdminServiceApplication.java │ │ │ └── keycloak │ │ │ ├── KeycloakConfig.java │ │ │ └── KeycloakController.java │ └── resources │ │ └── application.yml │ └── test │ └── java │ └── demo │ └── admin │ └── AdminServiceApplicationTests.java ├── bootadmin-realm.json ├── pom.xml ├── readme.md └── todo-service ├── .gitignore ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ └── maven-wrapper.properties ├── mvnw ├── mvnw.cmd ├── pom.xml └── src ├── main ├── java │ └── demo │ │ └── todo │ │ ├── TodoServiceApplication.java │ │ └── keycloak │ │ └── KeycloakConfig.java └── resources │ └── application.yml └── test └── java └── demo └── todo └── TodoServiceApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | .history/ 4 | 5 | ### STS ### 6 | .apt_generated 7 | .classpath 8 | .factorypath 9 | .project 10 | .settings 11 | .springBeans 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/ 26 | -------------------------------------------------------------------------------- /admin-service/.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/ -------------------------------------------------------------------------------- /admin-service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasdarimont/spring-boot-admin-keycloak-example/b186c53745722b28975312c587f25671b612183d/admin-service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /admin-service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /admin-service/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Migwn, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | echo $MAVEN_PROJECTBASEDIR 205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 206 | 207 | # For Cygwin, switch paths to Windows format before running java 208 | if $cygwin; then 209 | [ -n "$M2_HOME" ] && 210 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 211 | [ -n "$JAVA_HOME" ] && 212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 213 | [ -n "$CLASSPATH" ] && 214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 215 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 217 | fi 218 | 219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 220 | 221 | exec "$JAVACMD" \ 222 | $MAVEN_OPTS \ 223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 226 | -------------------------------------------------------------------------------- /admin-service/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /admin-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.example 8 | admin-service 9 | 0.1.0-SNAPSHOT 10 | jar 11 | 12 | admin-service 13 | Demo project for Spring Boot 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-parent 18 | 2.1.4.RELEASE 19 | 20 | 21 | 22 | 23 | UTF-8 24 | UTF-8 25 | 1.8 26 | 4.8.3.Final 27 | 2.1.3 28 | 3.6.1.Final 29 | Greenwich.SR1 30 | 31 | 32 | 33 | 34 | org.springframework.boot 35 | spring-boot-starter-security 36 | 37 | 38 | org.springframework.boot 39 | spring-boot-starter-web 40 | 41 | 42 | 43 | de.codecentric 44 | spring-boot-admin-starter-server 45 | ${spring-boot-admin.version} 46 | 47 | 48 | 49 | org.springframework.cloud 50 | spring-cloud-starter 51 | 52 | 53 | 54 | org.jboss.resteasy 55 | resteasy-client 56 | ${resteasy.version} 57 | 58 | 59 | 60 | org.jboss.resteasy 61 | resteasy-jackson2-provider 62 | ${resteasy.version} 63 | 64 | 65 | 66 | org.keycloak 67 | keycloak-spring-boot-starter 68 | 69 | 70 | 71 | org.keycloak 72 | keycloak-admin-client 73 | ${keycloak.version} 74 | 75 | 76 | 77 | org.springframework.boot 78 | spring-boot-starter-test 79 | test 80 | 81 | 82 | org.springframework.security 83 | spring-security-test 84 | test 85 | 86 | 87 | 88 | 89 | 90 | 91 | org.keycloak.bom 92 | keycloak-adapter-bom 93 | ${keycloak.version} 94 | pom 95 | import 96 | 97 | 98 | 99 | org.springframework.cloud 100 | spring-cloud-dependencies 101 | ${spring-cloud.version} 102 | pom 103 | import 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | org.springframework.boot 112 | spring-boot-maven-plugin 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /admin-service/src/main/java/demo/admin/AdminServiceApplication.java: -------------------------------------------------------------------------------- 1 | package demo.admin; 2 | 3 | import de.codecentric.boot.admin.server.config.EnableAdminServer; 4 | import org.springframework.boot.SpringApplication; 5 | import org.springframework.boot.autoconfigure.SpringBootApplication; 6 | 7 | @EnableAdminServer 8 | @SpringBootApplication 9 | public class AdminServiceApplication { 10 | 11 | public static void main(String[] args) { 12 | SpringApplication.run(AdminServiceApplication.class, args); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /admin-service/src/main/java/demo/admin/keycloak/KeycloakConfig.java: -------------------------------------------------------------------------------- 1 | package demo.admin.keycloak; 2 | 3 | import java.security.Principal; 4 | 5 | import org.keycloak.KeycloakPrincipal; 6 | import org.keycloak.KeycloakSecurityContext; 7 | import org.keycloak.OAuth2Constants; 8 | import org.keycloak.adapters.KeycloakConfigResolver; 9 | import org.keycloak.adapters.springboot.KeycloakBaseSpringBootConfiguration; 10 | import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; 11 | import org.keycloak.adapters.springboot.KeycloakSpringBootProperties; 12 | import org.keycloak.adapters.springsecurity.KeycloakConfiguration; 13 | import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; 14 | import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; 15 | import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; 16 | import org.keycloak.admin.client.Keycloak; 17 | import org.keycloak.admin.client.KeycloakBuilder; 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 20 | import org.springframework.context.annotation.Bean; 21 | import org.springframework.context.annotation.Configuration; 22 | import org.springframework.context.annotation.Scope; 23 | import org.springframework.context.annotation.ScopedProxyMode; 24 | import org.springframework.http.HttpHeaders; 25 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 26 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 27 | import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; 28 | import org.springframework.security.core.session.SessionRegistry; 29 | import org.springframework.security.core.session.SessionRegistryImpl; 30 | import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; 31 | import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; 32 | import org.springframework.web.context.WebApplicationContext; 33 | import org.springframework.web.context.request.RequestContextHolder; 34 | import org.springframework.web.context.request.ServletRequestAttributes; 35 | 36 | import de.codecentric.boot.admin.server.web.client.HttpHeadersProvider; 37 | 38 | @KeycloakConfiguration 39 | @EnableConfigurationProperties(KeycloakSpringBootProperties.class) 40 | class KeycloakConfig extends KeycloakWebSecurityConfigurerAdapter { 41 | 42 | /** 43 | * {@link HttpHeadersProvider} used to populate the {@link HttpHeaders} for 44 | * accessing the state of the disovered clients. 45 | * 46 | * @param keycloak 47 | * @return 48 | */ 49 | @Bean 50 | public HttpHeadersProvider keycloakBearerAuthHeaderProvider(Keycloak keycloak) { 51 | return (app) -> { 52 | String accessToken = keycloak.tokenManager().getAccessTokenString(); 53 | HttpHeaders headers = new HttpHeaders(); 54 | headers.add(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken); 55 | return headers; 56 | }; 57 | } 58 | 59 | /** 60 | * The Keycloak Admin client that provides the service-account Access-Token 61 | * 62 | * @param props 63 | * @return 64 | */ 65 | @Bean 66 | public Keycloak keycloak(KeycloakSpringBootProperties props) { 67 | Keycloak keycloak = KeycloakBuilder.builder() // 68 | .serverUrl(props.getAuthServerUrl()) // 69 | .realm(props.getRealm()) // 70 | .grantType(OAuth2Constants.CLIENT_CREDENTIALS) // 71 | .clientId(props.getResource()) // 72 | .clientSecret((String) props.getCredentials().get("secret")) // 73 | .build(); 74 | 75 | return keycloak; 76 | } 77 | 78 | @Override 79 | protected void configure(HttpSecurity http) throws Exception { 80 | super.configure(http); 81 | 82 | http // 83 | .csrf().disable() // for the sake of brevity... 84 | .authorizeRequests() // 85 | .antMatchers("/**/*.css", "/admin/img/**", "/admin/third-party/**").permitAll() // 86 | .antMatchers("/admin").hasRole("ADMIN") // 87 | .anyRequest().permitAll() // 88 | ; 89 | } 90 | 91 | /** 92 | * Load Keycloak configuration from application.properties or application.yml 93 | * 94 | * @return 95 | */ 96 | @Bean 97 | public KeycloakConfigResolver keycloakConfigResolver() { 98 | return new KeycloakSpringBootConfigResolver(); 99 | } 100 | 101 | /** 102 | * Use {@link KeycloakAuthenticationProvider} 103 | * 104 | * @param auth 105 | * @throws Exception 106 | */ 107 | @Autowired 108 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 109 | 110 | SimpleAuthorityMapper grantedAuthorityMapper = new SimpleAuthorityMapper(); 111 | grantedAuthorityMapper.setPrefix("ROLE_"); 112 | grantedAuthorityMapper.setConvertToUpperCase(true); 113 | 114 | KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider(); 115 | keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(grantedAuthorityMapper); 116 | auth.authenticationProvider(keycloakAuthenticationProvider); 117 | } 118 | 119 | @Bean 120 | @Override 121 | protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { 122 | return new RegisterSessionAuthenticationStrategy(buildSessionRegistry()); 123 | } 124 | 125 | @Bean 126 | protected SessionRegistry buildSessionRegistry() { 127 | return new SessionRegistryImpl(); 128 | } 129 | 130 | /** 131 | * Allows to inject requests scoped wrapper for {@link KeycloakSecurityContext}. 132 | *

133 | * Returns the {@link KeycloakSecurityContext} from the Spring 134 | * {@link ServletRequestAttributes}'s {@link Principal}. 135 | *

136 | * The principal must support retrieval of the KeycloakSecurityContext, so at 137 | * this point, only {@link KeycloakPrincipal} values and 138 | * {@link KeycloakAuthenticationToken} are supported. 139 | * 140 | * @return the current KeycloakSecurityContext 141 | */ 142 | @Bean 143 | @Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) 144 | public KeycloakSecurityContext provideKeycloakSecurityContext() { 145 | 146 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 147 | Principal principal = attributes.getRequest().getUserPrincipal(); 148 | if (principal == null) { 149 | return null; 150 | } 151 | 152 | if (principal instanceof KeycloakAuthenticationToken) { 153 | principal = Principal.class.cast(KeycloakAuthenticationToken.class.cast(principal).getPrincipal()); 154 | } 155 | 156 | if (principal instanceof KeycloakPrincipal) { 157 | return KeycloakPrincipal.class.cast(principal).getKeycloakSecurityContext(); 158 | } 159 | 160 | return null; 161 | } 162 | 163 | /** 164 | * Ensures the correct registration of KeycloakSpringBootConfigResolver when Keycloaks AutoConfiguration 165 | * is explicitly turned off in application.yml {@code keycloak.enabled: false}. 166 | */ 167 | @Configuration 168 | static class CustomKeycloakBaseSpringBootConfiguration extends KeycloakBaseSpringBootConfiguration { 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /admin-service/src/main/java/demo/admin/keycloak/KeycloakController.java: -------------------------------------------------------------------------------- 1 | package demo.admin.keycloak; 2 | 3 | import javax.servlet.http.HttpServletRequest; 4 | 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.web.bind.annotation.PostMapping; 7 | 8 | @Controller 9 | class KeycloakController { 10 | 11 | /** 12 | * Propagates the logout to the Keycloak infrastructure 13 | * @param request 14 | * @return 15 | * @throws Exception 16 | */ 17 | @PostMapping("/admin/logout") 18 | public String logout(HttpServletRequest request) throws Exception { 19 | request.logout(); 20 | return "redirect:/admin"; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /admin-service/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 30001 3 | 4 | spring: 5 | main: 6 | allow-bean-definition-overriding: true 7 | boot: 8 | admin: 9 | context-path: /admin 10 | cloud: 11 | discovery: 12 | client: 13 | simple: 14 | instances: 15 | app-todo: 16 | - uri: http://localhost:30002 17 | 18 | keycloak: 19 | # turn off keycloak spring boot auto-configuration: 20 | # We only want to use Spring Security without servlet container specific infrastructure 21 | # This allows us to pull the Keycloak configuration from here instead of keycloak.json 22 | enabled: false 23 | 24 | realm: bootadmin 25 | auth-server-url: http://localhost:8080/auth 26 | # The client_id 27 | resource: app-admin 28 | credentials: 29 | # The client_secret 30 | secret: 97edad04-49ca-4770-8e4a-3bc97c1714ce 31 | ssl-required: external 32 | # Configures what principal.getName() will return 33 | principal-attribute: preferred_username 34 | use-resource-role-mappings: true 35 | token-minimum-time-to-live: 30 -------------------------------------------------------------------------------- /admin-service/src/test/java/demo/admin/AdminServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package demo.admin; 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 AdminServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /bootadmin-realm.json: -------------------------------------------------------------------------------- 1 | { 2 | "id" : "bootadmin", 3 | "realm" : "bootadmin", 4 | "notBefore" : 0, 5 | "revokeRefreshToken" : false, 6 | "refreshTokenMaxReuse" : 0, 7 | "accessTokenLifespan" : 300, 8 | "accessTokenLifespanForImplicitFlow" : 900, 9 | "ssoSessionIdleTimeout" : 1800, 10 | "ssoSessionMaxLifespan" : 36000, 11 | "ssoSessionIdleTimeoutRememberMe" : 0, 12 | "ssoSessionMaxLifespanRememberMe" : 0, 13 | "offlineSessionIdleTimeout" : 2592000, 14 | "offlineSessionMaxLifespanEnabled" : false, 15 | "offlineSessionMaxLifespan" : 5184000, 16 | "accessCodeLifespan" : 60, 17 | "accessCodeLifespanUserAction" : 300, 18 | "accessCodeLifespanLogin" : 1800, 19 | "actionTokenGeneratedByAdminLifespan" : 43200, 20 | "actionTokenGeneratedByUserLifespan" : 300, 21 | "enabled" : true, 22 | "sslRequired" : "external", 23 | "registrationAllowed" : false, 24 | "registrationEmailAsUsername" : false, 25 | "rememberMe" : false, 26 | "verifyEmail" : false, 27 | "loginWithEmailAllowed" : true, 28 | "duplicateEmailsAllowed" : false, 29 | "resetPasswordAllowed" : false, 30 | "editUsernameAllowed" : false, 31 | "bruteForceProtected" : false, 32 | "permanentLockout" : false, 33 | "maxFailureWaitSeconds" : 900, 34 | "minimumQuickLoginWaitSeconds" : 60, 35 | "waitIncrementSeconds" : 60, 36 | "quickLoginCheckMilliSeconds" : 1000, 37 | "maxDeltaTimeSeconds" : 43200, 38 | "failureFactor" : 30, 39 | "roles" : { 40 | "realm" : [ { 41 | "id" : "bf7e52ae-a14d-431e-a190-c1a15b9696ff", 42 | "name" : "uma_authorization", 43 | "description" : "${role_uma_authorization}", 44 | "composite" : false, 45 | "clientRole" : false, 46 | "containerId" : "bootadmin", 47 | "attributes" : { } 48 | }, { 49 | "id" : "f5c8fe97-b9de-42c3-9b96-96131de3e54f", 50 | "name" : "offline_access", 51 | "description" : "${role_offline-access}", 52 | "composite" : false, 53 | "clientRole" : false, 54 | "containerId" : "bootadmin", 55 | "attributes" : { } 56 | } ], 57 | "client" : { 58 | "realm-management" : [ { 59 | "id" : "7047f22f-3efd-481a-b6ab-cc660903881a", 60 | "name" : "view-clients", 61 | "description" : "${role_view-clients}", 62 | "composite" : true, 63 | "composites" : { 64 | "client" : { 65 | "realm-management" : [ "query-clients" ] 66 | } 67 | }, 68 | "clientRole" : true, 69 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 70 | "attributes" : { } 71 | }, { 72 | "id" : "2e3589a5-52a7-40d0-b1d7-9a9a8b1809b0", 73 | "name" : "impersonation", 74 | "description" : "${role_impersonation}", 75 | "composite" : false, 76 | "clientRole" : true, 77 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 78 | "attributes" : { } 79 | }, { 80 | "id" : "95acd1c8-2016-42ca-9b08-36a6a40e7759", 81 | "name" : "realm-admin", 82 | "description" : "${role_realm-admin}", 83 | "composite" : true, 84 | "composites" : { 85 | "client" : { 86 | "realm-management" : [ "view-clients", "impersonation", "view-events", "view-realm", "create-client", "manage-realm", "view-identity-providers", "view-users", "view-authorization", "query-realms", "query-groups", "manage-users", "manage-clients", "manage-identity-providers", "query-users", "query-clients", "manage-authorization", "manage-events" ] 87 | } 88 | }, 89 | "clientRole" : true, 90 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 91 | "attributes" : { } 92 | }, { 93 | "id" : "d03f874c-70fc-4f52-9ee7-532477172913", 94 | "name" : "view-events", 95 | "description" : "${role_view-events}", 96 | "composite" : false, 97 | "clientRole" : true, 98 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 99 | "attributes" : { } 100 | }, { 101 | "id" : "3cf55bbc-5927-4428-8ecd-6e5c60b73d13", 102 | "name" : "create-client", 103 | "description" : "${role_create-client}", 104 | "composite" : false, 105 | "clientRole" : true, 106 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 107 | "attributes" : { } 108 | }, { 109 | "id" : "294aa047-925d-4b1e-ad0b-b920b73b70e2", 110 | "name" : "view-realm", 111 | "description" : "${role_view-realm}", 112 | "composite" : false, 113 | "clientRole" : true, 114 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 115 | "attributes" : { } 116 | }, { 117 | "id" : "76d23a47-be47-49b1-9876-2ba7cab9311d", 118 | "name" : "manage-realm", 119 | "description" : "${role_manage-realm}", 120 | "composite" : false, 121 | "clientRole" : true, 122 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 123 | "attributes" : { } 124 | }, { 125 | "id" : "8db96c77-edfd-4a2e-ac9a-1000ad062443", 126 | "name" : "view-users", 127 | "description" : "${role_view-users}", 128 | "composite" : true, 129 | "composites" : { 130 | "client" : { 131 | "realm-management" : [ "query-groups", "query-users" ] 132 | } 133 | }, 134 | "clientRole" : true, 135 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 136 | "attributes" : { } 137 | }, { 138 | "id" : "8088209d-e71d-4b05-b491-f90003c7df7b", 139 | "name" : "view-identity-providers", 140 | "description" : "${role_view-identity-providers}", 141 | "composite" : false, 142 | "clientRole" : true, 143 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 144 | "attributes" : { } 145 | }, { 146 | "id" : "772d1508-3887-43df-ba21-d75cb1316eb7", 147 | "name" : "view-authorization", 148 | "description" : "${role_view-authorization}", 149 | "composite" : false, 150 | "clientRole" : true, 151 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 152 | "attributes" : { } 153 | }, { 154 | "id" : "e377d771-ea6c-4d75-9344-a80cdcaa2c28", 155 | "name" : "query-realms", 156 | "description" : "${role_query-realms}", 157 | "composite" : false, 158 | "clientRole" : true, 159 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 160 | "attributes" : { } 161 | }, { 162 | "id" : "c319f826-f8dd-4399-807d-db0610d8e5c8", 163 | "name" : "manage-users", 164 | "description" : "${role_manage-users}", 165 | "composite" : false, 166 | "clientRole" : true, 167 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 168 | "attributes" : { } 169 | }, { 170 | "id" : "265a02b7-bae1-4d1c-94a8-71f95bee6e60", 171 | "name" : "query-groups", 172 | "description" : "${role_query-groups}", 173 | "composite" : false, 174 | "clientRole" : true, 175 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 176 | "attributes" : { } 177 | }, { 178 | "id" : "cc3cf200-f269-479d-bc9e-87939368afb9", 179 | "name" : "manage-clients", 180 | "description" : "${role_manage-clients}", 181 | "composite" : false, 182 | "clientRole" : true, 183 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 184 | "attributes" : { } 185 | }, { 186 | "id" : "5743268a-6afc-49c6-9474-7673520fb177", 187 | "name" : "manage-identity-providers", 188 | "description" : "${role_manage-identity-providers}", 189 | "composite" : false, 190 | "clientRole" : true, 191 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 192 | "attributes" : { } 193 | }, { 194 | "id" : "fdb7362e-fb1d-4f8b-b43f-b28f0f6beb4f", 195 | "name" : "query-users", 196 | "description" : "${role_query-users}", 197 | "composite" : false, 198 | "clientRole" : true, 199 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 200 | "attributes" : { } 201 | }, { 202 | "id" : "ec7d3534-f45d-46ce-abc4-f52908843551", 203 | "name" : "manage-authorization", 204 | "description" : "${role_manage-authorization}", 205 | "composite" : false, 206 | "clientRole" : true, 207 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 208 | "attributes" : { } 209 | }, { 210 | "id" : "6b565e25-a6a4-4661-a4a7-d06bea6d805e", 211 | "name" : "query-clients", 212 | "description" : "${role_query-clients}", 213 | "composite" : false, 214 | "clientRole" : true, 215 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 216 | "attributes" : { } 217 | }, { 218 | "id" : "9a245f68-46a2-4f4e-a8f0-daef605e88c9", 219 | "name" : "manage-events", 220 | "description" : "${role_manage-events}", 221 | "composite" : false, 222 | "clientRole" : true, 223 | "containerId" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 224 | "attributes" : { } 225 | } ], 226 | "security-admin-console" : [ ], 227 | "app-admin" : [ { 228 | "id" : "5a5e3740-2a0f-4e9a-a74f-2f5152f3c3d9", 229 | "name" : "admin", 230 | "composite" : true, 231 | "composites" : { 232 | "client" : { 233 | "app-todo" : [ "actuator" ] 234 | } 235 | }, 236 | "clientRole" : true, 237 | "containerId" : "5ea9cb3f-fc37-4e30-8809-60c6d8720ca4", 238 | "attributes" : { } 239 | }, { 240 | "id" : "62256203-31d3-428d-97fb-6727e798f52a", 241 | "name" : "actuator", 242 | "composite" : true, 243 | "composites" : { 244 | "client" : { 245 | "app-todo" : [ "actuator" ] 246 | } 247 | }, 248 | "clientRole" : true, 249 | "containerId" : "5ea9cb3f-fc37-4e30-8809-60c6d8720ca4", 250 | "attributes" : { } 251 | } ], 252 | "admin-cli" : [ ], 253 | "app-todo" : [ { 254 | "id" : "b190c0da-ee29-461a-b1b3-b964c28498a9", 255 | "name" : "user", 256 | "composite" : false, 257 | "clientRole" : true, 258 | "containerId" : "1330233a-ebc3-4a9d-ac4d-a1505b9f2afd", 259 | "attributes" : { } 260 | }, { 261 | "id" : "e9f1b0f4-9bc6-4eaf-a34c-746c22816b55", 262 | "name" : "actuator", 263 | "composite" : false, 264 | "clientRole" : true, 265 | "containerId" : "1330233a-ebc3-4a9d-ac4d-a1505b9f2afd", 266 | "attributes" : { } 267 | } ], 268 | "broker" : [ { 269 | "id" : "787b6781-b07b-4c07-b8fb-edfe29a9eecf", 270 | "name" : "read-token", 271 | "description" : "${role_read-token}", 272 | "composite" : false, 273 | "clientRole" : true, 274 | "containerId" : "1c66cf2f-6b95-4d32-bba6-f340368c0d62", 275 | "attributes" : { } 276 | } ], 277 | "account" : [ { 278 | "id" : "8f777533-54eb-4c00-b90b-55fd0c3eeacd", 279 | "name" : "manage-account", 280 | "description" : "${role_manage-account}", 281 | "composite" : true, 282 | "composites" : { 283 | "client" : { 284 | "account" : [ "manage-account-links" ] 285 | } 286 | }, 287 | "clientRole" : true, 288 | "containerId" : "e7b8feea-f561-4555-bd3f-64abb23fcdf1", 289 | "attributes" : { } 290 | }, { 291 | "id" : "25bc51d6-d7e8-4ccb-8363-03021d5b2010", 292 | "name" : "manage-account-links", 293 | "description" : "${role_manage-account-links}", 294 | "composite" : false, 295 | "clientRole" : true, 296 | "containerId" : "e7b8feea-f561-4555-bd3f-64abb23fcdf1", 297 | "attributes" : { } 298 | }, { 299 | "id" : "9268e01d-8906-4f6d-ada2-4dc541eedda1", 300 | "name" : "view-profile", 301 | "description" : "${role_view-profile}", 302 | "composite" : false, 303 | "clientRole" : true, 304 | "containerId" : "e7b8feea-f561-4555-bd3f-64abb23fcdf1", 305 | "attributes" : { } 306 | } ] 307 | } 308 | }, 309 | "groups" : [ ], 310 | "defaultRoles" : [ "uma_authorization", "offline_access" ], 311 | "requiredCredentials" : [ "password" ], 312 | "otpPolicyType" : "totp", 313 | "otpPolicyAlgorithm" : "HmacSHA1", 314 | "otpPolicyInitialCounter" : 0, 315 | "otpPolicyDigits" : 6, 316 | "otpPolicyLookAheadWindow" : 1, 317 | "otpPolicyPeriod" : 30, 318 | "otpSupportedApplications" : [ "FreeOTP", "Google Authenticator" ], 319 | "users" : [ { 320 | "id" : "8fd79665-4532-45e5-86a1-a0478b182211", 321 | "createdTimestamp" : 1527157168760, 322 | "username" : "service-account-app-admin", 323 | "enabled" : true, 324 | "totp" : false, 325 | "emailVerified" : false, 326 | "email" : "service-account-app-admin@placeholder.org", 327 | "serviceAccountClientId" : "app-admin", 328 | "credentials" : [ ], 329 | "disableableCredentialTypes" : [ ], 330 | "requiredActions" : [ ], 331 | "realmRoles" : [ "uma_authorization", "offline_access" ], 332 | "clientRoles" : { 333 | "app-admin" : [ "actuator" ], 334 | "account" : [ "manage-account", "view-profile" ] 335 | }, 336 | "notBefore" : 0, 337 | "groups" : [ ] 338 | }, { 339 | "id" : "34365502-984a-43d8-822b-83919eb6d55c", 340 | "createdTimestamp" : 1527155382298, 341 | "username" : "tester", 342 | "enabled" : true, 343 | "totp" : false, 344 | "emailVerified" : false, 345 | "firstName" : "Theo", 346 | "lastName" : "Tester", 347 | "email" : "tom+test@localhost", 348 | "credentials" : [ { 349 | "type" : "password", 350 | "hashedSaltedValue" : "u+b5GK1Rv/K83lWho8lVg5Cdpgut5MdMBxUBHY4a3/l46uRdAGj5+CkjuGaDy3kqz/J1U/3iXj/BYIcpwN5aJw==", 351 | "salt" : "aupp+K6EgbZStMoFct+IGQ==", 352 | "hashIterations" : 27500, 353 | "counter" : 0, 354 | "algorithm" : "pbkdf2-sha256", 355 | "digits" : 0, 356 | "period" : 0, 357 | "createdDate" : 1527155390114, 358 | "config" : { } 359 | } ], 360 | "disableableCredentialTypes" : [ "password" ], 361 | "requiredActions" : [ ], 362 | "realmRoles" : [ "uma_authorization", "offline_access" ], 363 | "clientRoles" : { 364 | "app-admin" : [ "admin" ], 365 | "account" : [ "manage-account", "view-profile" ] 366 | }, 367 | "notBefore" : 0, 368 | "groups" : [ ] 369 | } ], 370 | "scopeMappings" : [ { 371 | "clientScope" : "offline_access", 372 | "roles" : [ "offline_access" ] 373 | } ], 374 | "clients" : [ { 375 | "id" : "e7b8feea-f561-4555-bd3f-64abb23fcdf1", 376 | "clientId" : "account", 377 | "name" : "${client_account}", 378 | "baseUrl" : "/auth/realms/bootadmin/account", 379 | "surrogateAuthRequired" : false, 380 | "enabled" : true, 381 | "clientAuthenticatorType" : "client-secret", 382 | "secret" : "57feb045-1598-403a-a2ae-746db88e07e0", 383 | "defaultRoles" : [ "manage-account", "view-profile" ], 384 | "redirectUris" : [ "/auth/realms/bootadmin/account/*" ], 385 | "webOrigins" : [ ], 386 | "notBefore" : 0, 387 | "bearerOnly" : false, 388 | "consentRequired" : false, 389 | "standardFlowEnabled" : true, 390 | "implicitFlowEnabled" : false, 391 | "directAccessGrantsEnabled" : false, 392 | "serviceAccountsEnabled" : false, 393 | "publicClient" : false, 394 | "frontchannelLogout" : false, 395 | "protocol" : "openid-connect", 396 | "attributes" : { }, 397 | "authenticationFlowBindingOverrides" : { }, 398 | "fullScopeAllowed" : false, 399 | "nodeReRegistrationTimeout" : 0, 400 | "protocolMappers" : [ { 401 | "id" : "d93564c7-b847-403d-a1fc-fe954c3e57e0", 402 | "name" : "family name", 403 | "protocol" : "openid-connect", 404 | "protocolMapper" : "oidc-usermodel-property-mapper", 405 | "consentRequired" : false, 406 | "config" : { 407 | "userinfo.token.claim" : "true", 408 | "user.attribute" : "lastName", 409 | "id.token.claim" : "true", 410 | "access.token.claim" : "true", 411 | "claim.name" : "family_name", 412 | "jsonType.label" : "String" 413 | } 414 | }, { 415 | "id" : "30f30279-d6f4-49ee-ab7c-426572c70e13", 416 | "name" : "full name", 417 | "protocol" : "openid-connect", 418 | "protocolMapper" : "oidc-full-name-mapper", 419 | "consentRequired" : false, 420 | "config" : { 421 | "id.token.claim" : "true", 422 | "access.token.claim" : "true", 423 | "userinfo.token.claim" : "true" 424 | } 425 | }, { 426 | "id" : "9a071490-bc04-4128-841c-06fcb1d55849", 427 | "name" : "given name", 428 | "protocol" : "openid-connect", 429 | "protocolMapper" : "oidc-usermodel-property-mapper", 430 | "consentRequired" : false, 431 | "config" : { 432 | "userinfo.token.claim" : "true", 433 | "user.attribute" : "firstName", 434 | "id.token.claim" : "true", 435 | "access.token.claim" : "true", 436 | "claim.name" : "given_name", 437 | "jsonType.label" : "String" 438 | } 439 | }, { 440 | "id" : "fd2f17db-008d-4289-ab23-2de8cdb4a63b", 441 | "name" : "email", 442 | "protocol" : "openid-connect", 443 | "protocolMapper" : "oidc-usermodel-property-mapper", 444 | "consentRequired" : false, 445 | "config" : { 446 | "userinfo.token.claim" : "true", 447 | "user.attribute" : "email", 448 | "id.token.claim" : "true", 449 | "access.token.claim" : "true", 450 | "claim.name" : "email", 451 | "jsonType.label" : "String" 452 | } 453 | }, { 454 | "id" : "ee290255-2ec2-484c-9e35-94338a2d1a6c", 455 | "name" : "username", 456 | "protocol" : "openid-connect", 457 | "protocolMapper" : "oidc-usermodel-property-mapper", 458 | "consentRequired" : false, 459 | "config" : { 460 | "userinfo.token.claim" : "true", 461 | "user.attribute" : "username", 462 | "id.token.claim" : "true", 463 | "access.token.claim" : "true", 464 | "claim.name" : "preferred_username", 465 | "jsonType.label" : "String" 466 | } 467 | }, { 468 | "id" : "02aa7146-9607-40fb-b4f9-5165d3fd21c0", 469 | "name" : "role list", 470 | "protocol" : "saml", 471 | "protocolMapper" : "saml-role-list-mapper", 472 | "consentRequired" : false, 473 | "config" : { 474 | "single" : "false", 475 | "attribute.nameformat" : "Basic", 476 | "attribute.name" : "Role" 477 | } 478 | } ], 479 | "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], 480 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 481 | }, { 482 | "id" : "33ba643b-d507-49cc-9f47-20b4416c11f2", 483 | "clientId" : "admin-cli", 484 | "name" : "${client_admin-cli}", 485 | "surrogateAuthRequired" : false, 486 | "enabled" : true, 487 | "clientAuthenticatorType" : "client-secret", 488 | "secret" : "c224aead-e2f8-45d0-a813-898d3321b26d", 489 | "redirectUris" : [ ], 490 | "webOrigins" : [ ], 491 | "notBefore" : 0, 492 | "bearerOnly" : false, 493 | "consentRequired" : false, 494 | "standardFlowEnabled" : false, 495 | "implicitFlowEnabled" : false, 496 | "directAccessGrantsEnabled" : true, 497 | "serviceAccountsEnabled" : false, 498 | "publicClient" : true, 499 | "frontchannelLogout" : false, 500 | "protocol" : "openid-connect", 501 | "attributes" : { }, 502 | "authenticationFlowBindingOverrides" : { }, 503 | "fullScopeAllowed" : false, 504 | "nodeReRegistrationTimeout" : 0, 505 | "protocolMappers" : [ { 506 | "id" : "4d350084-282f-446d-b9f8-6f1f234f16c2", 507 | "name" : "family name", 508 | "protocol" : "openid-connect", 509 | "protocolMapper" : "oidc-usermodel-property-mapper", 510 | "consentRequired" : false, 511 | "config" : { 512 | "userinfo.token.claim" : "true", 513 | "user.attribute" : "lastName", 514 | "id.token.claim" : "true", 515 | "access.token.claim" : "true", 516 | "claim.name" : "family_name", 517 | "jsonType.label" : "String" 518 | } 519 | }, { 520 | "id" : "adad086e-b3b4-48b9-bf1e-83611cf32b5e", 521 | "name" : "full name", 522 | "protocol" : "openid-connect", 523 | "protocolMapper" : "oidc-full-name-mapper", 524 | "consentRequired" : false, 525 | "config" : { 526 | "id.token.claim" : "true", 527 | "access.token.claim" : "true", 528 | "userinfo.token.claim" : "true" 529 | } 530 | }, { 531 | "id" : "604f42fc-5312-47b8-8da9-7afd934afede", 532 | "name" : "email", 533 | "protocol" : "openid-connect", 534 | "protocolMapper" : "oidc-usermodel-property-mapper", 535 | "consentRequired" : false, 536 | "config" : { 537 | "userinfo.token.claim" : "true", 538 | "user.attribute" : "email", 539 | "id.token.claim" : "true", 540 | "access.token.claim" : "true", 541 | "claim.name" : "email", 542 | "jsonType.label" : "String" 543 | } 544 | }, { 545 | "id" : "8915095a-9c6c-4422-9f92-8f0159a73920", 546 | "name" : "given name", 547 | "protocol" : "openid-connect", 548 | "protocolMapper" : "oidc-usermodel-property-mapper", 549 | "consentRequired" : false, 550 | "config" : { 551 | "userinfo.token.claim" : "true", 552 | "user.attribute" : "firstName", 553 | "id.token.claim" : "true", 554 | "access.token.claim" : "true", 555 | "claim.name" : "given_name", 556 | "jsonType.label" : "String" 557 | } 558 | }, { 559 | "id" : "863cc7ee-235c-4f38-aee5-ff9f70b8ade8", 560 | "name" : "username", 561 | "protocol" : "openid-connect", 562 | "protocolMapper" : "oidc-usermodel-property-mapper", 563 | "consentRequired" : false, 564 | "config" : { 565 | "userinfo.token.claim" : "true", 566 | "user.attribute" : "username", 567 | "id.token.claim" : "true", 568 | "access.token.claim" : "true", 569 | "claim.name" : "preferred_username", 570 | "jsonType.label" : "String" 571 | } 572 | }, { 573 | "id" : "fd009a76-e567-4512-b56f-d61d9d39cf91", 574 | "name" : "role list", 575 | "protocol" : "saml", 576 | "protocolMapper" : "saml-role-list-mapper", 577 | "consentRequired" : false, 578 | "config" : { 579 | "single" : "false", 580 | "attribute.nameformat" : "Basic", 581 | "attribute.name" : "Role" 582 | } 583 | } ], 584 | "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], 585 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 586 | }, { 587 | "id" : "5ea9cb3f-fc37-4e30-8809-60c6d8720ca4", 588 | "clientId" : "app-admin", 589 | "name" : "Admin Server", 590 | "rootUrl" : "http://localhost:30001", 591 | "adminUrl" : "/", 592 | "baseUrl" : "/admin", 593 | "surrogateAuthRequired" : false, 594 | "enabled" : true, 595 | "clientAuthenticatorType" : "client-secret", 596 | "secret" : "97edad04-49ca-4770-8e4a-3bc97c1714ce", 597 | "redirectUris" : [ "/*" ], 598 | "webOrigins" : [ "+" ], 599 | "notBefore" : 0, 600 | "bearerOnly" : false, 601 | "consentRequired" : false, 602 | "standardFlowEnabled" : true, 603 | "implicitFlowEnabled" : false, 604 | "directAccessGrantsEnabled" : false, 605 | "serviceAccountsEnabled" : true, 606 | "publicClient" : false, 607 | "frontchannelLogout" : false, 608 | "protocol" : "openid-connect", 609 | "attributes" : { 610 | "saml.assertion.signature" : "false", 611 | "saml.force.post.binding" : "false", 612 | "saml.multivalued.roles" : "false", 613 | "saml.encrypt" : "false", 614 | "saml.server.signature" : "false", 615 | "saml.server.signature.keyinfo.ext" : "false", 616 | "exclude.session.state.from.auth.response" : "false", 617 | "saml_force_name_id_format" : "false", 618 | "saml.client.signature" : "false", 619 | "tls.client.certificate.bound.access.tokens" : "false", 620 | "saml.authnstatement" : "false", 621 | "display.on.consent.screen" : "false", 622 | "saml.onetimeuse.condition" : "false" 623 | }, 624 | "authenticationFlowBindingOverrides" : { }, 625 | "fullScopeAllowed" : true, 626 | "nodeReRegistrationTimeout" : -1, 627 | "protocolMappers" : [ { 628 | "id" : "97abf3a0-dc23-4bd7-bb4e-51922ee3e3bd", 629 | "name" : "role list", 630 | "protocol" : "saml", 631 | "protocolMapper" : "saml-role-list-mapper", 632 | "consentRequired" : false, 633 | "config" : { 634 | "single" : "false", 635 | "attribute.nameformat" : "Basic", 636 | "attribute.name" : "Role" 637 | } 638 | }, { 639 | "id" : "b506e20d-bf45-4f2a-a8b8-616ee0a22214", 640 | "name" : "username", 641 | "protocol" : "openid-connect", 642 | "protocolMapper" : "oidc-usermodel-property-mapper", 643 | "consentRequired" : false, 644 | "config" : { 645 | "userinfo.token.claim" : "true", 646 | "user.attribute" : "username", 647 | "id.token.claim" : "true", 648 | "access.token.claim" : "true", 649 | "claim.name" : "preferred_username", 650 | "jsonType.label" : "String" 651 | } 652 | }, { 653 | "id" : "1f1a339f-9705-4263-872e-69b423f33ce6", 654 | "name" : "Client ID", 655 | "protocol" : "openid-connect", 656 | "protocolMapper" : "oidc-usersessionmodel-note-mapper", 657 | "consentRequired" : false, 658 | "config" : { 659 | "user.session.note" : "clientId", 660 | "userinfo.token.claim" : "true", 661 | "id.token.claim" : "true", 662 | "access.token.claim" : "true", 663 | "claim.name" : "clientId", 664 | "jsonType.label" : "String" 665 | } 666 | }, { 667 | "id" : "0214c3e9-fb89-4125-bf46-ff5f0d78cdce", 668 | "name" : "given name", 669 | "protocol" : "openid-connect", 670 | "protocolMapper" : "oidc-usermodel-property-mapper", 671 | "consentRequired" : false, 672 | "config" : { 673 | "userinfo.token.claim" : "true", 674 | "user.attribute" : "firstName", 675 | "id.token.claim" : "true", 676 | "access.token.claim" : "true", 677 | "claim.name" : "given_name", 678 | "jsonType.label" : "String" 679 | } 680 | }, { 681 | "id" : "6fc90900-1fcb-4844-b6c7-92b1eaecdc8c", 682 | "name" : "Client IP Address", 683 | "protocol" : "openid-connect", 684 | "protocolMapper" : "oidc-usersessionmodel-note-mapper", 685 | "consentRequired" : false, 686 | "config" : { 687 | "user.session.note" : "clientAddress", 688 | "userinfo.token.claim" : "true", 689 | "id.token.claim" : "true", 690 | "access.token.claim" : "true", 691 | "claim.name" : "clientAddress", 692 | "jsonType.label" : "String" 693 | } 694 | }, { 695 | "id" : "b74cd919-e53c-4c00-9f6f-d04683fb871d", 696 | "name" : "full name", 697 | "protocol" : "openid-connect", 698 | "protocolMapper" : "oidc-full-name-mapper", 699 | "consentRequired" : false, 700 | "config" : { 701 | "id.token.claim" : "true", 702 | "access.token.claim" : "true", 703 | "userinfo.token.claim" : "true" 704 | } 705 | }, { 706 | "id" : "5a8421ec-4b40-40ce-a4a9-709e303a769f", 707 | "name" : "Client Host", 708 | "protocol" : "openid-connect", 709 | "protocolMapper" : "oidc-usersessionmodel-note-mapper", 710 | "consentRequired" : false, 711 | "config" : { 712 | "user.session.note" : "clientHost", 713 | "userinfo.token.claim" : "true", 714 | "id.token.claim" : "true", 715 | "access.token.claim" : "true", 716 | "claim.name" : "clientHost", 717 | "jsonType.label" : "String" 718 | } 719 | }, { 720 | "id" : "35aa0c1c-ade9-47bf-91d8-b3aa65fb1f3b", 721 | "name" : "email", 722 | "protocol" : "openid-connect", 723 | "protocolMapper" : "oidc-usermodel-property-mapper", 724 | "consentRequired" : false, 725 | "config" : { 726 | "userinfo.token.claim" : "true", 727 | "user.attribute" : "email", 728 | "id.token.claim" : "true", 729 | "access.token.claim" : "true", 730 | "claim.name" : "email", 731 | "jsonType.label" : "String" 732 | } 733 | }, { 734 | "id" : "c13c0479-fcd5-4414-a865-44137fb10d5b", 735 | "name" : "family name", 736 | "protocol" : "openid-connect", 737 | "protocolMapper" : "oidc-usermodel-property-mapper", 738 | "consentRequired" : false, 739 | "config" : { 740 | "userinfo.token.claim" : "true", 741 | "user.attribute" : "lastName", 742 | "id.token.claim" : "true", 743 | "access.token.claim" : "true", 744 | "claim.name" : "family_name", 745 | "jsonType.label" : "String" 746 | } 747 | } ], 748 | "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], 749 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 750 | }, { 751 | "id" : "1330233a-ebc3-4a9d-ac4d-a1505b9f2afd", 752 | "clientId" : "app-todo", 753 | "name" : "Todos", 754 | "rootUrl" : "http://localhost:30002", 755 | "adminUrl" : "/", 756 | "baseUrl" : "/", 757 | "surrogateAuthRequired" : false, 758 | "enabled" : true, 759 | "clientAuthenticatorType" : "client-secret", 760 | "secret" : "2cc653a3-24cc-4241-896d-813a726f9b33", 761 | "redirectUris" : [ "/*" ], 762 | "webOrigins" : [ "+" ], 763 | "notBefore" : 0, 764 | "bearerOnly" : false, 765 | "consentRequired" : false, 766 | "standardFlowEnabled" : true, 767 | "implicitFlowEnabled" : false, 768 | "directAccessGrantsEnabled" : false, 769 | "serviceAccountsEnabled" : false, 770 | "publicClient" : false, 771 | "frontchannelLogout" : false, 772 | "protocol" : "openid-connect", 773 | "attributes" : { 774 | "saml.assertion.signature" : "false", 775 | "saml.force.post.binding" : "false", 776 | "saml.multivalued.roles" : "false", 777 | "saml.encrypt" : "false", 778 | "saml.server.signature" : "false", 779 | "saml.server.signature.keyinfo.ext" : "false", 780 | "exclude.session.state.from.auth.response" : "false", 781 | "saml_force_name_id_format" : "false", 782 | "saml.client.signature" : "false", 783 | "tls.client.certificate.bound.access.tokens" : "false", 784 | "saml.authnstatement" : "false", 785 | "display.on.consent.screen" : "false", 786 | "saml.onetimeuse.condition" : "false" 787 | }, 788 | "authenticationFlowBindingOverrides" : { }, 789 | "fullScopeAllowed" : true, 790 | "nodeReRegistrationTimeout" : -1, 791 | "protocolMappers" : [ { 792 | "id" : "ddbd0a9c-69d5-445b-8ba8-51559d556d96", 793 | "name" : "username", 794 | "protocol" : "openid-connect", 795 | "protocolMapper" : "oidc-usermodel-property-mapper", 796 | "consentRequired" : false, 797 | "config" : { 798 | "userinfo.token.claim" : "true", 799 | "user.attribute" : "username", 800 | "id.token.claim" : "true", 801 | "access.token.claim" : "true", 802 | "claim.name" : "preferred_username", 803 | "jsonType.label" : "String" 804 | } 805 | }, { 806 | "id" : "9db7566a-c845-4f6f-94be-1989efed8ba1", 807 | "name" : "given name", 808 | "protocol" : "openid-connect", 809 | "protocolMapper" : "oidc-usermodel-property-mapper", 810 | "consentRequired" : false, 811 | "config" : { 812 | "userinfo.token.claim" : "true", 813 | "user.attribute" : "firstName", 814 | "id.token.claim" : "true", 815 | "access.token.claim" : "true", 816 | "claim.name" : "given_name", 817 | "jsonType.label" : "String" 818 | } 819 | }, { 820 | "id" : "5256aa84-f792-4d39-87bb-d2183d1e25a5", 821 | "name" : "role list", 822 | "protocol" : "saml", 823 | "protocolMapper" : "saml-role-list-mapper", 824 | "consentRequired" : false, 825 | "config" : { 826 | "single" : "false", 827 | "attribute.nameformat" : "Basic", 828 | "attribute.name" : "Role" 829 | } 830 | }, { 831 | "id" : "5911b290-537e-4027-afdf-a392b3c9da39", 832 | "name" : "full name", 833 | "protocol" : "openid-connect", 834 | "protocolMapper" : "oidc-full-name-mapper", 835 | "consentRequired" : false, 836 | "config" : { 837 | "id.token.claim" : "true", 838 | "access.token.claim" : "true", 839 | "userinfo.token.claim" : "true" 840 | } 841 | }, { 842 | "id" : "0c04711a-191b-49a6-aea3-7198fc94d8de", 843 | "name" : "email", 844 | "protocol" : "openid-connect", 845 | "protocolMapper" : "oidc-usermodel-property-mapper", 846 | "consentRequired" : false, 847 | "config" : { 848 | "userinfo.token.claim" : "true", 849 | "user.attribute" : "email", 850 | "id.token.claim" : "true", 851 | "access.token.claim" : "true", 852 | "claim.name" : "email", 853 | "jsonType.label" : "String" 854 | } 855 | }, { 856 | "id" : "5e11119f-e3a7-4d6d-9fa9-7ecae0748418", 857 | "name" : "family name", 858 | "protocol" : "openid-connect", 859 | "protocolMapper" : "oidc-usermodel-property-mapper", 860 | "consentRequired" : false, 861 | "config" : { 862 | "userinfo.token.claim" : "true", 863 | "user.attribute" : "lastName", 864 | "id.token.claim" : "true", 865 | "access.token.claim" : "true", 866 | "claim.name" : "family_name", 867 | "jsonType.label" : "String" 868 | } 869 | } ], 870 | "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], 871 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 872 | }, { 873 | "id" : "1c66cf2f-6b95-4d32-bba6-f340368c0d62", 874 | "clientId" : "broker", 875 | "name" : "${client_broker}", 876 | "surrogateAuthRequired" : false, 877 | "enabled" : true, 878 | "clientAuthenticatorType" : "client-secret", 879 | "secret" : "b321dd13-c1a8-4523-b320-3f9d972688b3", 880 | "redirectUris" : [ ], 881 | "webOrigins" : [ ], 882 | "notBefore" : 0, 883 | "bearerOnly" : false, 884 | "consentRequired" : false, 885 | "standardFlowEnabled" : true, 886 | "implicitFlowEnabled" : false, 887 | "directAccessGrantsEnabled" : false, 888 | "serviceAccountsEnabled" : false, 889 | "publicClient" : false, 890 | "frontchannelLogout" : false, 891 | "protocol" : "openid-connect", 892 | "attributes" : { }, 893 | "authenticationFlowBindingOverrides" : { }, 894 | "fullScopeAllowed" : false, 895 | "nodeReRegistrationTimeout" : 0, 896 | "protocolMappers" : [ { 897 | "id" : "ff166ffe-7e9a-45f5-abf5-42f515f8f3e5", 898 | "name" : "given name", 899 | "protocol" : "openid-connect", 900 | "protocolMapper" : "oidc-usermodel-property-mapper", 901 | "consentRequired" : false, 902 | "config" : { 903 | "userinfo.token.claim" : "true", 904 | "user.attribute" : "firstName", 905 | "id.token.claim" : "true", 906 | "access.token.claim" : "true", 907 | "claim.name" : "given_name", 908 | "jsonType.label" : "String" 909 | } 910 | }, { 911 | "id" : "ff81dd99-d18d-46e6-86a8-5e56f3dcfa3a", 912 | "name" : "email", 913 | "protocol" : "openid-connect", 914 | "protocolMapper" : "oidc-usermodel-property-mapper", 915 | "consentRequired" : false, 916 | "config" : { 917 | "userinfo.token.claim" : "true", 918 | "user.attribute" : "email", 919 | "id.token.claim" : "true", 920 | "access.token.claim" : "true", 921 | "claim.name" : "email", 922 | "jsonType.label" : "String" 923 | } 924 | }, { 925 | "id" : "789faf1e-fb11-4e0b-9945-cfb71484d3e2", 926 | "name" : "full name", 927 | "protocol" : "openid-connect", 928 | "protocolMapper" : "oidc-full-name-mapper", 929 | "consentRequired" : false, 930 | "config" : { 931 | "id.token.claim" : "true", 932 | "access.token.claim" : "true", 933 | "userinfo.token.claim" : "true" 934 | } 935 | }, { 936 | "id" : "28095876-c419-47f4-85f5-cea014b593f5", 937 | "name" : "family name", 938 | "protocol" : "openid-connect", 939 | "protocolMapper" : "oidc-usermodel-property-mapper", 940 | "consentRequired" : false, 941 | "config" : { 942 | "userinfo.token.claim" : "true", 943 | "user.attribute" : "lastName", 944 | "id.token.claim" : "true", 945 | "access.token.claim" : "true", 946 | "claim.name" : "family_name", 947 | "jsonType.label" : "String" 948 | } 949 | }, { 950 | "id" : "06d6f324-33c7-4b1a-96e8-c5367a6f8302", 951 | "name" : "role list", 952 | "protocol" : "saml", 953 | "protocolMapper" : "saml-role-list-mapper", 954 | "consentRequired" : false, 955 | "config" : { 956 | "single" : "false", 957 | "attribute.nameformat" : "Basic", 958 | "attribute.name" : "Role" 959 | } 960 | }, { 961 | "id" : "c1a510ed-05fb-4a45-9f9f-58104d27f56c", 962 | "name" : "username", 963 | "protocol" : "openid-connect", 964 | "protocolMapper" : "oidc-usermodel-property-mapper", 965 | "consentRequired" : false, 966 | "config" : { 967 | "userinfo.token.claim" : "true", 968 | "user.attribute" : "username", 969 | "id.token.claim" : "true", 970 | "access.token.claim" : "true", 971 | "claim.name" : "preferred_username", 972 | "jsonType.label" : "String" 973 | } 974 | } ], 975 | "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], 976 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 977 | }, { 978 | "id" : "7155f9df-a0a7-40d0-81b3-53824d2bf7e6", 979 | "clientId" : "realm-management", 980 | "name" : "${client_realm-management}", 981 | "surrogateAuthRequired" : false, 982 | "enabled" : true, 983 | "clientAuthenticatorType" : "client-secret", 984 | "secret" : "07951343-dd29-473a-abb7-090cc4f17d8e", 985 | "redirectUris" : [ ], 986 | "webOrigins" : [ ], 987 | "notBefore" : 0, 988 | "bearerOnly" : true, 989 | "consentRequired" : false, 990 | "standardFlowEnabled" : true, 991 | "implicitFlowEnabled" : false, 992 | "directAccessGrantsEnabled" : false, 993 | "serviceAccountsEnabled" : false, 994 | "publicClient" : false, 995 | "frontchannelLogout" : false, 996 | "protocol" : "openid-connect", 997 | "attributes" : { }, 998 | "authenticationFlowBindingOverrides" : { }, 999 | "fullScopeAllowed" : false, 1000 | "nodeReRegistrationTimeout" : 0, 1001 | "protocolMappers" : [ { 1002 | "id" : "2d59605f-9f4f-47b1-9282-10280ed02012", 1003 | "name" : "role list", 1004 | "protocol" : "saml", 1005 | "protocolMapper" : "saml-role-list-mapper", 1006 | "consentRequired" : false, 1007 | "config" : { 1008 | "single" : "false", 1009 | "attribute.nameformat" : "Basic", 1010 | "attribute.name" : "Role" 1011 | } 1012 | }, { 1013 | "id" : "f3cbec6f-d30b-46e6-9ebc-74f238271818", 1014 | "name" : "family name", 1015 | "protocol" : "openid-connect", 1016 | "protocolMapper" : "oidc-usermodel-property-mapper", 1017 | "consentRequired" : false, 1018 | "config" : { 1019 | "userinfo.token.claim" : "true", 1020 | "user.attribute" : "lastName", 1021 | "id.token.claim" : "true", 1022 | "access.token.claim" : "true", 1023 | "claim.name" : "family_name", 1024 | "jsonType.label" : "String" 1025 | } 1026 | }, { 1027 | "id" : "b3ad882d-db2f-4779-b43c-861a79089c89", 1028 | "name" : "email", 1029 | "protocol" : "openid-connect", 1030 | "protocolMapper" : "oidc-usermodel-property-mapper", 1031 | "consentRequired" : false, 1032 | "config" : { 1033 | "userinfo.token.claim" : "true", 1034 | "user.attribute" : "email", 1035 | "id.token.claim" : "true", 1036 | "access.token.claim" : "true", 1037 | "claim.name" : "email", 1038 | "jsonType.label" : "String" 1039 | } 1040 | }, { 1041 | "id" : "69fadea3-60d4-4507-9367-e50bb66d8609", 1042 | "name" : "full name", 1043 | "protocol" : "openid-connect", 1044 | "protocolMapper" : "oidc-full-name-mapper", 1045 | "consentRequired" : false, 1046 | "config" : { 1047 | "id.token.claim" : "true", 1048 | "access.token.claim" : "true", 1049 | "userinfo.token.claim" : "true" 1050 | } 1051 | }, { 1052 | "id" : "f40471ec-111a-4d4b-ad2a-4caaf1bca912", 1053 | "name" : "username", 1054 | "protocol" : "openid-connect", 1055 | "protocolMapper" : "oidc-usermodel-property-mapper", 1056 | "consentRequired" : false, 1057 | "config" : { 1058 | "userinfo.token.claim" : "true", 1059 | "user.attribute" : "username", 1060 | "id.token.claim" : "true", 1061 | "access.token.claim" : "true", 1062 | "claim.name" : "preferred_username", 1063 | "jsonType.label" : "String" 1064 | } 1065 | }, { 1066 | "id" : "dfc548d8-0d84-4796-bb95-1fc7af320b79", 1067 | "name" : "given name", 1068 | "protocol" : "openid-connect", 1069 | "protocolMapper" : "oidc-usermodel-property-mapper", 1070 | "consentRequired" : false, 1071 | "config" : { 1072 | "userinfo.token.claim" : "true", 1073 | "user.attribute" : "firstName", 1074 | "id.token.claim" : "true", 1075 | "access.token.claim" : "true", 1076 | "claim.name" : "given_name", 1077 | "jsonType.label" : "String" 1078 | } 1079 | } ], 1080 | "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], 1081 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 1082 | }, { 1083 | "id" : "860ac490-3d24-487a-94a0-41e777b8762f", 1084 | "clientId" : "security-admin-console", 1085 | "name" : "${client_security-admin-console}", 1086 | "baseUrl" : "/auth/admin/bootadmin/console/index.html", 1087 | "surrogateAuthRequired" : false, 1088 | "enabled" : true, 1089 | "clientAuthenticatorType" : "client-secret", 1090 | "secret" : "0606a283-92f2-454a-98ba-f4050b420b3f", 1091 | "redirectUris" : [ "/auth/admin/bootadmin/console/*" ], 1092 | "webOrigins" : [ ], 1093 | "notBefore" : 0, 1094 | "bearerOnly" : false, 1095 | "consentRequired" : false, 1096 | "standardFlowEnabled" : true, 1097 | "implicitFlowEnabled" : false, 1098 | "directAccessGrantsEnabled" : false, 1099 | "serviceAccountsEnabled" : false, 1100 | "publicClient" : true, 1101 | "frontchannelLogout" : false, 1102 | "protocol" : "openid-connect", 1103 | "attributes" : { }, 1104 | "authenticationFlowBindingOverrides" : { }, 1105 | "fullScopeAllowed" : false, 1106 | "nodeReRegistrationTimeout" : 0, 1107 | "protocolMappers" : [ { 1108 | "id" : "3fcc8da1-0531-4072-ac52-54faa6eb33ba", 1109 | "name" : "family name", 1110 | "protocol" : "openid-connect", 1111 | "protocolMapper" : "oidc-usermodel-property-mapper", 1112 | "consentRequired" : false, 1113 | "config" : { 1114 | "userinfo.token.claim" : "true", 1115 | "user.attribute" : "lastName", 1116 | "id.token.claim" : "true", 1117 | "access.token.claim" : "true", 1118 | "claim.name" : "family_name", 1119 | "jsonType.label" : "String" 1120 | } 1121 | }, { 1122 | "id" : "796ef4be-eb8f-4d1c-a9b4-9eda86d0e234", 1123 | "name" : "locale", 1124 | "protocol" : "openid-connect", 1125 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 1126 | "consentRequired" : false, 1127 | "config" : { 1128 | "userinfo.token.claim" : "true", 1129 | "user.attribute" : "locale", 1130 | "id.token.claim" : "true", 1131 | "access.token.claim" : "true", 1132 | "claim.name" : "locale", 1133 | "jsonType.label" : "String" 1134 | } 1135 | }, { 1136 | "id" : "264520ae-91e4-45dc-bf0d-6d444752648e", 1137 | "name" : "username", 1138 | "protocol" : "openid-connect", 1139 | "protocolMapper" : "oidc-usermodel-property-mapper", 1140 | "consentRequired" : false, 1141 | "config" : { 1142 | "userinfo.token.claim" : "true", 1143 | "user.attribute" : "username", 1144 | "id.token.claim" : "true", 1145 | "access.token.claim" : "true", 1146 | "claim.name" : "preferred_username", 1147 | "jsonType.label" : "String" 1148 | } 1149 | }, { 1150 | "id" : "52b7bef7-f4cf-445a-b252-bffc47207d1a", 1151 | "name" : "full name", 1152 | "protocol" : "openid-connect", 1153 | "protocolMapper" : "oidc-full-name-mapper", 1154 | "consentRequired" : false, 1155 | "config" : { 1156 | "id.token.claim" : "true", 1157 | "access.token.claim" : "true", 1158 | "userinfo.token.claim" : "true" 1159 | } 1160 | }, { 1161 | "id" : "66608a22-7f99-4afc-a9ab-dfdfab6a6b69", 1162 | "name" : "email", 1163 | "protocol" : "openid-connect", 1164 | "protocolMapper" : "oidc-usermodel-property-mapper", 1165 | "consentRequired" : false, 1166 | "config" : { 1167 | "userinfo.token.claim" : "true", 1168 | "user.attribute" : "email", 1169 | "id.token.claim" : "true", 1170 | "access.token.claim" : "true", 1171 | "claim.name" : "email", 1172 | "jsonType.label" : "String" 1173 | } 1174 | }, { 1175 | "id" : "3412e844-fd6a-406d-bec2-ba36b57807e9", 1176 | "name" : "role list", 1177 | "protocol" : "saml", 1178 | "protocolMapper" : "saml-role-list-mapper", 1179 | "consentRequired" : false, 1180 | "config" : { 1181 | "single" : "false", 1182 | "attribute.nameformat" : "Basic", 1183 | "attribute.name" : "Role" 1184 | } 1185 | }, { 1186 | "id" : "ddac44ca-e487-4436-acea-76b396bc5ffc", 1187 | "name" : "given name", 1188 | "protocol" : "openid-connect", 1189 | "protocolMapper" : "oidc-usermodel-property-mapper", 1190 | "consentRequired" : false, 1191 | "config" : { 1192 | "userinfo.token.claim" : "true", 1193 | "user.attribute" : "firstName", 1194 | "id.token.claim" : "true", 1195 | "access.token.claim" : "true", 1196 | "claim.name" : "given_name", 1197 | "jsonType.label" : "String" 1198 | } 1199 | } ], 1200 | "defaultClientScopes" : [ "web-origins", "role_list", "profile", "roles", "email" ], 1201 | "optionalClientScopes" : [ "address", "phone", "offline_access" ] 1202 | } ], 1203 | "clientScopes" : [ { 1204 | "id" : "d372d4d4-5c3c-4801-8729-67531b4fa4f0", 1205 | "name" : "address", 1206 | "description" : "OpenID Connect built-in scope: address", 1207 | "protocol" : "openid-connect", 1208 | "attributes" : { 1209 | "include.in.token.scope" : "true", 1210 | "display.on.consent.screen" : "true", 1211 | "consent.screen.text" : "${addressScopeConsentText}" 1212 | }, 1213 | "protocolMappers" : [ { 1214 | "id" : "ba70e536-0269-4639-b997-14d21d9ba871", 1215 | "name" : "address", 1216 | "protocol" : "openid-connect", 1217 | "protocolMapper" : "oidc-address-mapper", 1218 | "consentRequired" : false, 1219 | "config" : { 1220 | "user.attribute.formatted" : "formatted", 1221 | "user.attribute.country" : "country", 1222 | "user.attribute.postal_code" : "postal_code", 1223 | "userinfo.token.claim" : "true", 1224 | "user.attribute.street" : "street", 1225 | "id.token.claim" : "true", 1226 | "user.attribute.region" : "region", 1227 | "access.token.claim" : "true", 1228 | "user.attribute.locality" : "locality" 1229 | } 1230 | } ] 1231 | }, { 1232 | "id" : "b0f5b148-1cca-4c4d-b4b6-d4925ba6d196", 1233 | "name" : "email", 1234 | "description" : "OpenID Connect built-in scope: email", 1235 | "protocol" : "openid-connect", 1236 | "attributes" : { 1237 | "include.in.token.scope" : "true", 1238 | "display.on.consent.screen" : "true", 1239 | "consent.screen.text" : "${emailScopeConsentText}" 1240 | }, 1241 | "protocolMappers" : [ { 1242 | "id" : "50e26d09-f061-4544-b481-87c7f0a9f4d7", 1243 | "name" : "email verified", 1244 | "protocol" : "openid-connect", 1245 | "protocolMapper" : "oidc-usermodel-property-mapper", 1246 | "consentRequired" : false, 1247 | "config" : { 1248 | "userinfo.token.claim" : "true", 1249 | "user.attribute" : "emailVerified", 1250 | "id.token.claim" : "true", 1251 | "access.token.claim" : "true", 1252 | "claim.name" : "email_verified", 1253 | "jsonType.label" : "boolean" 1254 | } 1255 | }, { 1256 | "id" : "90f5419d-5908-4cc1-a4cf-98ce4ad308d3", 1257 | "name" : "email", 1258 | "protocol" : "openid-connect", 1259 | "protocolMapper" : "oidc-usermodel-property-mapper", 1260 | "consentRequired" : false, 1261 | "config" : { 1262 | "userinfo.token.claim" : "true", 1263 | "user.attribute" : "email", 1264 | "id.token.claim" : "true", 1265 | "access.token.claim" : "true", 1266 | "claim.name" : "email", 1267 | "jsonType.label" : "String" 1268 | } 1269 | } ] 1270 | }, { 1271 | "id" : "861d3152-95c4-49a5-9106-b7210e0927ed", 1272 | "name" : "offline_access", 1273 | "description" : "OpenID Connect built-in scope: offline_access", 1274 | "protocol" : "openid-connect", 1275 | "attributes" : { 1276 | "consent.screen.text" : "${offlineAccessScopeConsentText}", 1277 | "display.on.consent.screen" : "true" 1278 | } 1279 | }, { 1280 | "id" : "d7381441-6c76-4625-ac0a-82d052fa797f", 1281 | "name" : "phone", 1282 | "description" : "OpenID Connect built-in scope: phone", 1283 | "protocol" : "openid-connect", 1284 | "attributes" : { 1285 | "include.in.token.scope" : "true", 1286 | "display.on.consent.screen" : "true", 1287 | "consent.screen.text" : "${phoneScopeConsentText}" 1288 | }, 1289 | "protocolMappers" : [ { 1290 | "id" : "23fec1f1-a87b-4ed5-8297-17a6ec7483f9", 1291 | "name" : "phone number", 1292 | "protocol" : "openid-connect", 1293 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 1294 | "consentRequired" : false, 1295 | "config" : { 1296 | "userinfo.token.claim" : "true", 1297 | "user.attribute" : "phoneNumber", 1298 | "id.token.claim" : "true", 1299 | "access.token.claim" : "true", 1300 | "claim.name" : "phone_number", 1301 | "jsonType.label" : "String" 1302 | } 1303 | }, { 1304 | "id" : "aa30dd9a-9c50-45c7-a233-3c822e6f0ce3", 1305 | "name" : "phone number verified", 1306 | "protocol" : "openid-connect", 1307 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 1308 | "consentRequired" : false, 1309 | "config" : { 1310 | "userinfo.token.claim" : "true", 1311 | "user.attribute" : "phoneNumberVerified", 1312 | "id.token.claim" : "true", 1313 | "access.token.claim" : "true", 1314 | "claim.name" : "phone_number_verified", 1315 | "jsonType.label" : "boolean" 1316 | } 1317 | } ] 1318 | }, { 1319 | "id" : "c2deddd4-52d6-4583-9770-ee198f8434fe", 1320 | "name" : "profile", 1321 | "description" : "OpenID Connect built-in scope: profile", 1322 | "protocol" : "openid-connect", 1323 | "attributes" : { 1324 | "include.in.token.scope" : "true", 1325 | "display.on.consent.screen" : "true", 1326 | "consent.screen.text" : "${profileScopeConsentText}" 1327 | }, 1328 | "protocolMappers" : [ { 1329 | "id" : "978dc3f2-9844-457f-8d6e-9b1e7566e0d3", 1330 | "name" : "updated at", 1331 | "protocol" : "openid-connect", 1332 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 1333 | "consentRequired" : false, 1334 | "config" : { 1335 | "userinfo.token.claim" : "true", 1336 | "user.attribute" : "updatedAt", 1337 | "id.token.claim" : "true", 1338 | "access.token.claim" : "true", 1339 | "claim.name" : "updated_at", 1340 | "jsonType.label" : "String" 1341 | } 1342 | }, { 1343 | "id" : "a0165ec1-fb3c-4671-b0a8-7d70afd1850c", 1344 | "name" : "family name", 1345 | "protocol" : "openid-connect", 1346 | "protocolMapper" : "oidc-usermodel-property-mapper", 1347 | "consentRequired" : false, 1348 | "config" : { 1349 | "userinfo.token.claim" : "true", 1350 | "user.attribute" : "lastName", 1351 | "id.token.claim" : "true", 1352 | "access.token.claim" : "true", 1353 | "claim.name" : "family_name", 1354 | "jsonType.label" : "String" 1355 | } 1356 | }, { 1357 | "id" : "823d6c4c-20d1-48df-93ac-09197a8f109c", 1358 | "name" : "middle name", 1359 | "protocol" : "openid-connect", 1360 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 1361 | "consentRequired" : false, 1362 | "config" : { 1363 | "userinfo.token.claim" : "true", 1364 | "user.attribute" : "middleName", 1365 | "id.token.claim" : "true", 1366 | "access.token.claim" : "true", 1367 | "claim.name" : "middle_name", 1368 | "jsonType.label" : "String" 1369 | } 1370 | }, { 1371 | "id" : "d18fec8a-4ad3-40f9-8cbf-3addeaf5232f", 1372 | "name" : "website", 1373 | "protocol" : "openid-connect", 1374 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 1375 | "consentRequired" : false, 1376 | "config" : { 1377 | "userinfo.token.claim" : "true", 1378 | "user.attribute" : "website", 1379 | "id.token.claim" : "true", 1380 | "access.token.claim" : "true", 1381 | "claim.name" : "website", 1382 | "jsonType.label" : "String" 1383 | } 1384 | }, { 1385 | "id" : "2b6d20b4-9360-4740-8c18-6c53ea67b96c", 1386 | "name" : "profile", 1387 | "protocol" : "openid-connect", 1388 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 1389 | "consentRequired" : false, 1390 | "config" : { 1391 | "userinfo.token.claim" : "true", 1392 | "user.attribute" : "profile", 1393 | "id.token.claim" : "true", 1394 | "access.token.claim" : "true", 1395 | "claim.name" : "profile", 1396 | "jsonType.label" : "String" 1397 | } 1398 | }, { 1399 | "id" : "466ac067-dd33-44e5-b701-111c9014b7d6", 1400 | "name" : "locale", 1401 | "protocol" : "openid-connect", 1402 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 1403 | "consentRequired" : false, 1404 | "config" : { 1405 | "userinfo.token.claim" : "true", 1406 | "user.attribute" : "locale", 1407 | "id.token.claim" : "true", 1408 | "access.token.claim" : "true", 1409 | "claim.name" : "locale", 1410 | "jsonType.label" : "String" 1411 | } 1412 | }, { 1413 | "id" : "d6be8ea5-ceb9-43ad-b43f-051f2e7abc19", 1414 | "name" : "username", 1415 | "protocol" : "openid-connect", 1416 | "protocolMapper" : "oidc-usermodel-property-mapper", 1417 | "consentRequired" : false, 1418 | "config" : { 1419 | "userinfo.token.claim" : "true", 1420 | "user.attribute" : "username", 1421 | "id.token.claim" : "true", 1422 | "access.token.claim" : "true", 1423 | "claim.name" : "preferred_username", 1424 | "jsonType.label" : "String" 1425 | } 1426 | }, { 1427 | "id" : "7596da39-f8ec-4451-be12-5aad3c6b6e50", 1428 | "name" : "given name", 1429 | "protocol" : "openid-connect", 1430 | "protocolMapper" : "oidc-usermodel-property-mapper", 1431 | "consentRequired" : false, 1432 | "config" : { 1433 | "userinfo.token.claim" : "true", 1434 | "user.attribute" : "firstName", 1435 | "id.token.claim" : "true", 1436 | "access.token.claim" : "true", 1437 | "claim.name" : "given_name", 1438 | "jsonType.label" : "String" 1439 | } 1440 | }, { 1441 | "id" : "31d83f6b-f077-4908-bc84-54cacce02df4", 1442 | "name" : "full name", 1443 | "protocol" : "openid-connect", 1444 | "protocolMapper" : "oidc-full-name-mapper", 1445 | "consentRequired" : false, 1446 | "config" : { 1447 | "id.token.claim" : "true", 1448 | "access.token.claim" : "true", 1449 | "userinfo.token.claim" : "true" 1450 | } 1451 | }, { 1452 | "id" : "bd7d71b1-0bda-4626-86db-e7c9a9a462cb", 1453 | "name" : "nickname", 1454 | "protocol" : "openid-connect", 1455 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 1456 | "consentRequired" : false, 1457 | "config" : { 1458 | "userinfo.token.claim" : "true", 1459 | "user.attribute" : "nickname", 1460 | "id.token.claim" : "true", 1461 | "access.token.claim" : "true", 1462 | "claim.name" : "nickname", 1463 | "jsonType.label" : "String" 1464 | } 1465 | }, { 1466 | "id" : "8b62e000-71f7-4036-a511-f5be4c496840", 1467 | "name" : "picture", 1468 | "protocol" : "openid-connect", 1469 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 1470 | "consentRequired" : false, 1471 | "config" : { 1472 | "userinfo.token.claim" : "true", 1473 | "user.attribute" : "picture", 1474 | "id.token.claim" : "true", 1475 | "access.token.claim" : "true", 1476 | "claim.name" : "picture", 1477 | "jsonType.label" : "String" 1478 | } 1479 | }, { 1480 | "id" : "8021d664-20e0-40d8-b2e0-74a8d4a53379", 1481 | "name" : "gender", 1482 | "protocol" : "openid-connect", 1483 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 1484 | "consentRequired" : false, 1485 | "config" : { 1486 | "userinfo.token.claim" : "true", 1487 | "user.attribute" : "gender", 1488 | "id.token.claim" : "true", 1489 | "access.token.claim" : "true", 1490 | "claim.name" : "gender", 1491 | "jsonType.label" : "String" 1492 | } 1493 | }, { 1494 | "id" : "70cb60c1-6826-4dcc-80c0-fd8b289753b8", 1495 | "name" : "zoneinfo", 1496 | "protocol" : "openid-connect", 1497 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 1498 | "consentRequired" : false, 1499 | "config" : { 1500 | "userinfo.token.claim" : "true", 1501 | "user.attribute" : "zoneinfo", 1502 | "id.token.claim" : "true", 1503 | "access.token.claim" : "true", 1504 | "claim.name" : "zoneinfo", 1505 | "jsonType.label" : "String" 1506 | } 1507 | }, { 1508 | "id" : "ae8619be-28d7-4ff0-b4a0-9e3904dd3374", 1509 | "name" : "birthdate", 1510 | "protocol" : "openid-connect", 1511 | "protocolMapper" : "oidc-usermodel-attribute-mapper", 1512 | "consentRequired" : false, 1513 | "config" : { 1514 | "userinfo.token.claim" : "true", 1515 | "user.attribute" : "birthdate", 1516 | "id.token.claim" : "true", 1517 | "access.token.claim" : "true", 1518 | "claim.name" : "birthdate", 1519 | "jsonType.label" : "String" 1520 | } 1521 | } ] 1522 | }, { 1523 | "id" : "e60f3ae8-51ce-4b59-a97a-3ac45353a83d", 1524 | "name" : "role_list", 1525 | "description" : "SAML role list", 1526 | "protocol" : "saml", 1527 | "attributes" : { 1528 | "consent.screen.text" : "${samlRoleListScopeConsentText}", 1529 | "display.on.consent.screen" : "true" 1530 | }, 1531 | "protocolMappers" : [ { 1532 | "id" : "cecb60ca-ff19-4de8-ad66-147f54d148d1", 1533 | "name" : "role list", 1534 | "protocol" : "saml", 1535 | "protocolMapper" : "saml-role-list-mapper", 1536 | "consentRequired" : false, 1537 | "config" : { 1538 | "single" : "false", 1539 | "attribute.nameformat" : "Basic", 1540 | "attribute.name" : "Role" 1541 | } 1542 | } ] 1543 | }, { 1544 | "id" : "3109a5ce-47ee-4e88-ace6-efc5f9cba333", 1545 | "name" : "roles", 1546 | "description" : "OpenID Connect scope for add user roles to the access token", 1547 | "protocol" : "openid-connect", 1548 | "attributes" : { 1549 | "include.in.token.scope" : "false", 1550 | "display.on.consent.screen" : "true", 1551 | "consent.screen.text" : "${rolesScopeConsentText}" 1552 | }, 1553 | "protocolMappers" : [ { 1554 | "id" : "3a34b1d4-ff02-430a-833f-fd05e102a38d", 1555 | "name" : "client roles", 1556 | "protocol" : "openid-connect", 1557 | "protocolMapper" : "oidc-usermodel-client-role-mapper", 1558 | "consentRequired" : false, 1559 | "config" : { 1560 | "user.attribute" : "foo", 1561 | "access.token.claim" : "true", 1562 | "claim.name" : "resource_access.${client_id}.roles", 1563 | "jsonType.label" : "String", 1564 | "multivalued" : "true" 1565 | } 1566 | }, { 1567 | "id" : "81960814-25ef-4190-8509-1684d57d2be6", 1568 | "name" : "audience resolve", 1569 | "protocol" : "openid-connect", 1570 | "protocolMapper" : "oidc-audience-resolve-mapper", 1571 | "consentRequired" : false, 1572 | "config" : { } 1573 | }, { 1574 | "id" : "3950bc70-54db-4b36-85f3-f3b3ad453320", 1575 | "name" : "realm roles", 1576 | "protocol" : "openid-connect", 1577 | "protocolMapper" : "oidc-usermodel-realm-role-mapper", 1578 | "consentRequired" : false, 1579 | "config" : { 1580 | "user.attribute" : "foo", 1581 | "access.token.claim" : "true", 1582 | "claim.name" : "realm_access.roles", 1583 | "jsonType.label" : "String", 1584 | "multivalued" : "true" 1585 | } 1586 | } ] 1587 | }, { 1588 | "id" : "e3c83702-9ade-464c-ac28-2090cc54d2cb", 1589 | "name" : "web-origins", 1590 | "description" : "OpenID Connect scope for add allowed web origins to the access token", 1591 | "protocol" : "openid-connect", 1592 | "attributes" : { 1593 | "include.in.token.scope" : "false", 1594 | "display.on.consent.screen" : "false", 1595 | "consent.screen.text" : "" 1596 | }, 1597 | "protocolMappers" : [ { 1598 | "id" : "bb1a0709-3871-4c64-b796-7f60e481c069", 1599 | "name" : "allowed web origins", 1600 | "protocol" : "openid-connect", 1601 | "protocolMapper" : "oidc-allowed-origins-mapper", 1602 | "consentRequired" : false, 1603 | "config" : { } 1604 | } ] 1605 | } ], 1606 | "defaultDefaultClientScopes" : [ "role_list", "profile", "email", "roles", "web-origins" ], 1607 | "defaultOptionalClientScopes" : [ "offline_access", "address", "phone" ], 1608 | "browserSecurityHeaders" : { 1609 | "contentSecurityPolicyReportOnly" : "", 1610 | "xContentTypeOptions" : "nosniff", 1611 | "xRobotsTag" : "none", 1612 | "xFrameOptions" : "SAMEORIGIN", 1613 | "xXSSProtection" : "1; mode=block", 1614 | "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", 1615 | "strictTransportSecurity" : "max-age=31536000; includeSubDomains" 1616 | }, 1617 | "smtpServer" : { }, 1618 | "eventsEnabled" : false, 1619 | "eventsListeners" : [ "jboss-logging" ], 1620 | "enabledEventTypes" : [ ], 1621 | "adminEventsEnabled" : false, 1622 | "adminEventsDetailsEnabled" : false, 1623 | "components" : { 1624 | "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { 1625 | "id" : "ad5c39cb-75c1-4f9b-9b6b-1c4986b891f4", 1626 | "name" : "Allowed Client Templates", 1627 | "providerId" : "allowed-client-templates", 1628 | "subType" : "anonymous", 1629 | "subComponents" : { }, 1630 | "config" : { 1631 | "allow-default-scopes" : [ "true" ] 1632 | } 1633 | }, { 1634 | "id" : "9eb52e8b-e1c0-4186-9790-bb91bae169e8", 1635 | "name" : "Allowed Protocol Mapper Types", 1636 | "providerId" : "allowed-protocol-mappers", 1637 | "subType" : "authenticated", 1638 | "subComponents" : { }, 1639 | "config" : { 1640 | "allowed-protocol-mapper-types" : [ "oidc-full-name-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", "oidc-address-mapper" ], 1641 | "consent-required-for-all-mappers" : [ "true" ] 1642 | } 1643 | }, { 1644 | "id" : "996be1a8-92af-4eb3-bab9-c0f627da98a1", 1645 | "name" : "Max Clients Limit", 1646 | "providerId" : "max-clients", 1647 | "subType" : "anonymous", 1648 | "subComponents" : { }, 1649 | "config" : { 1650 | "max-clients" : [ "200" ] 1651 | } 1652 | }, { 1653 | "id" : "c21e9798-00f6-4c91-a7bc-9a05861bb32f", 1654 | "name" : "Allowed Protocol Mapper Types", 1655 | "providerId" : "allowed-protocol-mappers", 1656 | "subType" : "anonymous", 1657 | "subComponents" : { }, 1658 | "config" : { 1659 | "allowed-protocol-mapper-types" : [ "oidc-usermodel-property-mapper", "saml-user-attribute-mapper", "oidc-usermodel-attribute-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", "oidc-full-name-mapper", "saml-user-property-mapper", "oidc-address-mapper" ], 1660 | "consent-required-for-all-mappers" : [ "true" ] 1661 | } 1662 | }, { 1663 | "id" : "079cedc6-9c54-4543-b109-19c19e8b37b8", 1664 | "name" : "Consent Required", 1665 | "providerId" : "consent-required", 1666 | "subType" : "anonymous", 1667 | "subComponents" : { }, 1668 | "config" : { } 1669 | }, { 1670 | "id" : "d544d3e1-9145-424a-a7ca-15c256779741", 1671 | "name" : "Allowed Client Templates", 1672 | "providerId" : "allowed-client-templates", 1673 | "subType" : "authenticated", 1674 | "subComponents" : { }, 1675 | "config" : { 1676 | "allow-default-scopes" : [ "true" ] 1677 | } 1678 | }, { 1679 | "id" : "dd0a6ace-8fda-4cdf-8cbd-8ddacd2cdda5", 1680 | "name" : "Full Scope Disabled", 1681 | "providerId" : "scope", 1682 | "subType" : "anonymous", 1683 | "subComponents" : { }, 1684 | "config" : { } 1685 | }, { 1686 | "id" : "cef1c942-3364-47e6-8133-fdd0ecdd3cbf", 1687 | "name" : "Trusted Hosts", 1688 | "providerId" : "trusted-hosts", 1689 | "subType" : "anonymous", 1690 | "subComponents" : { }, 1691 | "config" : { 1692 | "host-sending-registration-request-must-match" : [ "true" ], 1693 | "client-uris-must-match" : [ "true" ] 1694 | } 1695 | } ], 1696 | "org.keycloak.keys.KeyProvider" : [ { 1697 | "id" : "8276065c-e57c-4742-bbda-2233f7d13829", 1698 | "name" : "aes-generated", 1699 | "providerId" : "aes-generated", 1700 | "subComponents" : { }, 1701 | "config" : { 1702 | "kid" : [ "bdd4422c-39e6-455b-83bd-522ca2161376" ], 1703 | "secret" : [ "JoEOmDTz8ACEYcfB9atEVA" ], 1704 | "priority" : [ "100" ] 1705 | } 1706 | }, { 1707 | "id" : "8698126a-2f8e-4ea1-9e7c-62676075bce4", 1708 | "name" : "rsa-generated", 1709 | "providerId" : "rsa-generated", 1710 | "subComponents" : { }, 1711 | "config" : { 1712 | "privateKey" : [ "MIIEogIBAAKCAQEAlEkhrJYezMZTAI3AxocUbDVn+S9soBOSbyZHwD+dJTv4UyDGh9tYHjupMdHlJpPsWyI/Fv6bxoveRtbfGOeCK2+4tae1zPI8uYRXsMQSlRJRvcbMQrOSDhSAWCelSw4lerPmCpMpcjgeMQuQftXVaygQV20jhj/WP6tLiQWj26zhXsXMpb8/JElVmdXEuJjP3k8oQ5Hz2dqyrskl0pIx6eqiRHto1+2/MkcX/FUB7nvEsuMnpCWh41KAhG6ZUQY2Nvfku/ZVeW0/pPw17OVebgHKXLfc8ulGZJMFn7571TYQ9rF+ymgXkwxK2RuIniST8DFlwJiNLD98efUuTAhKcwIDAQABAoIBAHZtldRVrNGUzzORAtZLibcGTDzKcHHET94vb3yOEb5sD96sPYLBXrX+phlg7ieKWmlKh6Kgw96lVGe1MkacluyD9Lw37k15ZaAwnyxQ3BpsoBX2EKpw6gQOwZYmS7AO40YFKYNmluJfCVXYS5XQx/sl6y83vfh5QW5mKxSLCZvmS4Fu7ByC+8/v/d/3/EjpwQEF8wPYZp67s84D24mSf4K3A0UsZRwu9er9l3XecNn0OR8d1oVR7/WJtJeW7YHo2K874OtpORa+SfX3OHO0gZUur2UXe16ISuEJKvbLDAC5PPtoIP2ak0mYGQT/E2I32yu4fpEc/rmNZvcfheTYp7ECgYEA/e2L+qqJ6geueKZvU0jfJSTYScHhS10uO/aOp+sX4ssveG/A/9Vz5lWBi8whzCSALwaBrbvlro+Gm9D0dUmM1KPRZ5ljihspA+ELvWLMQwSWVTnygKVpA2GLBU8VXgHyfR3QgrHcm76GJnprWKWAffMPVr8CaWpGj6dn51jAuusCgYEAlX7mJa3MRuseZJLXuO8A7yGRzwINayw4UcE8Bl7x+1JKHOIx2hx9qV74+qx9nknKCJX4a1JMl6XmArw7/sPzvcoVVdbdaLtFojxNGDnmhx4748V7BRsZ09U1DCCF90LElEUA802cBo7JQ2DdQFDH0pLCn7ufcXLYV/UTN5m8vJkCgYBj/bnEYIlkZdf3XJqz8hsk1khxau5brfq51BJC31mNjjNIOsGGPLih+APGWADrEWiEnAxOrJH6VjxMeVD6KpdRWJzqLcW7qYxSIblsv03uCg1kzCfJLtmWYj/LPGQOm7ewOyBThtR3Y+QRnN1OkAV0E1Vz9E1v01Cr2uEYgaOLNwKBgFiRXPKXu/2MEG6PXMTQvGHwJn1Y/vAuu5McA17W40/9GbFxBQ3ucThl7uY8SRP9LXfWud2DXaM+gz29nWG7X+1iCy/W40fII2IRja87pmsIq3yvI8oLm0qX9xyfLB8obGRXWU/L/BMahvynJ42SDkCf+DRAKR9CZg/+PwtixqGJAoGABLGY/A4p49Yn1ATMzzWltRhylc6UT3QvNnIfdrKna7Ou5q1pSvNtZ7vKp8hC1xiy35bdJpbp9zRFp3Mh8BQAYWLZrjGY8livUyAa0oaHNKUuzLUlGUTMg8he9UDsyHFvqp4vsCtzF9HpWjE7bYOtWtB7redIvoRGoRP2jK7rP/M=" ], 1713 | "certificate" : [ "MIICoTCCAYkCBgFjkY0GIjANBgkqhkiG9w0BAQsFADAUMRIwEAYDVQQDDAlib290YWRtaW4wHhcNMTgwNTI0MDk0NzA4WhcNMjgwNTI0MDk0ODQ4WjAUMRIwEAYDVQQDDAlib290YWRtaW4wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCUSSGslh7MxlMAjcDGhxRsNWf5L2ygE5JvJkfAP50lO/hTIMaH21geO6kx0eUmk+xbIj8W/pvGi95G1t8Y54Irb7i1p7XM8jy5hFewxBKVElG9xsxCs5IOFIBYJ6VLDiV6s+YKkylyOB4xC5B+1dVrKBBXbSOGP9Y/q0uJBaPbrOFexcylvz8kSVWZ1cS4mM/eTyhDkfPZ2rKuySXSkjHp6qJEe2jX7b8yRxf8VQHue8Sy4yekJaHjUoCEbplRBjY29+S79lV5bT+k/DXs5V5uAcpct9zy6UZkkwWfvnvVNhD2sX7KaBeTDErZG4ieJJPwMWXAmI0sP3x59S5MCEpzAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAFVoFt4gsvoL/l0O7Pf4DMiTa/oa5/Ga4qiYL0/HJG6Qv7cJsYEGKydXsZWwrcuzlekJaCfJRO0eOqD83MMV0sPUtl5tXmpKhZe4482mCPc+u2XezoloXcFEFx+BFJAWjVxUegsxIklaZVq/JtTIZOj4csKkGbHUJ3EG97Bxmeg4b9moaK5YMJJzdYpQQ7LiVDBryc4B9MzxcTsvr2JJxDOQGcpMvYLWXHsJkHufDw+p0i1281GlTKMDRE1eGELnQQIy9yOnAoafv6u6lV70BJ7fmgt9GokOY5q5D7bZIelBkxx/lA2YukqlA61HicJYqRI8p7BBADr2wf0UaWkoQ4Q=" ], 1714 | "priority" : [ "100" ] 1715 | } 1716 | }, { 1717 | "id" : "a1bda1a8-4cee-49bb-9def-808168c0b73d", 1718 | "name" : "hmac-generated", 1719 | "providerId" : "hmac-generated", 1720 | "subComponents" : { }, 1721 | "config" : { 1722 | "kid" : [ "3e9c8443-1f48-45af-84a5-1a225e61c1c5" ], 1723 | "secret" : [ "0KTfnsOZMTidy9ZBE3LK8ICuqajSPTS67NmQxNstXSF37vdmqDZBWiSIiphJVfZn-W9OnL-BQ_KhplkvMooPmg" ], 1724 | "priority" : [ "100" ] 1725 | } 1726 | } ] 1727 | }, 1728 | "internationalizationEnabled" : false, 1729 | "supportedLocales" : [ ], 1730 | "authenticationFlows" : [ { 1731 | "id" : "a60242ee-c5ff-4d5c-8b88-86d0377baaf4", 1732 | "alias" : "Handle Existing Account", 1733 | "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", 1734 | "providerId" : "basic-flow", 1735 | "topLevel" : false, 1736 | "builtIn" : true, 1737 | "authenticationExecutions" : [ { 1738 | "authenticator" : "idp-confirm-link", 1739 | "requirement" : "REQUIRED", 1740 | "priority" : 10, 1741 | "userSetupAllowed" : false, 1742 | "autheticatorFlow" : false 1743 | }, { 1744 | "authenticator" : "idp-email-verification", 1745 | "requirement" : "ALTERNATIVE", 1746 | "priority" : 20, 1747 | "userSetupAllowed" : false, 1748 | "autheticatorFlow" : false 1749 | }, { 1750 | "requirement" : "ALTERNATIVE", 1751 | "priority" : 30, 1752 | "flowAlias" : "Verify Existing Account by Re-authentication", 1753 | "userSetupAllowed" : false, 1754 | "autheticatorFlow" : true 1755 | } ] 1756 | }, { 1757 | "id" : "3d5eb7f6-67fb-4310-957e-0ff860efae47", 1758 | "alias" : "Verify Existing Account by Re-authentication", 1759 | "description" : "Reauthentication of existing account", 1760 | "providerId" : "basic-flow", 1761 | "topLevel" : false, 1762 | "builtIn" : true, 1763 | "authenticationExecutions" : [ { 1764 | "authenticator" : "idp-username-password-form", 1765 | "requirement" : "REQUIRED", 1766 | "priority" : 10, 1767 | "userSetupAllowed" : false, 1768 | "autheticatorFlow" : false 1769 | }, { 1770 | "authenticator" : "auth-otp-form", 1771 | "requirement" : "OPTIONAL", 1772 | "priority" : 20, 1773 | "userSetupAllowed" : false, 1774 | "autheticatorFlow" : false 1775 | } ] 1776 | }, { 1777 | "id" : "7e2863b4-b43a-4166-a94a-99cfc5e6c9c8", 1778 | "alias" : "browser", 1779 | "description" : "browser based authentication", 1780 | "providerId" : "basic-flow", 1781 | "topLevel" : true, 1782 | "builtIn" : true, 1783 | "authenticationExecutions" : [ { 1784 | "authenticator" : "auth-cookie", 1785 | "requirement" : "ALTERNATIVE", 1786 | "priority" : 10, 1787 | "userSetupAllowed" : false, 1788 | "autheticatorFlow" : false 1789 | }, { 1790 | "authenticator" : "auth-spnego", 1791 | "requirement" : "DISABLED", 1792 | "priority" : 20, 1793 | "userSetupAllowed" : false, 1794 | "autheticatorFlow" : false 1795 | }, { 1796 | "authenticator" : "identity-provider-redirector", 1797 | "requirement" : "ALTERNATIVE", 1798 | "priority" : 25, 1799 | "userSetupAllowed" : false, 1800 | "autheticatorFlow" : false 1801 | }, { 1802 | "requirement" : "ALTERNATIVE", 1803 | "priority" : 30, 1804 | "flowAlias" : "forms", 1805 | "userSetupAllowed" : false, 1806 | "autheticatorFlow" : true 1807 | } ] 1808 | }, { 1809 | "id" : "5fa1c2c6-3f11-4157-a4f9-7b14a4e752d4", 1810 | "alias" : "clients", 1811 | "description" : "Base authentication for clients", 1812 | "providerId" : "client-flow", 1813 | "topLevel" : true, 1814 | "builtIn" : true, 1815 | "authenticationExecutions" : [ { 1816 | "authenticator" : "client-secret", 1817 | "requirement" : "ALTERNATIVE", 1818 | "priority" : 10, 1819 | "userSetupAllowed" : false, 1820 | "autheticatorFlow" : false 1821 | }, { 1822 | "authenticator" : "client-jwt", 1823 | "requirement" : "ALTERNATIVE", 1824 | "priority" : 20, 1825 | "userSetupAllowed" : false, 1826 | "autheticatorFlow" : false 1827 | } ] 1828 | }, { 1829 | "id" : "fd71bbc9-0147-4934-9ab5-141e887d80cd", 1830 | "alias" : "direct grant", 1831 | "description" : "OpenID Connect Resource Owner Grant", 1832 | "providerId" : "basic-flow", 1833 | "topLevel" : true, 1834 | "builtIn" : true, 1835 | "authenticationExecutions" : [ { 1836 | "authenticator" : "direct-grant-validate-username", 1837 | "requirement" : "REQUIRED", 1838 | "priority" : 10, 1839 | "userSetupAllowed" : false, 1840 | "autheticatorFlow" : false 1841 | }, { 1842 | "authenticator" : "direct-grant-validate-password", 1843 | "requirement" : "REQUIRED", 1844 | "priority" : 20, 1845 | "userSetupAllowed" : false, 1846 | "autheticatorFlow" : false 1847 | }, { 1848 | "authenticator" : "direct-grant-validate-otp", 1849 | "requirement" : "OPTIONAL", 1850 | "priority" : 30, 1851 | "userSetupAllowed" : false, 1852 | "autheticatorFlow" : false 1853 | } ] 1854 | }, { 1855 | "id" : "b2ec296c-162f-4d7b-826c-0ce9e7d7e239", 1856 | "alias" : "docker auth", 1857 | "description" : "Used by Docker clients to authenticate against the IDP", 1858 | "providerId" : "basic-flow", 1859 | "topLevel" : true, 1860 | "builtIn" : true, 1861 | "authenticationExecutions" : [ { 1862 | "authenticator" : "docker-http-basic-authenticator", 1863 | "requirement" : "REQUIRED", 1864 | "priority" : 10, 1865 | "userSetupAllowed" : false, 1866 | "autheticatorFlow" : false 1867 | } ] 1868 | }, { 1869 | "id" : "2651a674-b8fc-4fd4-8460-cba7038f44a1", 1870 | "alias" : "first broker login", 1871 | "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", 1872 | "providerId" : "basic-flow", 1873 | "topLevel" : true, 1874 | "builtIn" : true, 1875 | "authenticationExecutions" : [ { 1876 | "authenticatorConfig" : "review profile config", 1877 | "authenticator" : "idp-review-profile", 1878 | "requirement" : "REQUIRED", 1879 | "priority" : 10, 1880 | "userSetupAllowed" : false, 1881 | "autheticatorFlow" : false 1882 | }, { 1883 | "authenticatorConfig" : "create unique user config", 1884 | "authenticator" : "idp-create-user-if-unique", 1885 | "requirement" : "ALTERNATIVE", 1886 | "priority" : 20, 1887 | "userSetupAllowed" : false, 1888 | "autheticatorFlow" : false 1889 | }, { 1890 | "requirement" : "ALTERNATIVE", 1891 | "priority" : 30, 1892 | "flowAlias" : "Handle Existing Account", 1893 | "userSetupAllowed" : false, 1894 | "autheticatorFlow" : true 1895 | } ] 1896 | }, { 1897 | "id" : "0f76c17e-e40e-4e43-afb6-b3956386ee1c", 1898 | "alias" : "forms", 1899 | "description" : "Username, password, otp and other auth forms.", 1900 | "providerId" : "basic-flow", 1901 | "topLevel" : false, 1902 | "builtIn" : true, 1903 | "authenticationExecutions" : [ { 1904 | "authenticator" : "auth-username-password-form", 1905 | "requirement" : "REQUIRED", 1906 | "priority" : 10, 1907 | "userSetupAllowed" : false, 1908 | "autheticatorFlow" : false 1909 | }, { 1910 | "authenticator" : "auth-otp-form", 1911 | "requirement" : "OPTIONAL", 1912 | "priority" : 20, 1913 | "userSetupAllowed" : false, 1914 | "autheticatorFlow" : false 1915 | } ] 1916 | }, { 1917 | "id" : "b85fc3a3-3e52-40c8-8adb-3eb3bc171ace", 1918 | "alias" : "registration", 1919 | "description" : "registration flow", 1920 | "providerId" : "basic-flow", 1921 | "topLevel" : true, 1922 | "builtIn" : true, 1923 | "authenticationExecutions" : [ { 1924 | "authenticator" : "registration-page-form", 1925 | "requirement" : "REQUIRED", 1926 | "priority" : 10, 1927 | "flowAlias" : "registration form", 1928 | "userSetupAllowed" : false, 1929 | "autheticatorFlow" : true 1930 | } ] 1931 | }, { 1932 | "id" : "e23fe0fb-177d-4459-8cfb-9a53b60a7007", 1933 | "alias" : "registration form", 1934 | "description" : "registration form", 1935 | "providerId" : "form-flow", 1936 | "topLevel" : false, 1937 | "builtIn" : true, 1938 | "authenticationExecutions" : [ { 1939 | "authenticator" : "registration-user-creation", 1940 | "requirement" : "REQUIRED", 1941 | "priority" : 20, 1942 | "userSetupAllowed" : false, 1943 | "autheticatorFlow" : false 1944 | }, { 1945 | "authenticator" : "registration-profile-action", 1946 | "requirement" : "REQUIRED", 1947 | "priority" : 40, 1948 | "userSetupAllowed" : false, 1949 | "autheticatorFlow" : false 1950 | }, { 1951 | "authenticator" : "registration-password-action", 1952 | "requirement" : "REQUIRED", 1953 | "priority" : 50, 1954 | "userSetupAllowed" : false, 1955 | "autheticatorFlow" : false 1956 | }, { 1957 | "authenticator" : "registration-recaptcha-action", 1958 | "requirement" : "DISABLED", 1959 | "priority" : 60, 1960 | "userSetupAllowed" : false, 1961 | "autheticatorFlow" : false 1962 | } ] 1963 | }, { 1964 | "id" : "7e114160-12a0-4745-95f6-5fddc2a4a88d", 1965 | "alias" : "reset credentials", 1966 | "description" : "Reset credentials for a user if they forgot their password or something", 1967 | "providerId" : "basic-flow", 1968 | "topLevel" : true, 1969 | "builtIn" : true, 1970 | "authenticationExecutions" : [ { 1971 | "authenticator" : "reset-credentials-choose-user", 1972 | "requirement" : "REQUIRED", 1973 | "priority" : 10, 1974 | "userSetupAllowed" : false, 1975 | "autheticatorFlow" : false 1976 | }, { 1977 | "authenticator" : "reset-credential-email", 1978 | "requirement" : "REQUIRED", 1979 | "priority" : 20, 1980 | "userSetupAllowed" : false, 1981 | "autheticatorFlow" : false 1982 | }, { 1983 | "authenticator" : "reset-password", 1984 | "requirement" : "REQUIRED", 1985 | "priority" : 30, 1986 | "userSetupAllowed" : false, 1987 | "autheticatorFlow" : false 1988 | }, { 1989 | "authenticator" : "reset-otp", 1990 | "requirement" : "OPTIONAL", 1991 | "priority" : 40, 1992 | "userSetupAllowed" : false, 1993 | "autheticatorFlow" : false 1994 | } ] 1995 | }, { 1996 | "id" : "640f1f65-6981-43aa-9280-26df6e2ee2a5", 1997 | "alias" : "saml ecp", 1998 | "description" : "SAML ECP Profile Authentication Flow", 1999 | "providerId" : "basic-flow", 2000 | "topLevel" : true, 2001 | "builtIn" : true, 2002 | "authenticationExecutions" : [ { 2003 | "authenticator" : "http-basic-authenticator", 2004 | "requirement" : "REQUIRED", 2005 | "priority" : 10, 2006 | "userSetupAllowed" : false, 2007 | "autheticatorFlow" : false 2008 | } ] 2009 | } ], 2010 | "authenticatorConfig" : [ { 2011 | "id" : "b5fdc759-2538-4cb8-b3f6-7f0ee09b713a", 2012 | "alias" : "create unique user config", 2013 | "config" : { 2014 | "require.password.update.after.registration" : "false" 2015 | } 2016 | }, { 2017 | "id" : "9bb26eb6-c273-48b3-9255-bf41629fcc53", 2018 | "alias" : "review profile config", 2019 | "config" : { 2020 | "update.profile.on.first.login" : "missing" 2021 | } 2022 | } ], 2023 | "requiredActions" : [ { 2024 | "alias" : "CONFIGURE_TOTP", 2025 | "name" : "Configure OTP", 2026 | "providerId" : "CONFIGURE_TOTP", 2027 | "enabled" : true, 2028 | "defaultAction" : false, 2029 | "priority" : 10, 2030 | "config" : { } 2031 | }, { 2032 | "alias" : "terms_and_conditions", 2033 | "name" : "Terms and Conditions", 2034 | "providerId" : "terms_and_conditions", 2035 | "enabled" : false, 2036 | "defaultAction" : false, 2037 | "priority" : 20, 2038 | "config" : { } 2039 | }, { 2040 | "alias" : "UPDATE_PASSWORD", 2041 | "name" : "Update Password", 2042 | "providerId" : "UPDATE_PASSWORD", 2043 | "enabled" : true, 2044 | "defaultAction" : false, 2045 | "priority" : 30, 2046 | "config" : { } 2047 | }, { 2048 | "alias" : "UPDATE_PROFILE", 2049 | "name" : "Update Profile", 2050 | "providerId" : "UPDATE_PROFILE", 2051 | "enabled" : true, 2052 | "defaultAction" : false, 2053 | "priority" : 40, 2054 | "config" : { } 2055 | }, { 2056 | "alias" : "VERIFY_EMAIL", 2057 | "name" : "Verify Email", 2058 | "providerId" : "VERIFY_EMAIL", 2059 | "enabled" : true, 2060 | "defaultAction" : false, 2061 | "priority" : 50, 2062 | "config" : { } 2063 | } ], 2064 | "browserFlow" : "browser", 2065 | "registrationFlow" : "registration", 2066 | "directGrantFlow" : "direct grant", 2067 | "resetCredentialsFlow" : "reset credentials", 2068 | "clientAuthenticationFlow" : "clients", 2069 | "dockerAuthenticationFlow" : "docker auth", 2070 | "attributes" : { 2071 | "_browser_header.xXSSProtection" : "1; mode=block", 2072 | "_browser_header.xFrameOptions" : "SAMEORIGIN", 2073 | "_browser_header.strictTransportSecurity" : "max-age=31536000; includeSubDomains", 2074 | "permanentLockout" : "false", 2075 | "quickLoginCheckMilliSeconds" : "1000", 2076 | "_browser_header.xRobotsTag" : "none", 2077 | "maxFailureWaitSeconds" : "900", 2078 | "minimumQuickLoginWaitSeconds" : "60", 2079 | "failureFactor" : "30", 2080 | "actionTokenGeneratedByUserLifespan" : "300", 2081 | "maxDeltaTimeSeconds" : "43200", 2082 | "_browser_header.xContentTypeOptions" : "nosniff", 2083 | "offlineSessionMaxLifespan" : "5184000", 2084 | "actionTokenGeneratedByAdminLifespan" : "43200", 2085 | "_browser_header.contentSecurityPolicyReportOnly" : "", 2086 | "bruteForceProtected" : "false", 2087 | "_browser_header.contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", 2088 | "waitIncrementSeconds" : "60", 2089 | "offlineSessionMaxLifespanEnabled" : "false" 2090 | }, 2091 | "keycloakVersion" : "4.8.3.Final", 2092 | "userManagedAccessAllowed" : false 2093 | } -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.example 8 | spring-boot-admin-keycloak-example 9 | 0.1.0-SNAPSHOT 10 | pom 11 | 12 | 13 | admin-service 14 | todo-service 15 | 16 | 17 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Protecting Spring Boot Admin & Actuator Endpoints with Keycloak 2 | 3 | This example consists of a [spring-boot-admin](https://github.com/codecentric/spring-boot-admin) server application `admin-service` which monitors 4 | another application called `todo-service` build with Spring Boot. 5 | The `admin-service` exposes the Spring Boot Admin UI via the `/admin` endpoint which is protected by the Keycloak adapter. The actuator endpoints of the `todo-service` are also protected with Keycloak and accessed via a `service-account` configured for the `admin-service` Keycloak client. 6 | 7 | This example is currently build with: 8 | - Spring Boot 2.1.4 9 | - Spring Boot Admin 2.1.3 10 | - Keycloak 4.8.3 11 | 12 | Note that an older version of this example is available in the [1.5.x](https://github.com/thomasdarimont/spring-boot-admin-keycloak-example/tree/1.5.x) branch, which uses: 13 | - Spring Boot 1.5.13 14 | - Spring Boot Admin 1.5.7 15 | - Keycloak 3.4.3.Final. 16 | 17 | # Setup Keycloak 18 | 19 | Import `bootadmin` demo realm by executing the following command in the `KEYCLOAK_HOME` directory. 20 | ``` 21 | bin/standalone.sh -Dkeycloak.migration.action=import \ 22 | -Dkeycloak.migration.provider=singleFile \ 23 | -Dkeycloak.migration.file=/path/to/bootadmin-realm.json \ 24 | -Dkeycloak.migration.strategy=OVERWRITE_EXISTING 25 | ``` 26 | 27 | After that Keycloak should be running with the `bootadmin` realm loaded in Keycloaks in-memory database. 28 | You can stop Keycloak with `CTRL+C`. You can start it again by running `bin/standalone.sh`. 29 | 30 | # Build the examples 31 | 32 | Run `mvn clean package` in the project root. 33 | 34 | # Run the examples 35 | 36 | ## Run the todo-service 37 | The simple `todo-service` can be reached via http://localhost:30002 38 | To start the service just run `java -jar todo-service/target/*.jar` 39 | 40 | ## Run the admin-service 41 | The `admin-service` can be reached via http://localhost:30001/admin 42 | To start the service just run `java -jar admin-service/target/*.jar` 43 | -------------------------------------------------------------------------------- /todo-service/.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/ -------------------------------------------------------------------------------- /todo-service/.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thomasdarimont/spring-boot-admin-keycloak-example/b186c53745722b28975312c587f25671b612183d/todo-service/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /todo-service/.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.5.3/apache-maven-3.5.3-bin.zip 2 | -------------------------------------------------------------------------------- /todo-service/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /etc/mavenrc ] ; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ] ; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false; 51 | darwin=false; 52 | mingw=false 53 | case "`uname`" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true;; 56 | Darwin*) darwin=true 57 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 58 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 59 | if [ -z "$JAVA_HOME" ]; then 60 | if [ -x "/usr/libexec/java_home" ]; then 61 | export JAVA_HOME="`/usr/libexec/java_home`" 62 | else 63 | export JAVA_HOME="/Library/Java/Home" 64 | fi 65 | fi 66 | ;; 67 | esac 68 | 69 | if [ -z "$JAVA_HOME" ] ; then 70 | if [ -r /etc/gentoo-release ] ; then 71 | JAVA_HOME=`java-config --jre-home` 72 | fi 73 | fi 74 | 75 | if [ -z "$M2_HOME" ] ; then 76 | ## resolve links - $0 may be a link to maven's home 77 | PRG="$0" 78 | 79 | # need this for relative symlinks 80 | while [ -h "$PRG" ] ; do 81 | ls=`ls -ld "$PRG"` 82 | link=`expr "$ls" : '.*-> \(.*\)$'` 83 | if expr "$link" : '/.*' > /dev/null; then 84 | PRG="$link" 85 | else 86 | PRG="`dirname "$PRG"`/$link" 87 | fi 88 | done 89 | 90 | saveddir=`pwd` 91 | 92 | M2_HOME=`dirname "$PRG"`/.. 93 | 94 | # make it fully qualified 95 | M2_HOME=`cd "$M2_HOME" && pwd` 96 | 97 | cd "$saveddir" 98 | # echo Using m2 at $M2_HOME 99 | fi 100 | 101 | # For Cygwin, ensure paths are in UNIX format before anything is touched 102 | if $cygwin ; then 103 | [ -n "$M2_HOME" ] && 104 | M2_HOME=`cygpath --unix "$M2_HOME"` 105 | [ -n "$JAVA_HOME" ] && 106 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 107 | [ -n "$CLASSPATH" ] && 108 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 109 | fi 110 | 111 | # For Migwn, ensure paths are in UNIX format before anything is touched 112 | if $mingw ; then 113 | [ -n "$M2_HOME" ] && 114 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 115 | [ -n "$JAVA_HOME" ] && 116 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 117 | # TODO classpath? 118 | fi 119 | 120 | if [ -z "$JAVA_HOME" ]; then 121 | javaExecutable="`which javac`" 122 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 123 | # readlink(1) is not available as standard on Solaris 10. 124 | readLink=`which readlink` 125 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 126 | if $darwin ; then 127 | javaHome="`dirname \"$javaExecutable\"`" 128 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 129 | else 130 | javaExecutable="`readlink -f \"$javaExecutable\"`" 131 | fi 132 | javaHome="`dirname \"$javaExecutable\"`" 133 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 134 | JAVA_HOME="$javaHome" 135 | export JAVA_HOME 136 | fi 137 | fi 138 | fi 139 | 140 | if [ -z "$JAVACMD" ] ; then 141 | if [ -n "$JAVA_HOME" ] ; then 142 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 143 | # IBM's JDK on AIX uses strange locations for the executables 144 | JAVACMD="$JAVA_HOME/jre/sh/java" 145 | else 146 | JAVACMD="$JAVA_HOME/bin/java" 147 | fi 148 | else 149 | JAVACMD="`which java`" 150 | fi 151 | fi 152 | 153 | if [ ! -x "$JAVACMD" ] ; then 154 | echo "Error: JAVA_HOME is not defined correctly." >&2 155 | echo " We cannot execute $JAVACMD" >&2 156 | exit 1 157 | fi 158 | 159 | if [ -z "$JAVA_HOME" ] ; then 160 | echo "Warning: JAVA_HOME environment variable is not set." 161 | fi 162 | 163 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 164 | 165 | # traverses directory structure from process work directory to filesystem root 166 | # first directory with .mvn subdirectory is considered project base directory 167 | find_maven_basedir() { 168 | 169 | if [ -z "$1" ] 170 | then 171 | echo "Path not specified to find_maven_basedir" 172 | return 1 173 | fi 174 | 175 | basedir="$1" 176 | wdir="$1" 177 | while [ "$wdir" != '/' ] ; do 178 | if [ -d "$wdir"/.mvn ] ; then 179 | basedir=$wdir 180 | break 181 | fi 182 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 183 | if [ -d "${wdir}" ]; then 184 | wdir=`cd "$wdir/.."; pwd` 185 | fi 186 | # end of workaround 187 | done 188 | echo "${basedir}" 189 | } 190 | 191 | # concatenates all lines of a file 192 | concat_lines() { 193 | if [ -f "$1" ]; then 194 | echo "$(tr -s '\n' ' ' < "$1")" 195 | fi 196 | } 197 | 198 | BASE_DIR=`find_maven_basedir "$(pwd)"` 199 | if [ -z "$BASE_DIR" ]; then 200 | exit 1; 201 | fi 202 | 203 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 204 | echo $MAVEN_PROJECTBASEDIR 205 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 206 | 207 | # For Cygwin, switch paths to Windows format before running java 208 | if $cygwin; then 209 | [ -n "$M2_HOME" ] && 210 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 211 | [ -n "$JAVA_HOME" ] && 212 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 213 | [ -n "$CLASSPATH" ] && 214 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 215 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 216 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 217 | fi 218 | 219 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 220 | 221 | exec "$JAVACMD" \ 222 | $MAVEN_OPTS \ 223 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 224 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 225 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 226 | -------------------------------------------------------------------------------- /todo-service/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM http://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' 39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 40 | 41 | @REM set %HOME% to equivalent of $HOME 42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 43 | 44 | @REM Execute a user defined script before this one 45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 49 | :skipRcPre 50 | 51 | @setlocal 52 | 53 | set ERROR_CODE=0 54 | 55 | @REM To isolate internal variables from possible post scripts, we use another setlocal 56 | @setlocal 57 | 58 | @REM ==== START VALIDATION ==== 59 | if not "%JAVA_HOME%" == "" goto OkJHome 60 | 61 | echo. 62 | echo Error: JAVA_HOME not found in your environment. >&2 63 | echo Please set the JAVA_HOME variable in your environment to match the >&2 64 | echo location of your Java installation. >&2 65 | echo. 66 | goto error 67 | 68 | :OkJHome 69 | if exist "%JAVA_HOME%\bin\java.exe" goto init 70 | 71 | echo. 72 | echo Error: JAVA_HOME is set to an invalid directory. >&2 73 | echo JAVA_HOME = "%JAVA_HOME%" >&2 74 | echo Please set the JAVA_HOME variable in your environment to match the >&2 75 | echo location of your Java installation. >&2 76 | echo. 77 | goto error 78 | 79 | @REM ==== END VALIDATION ==== 80 | 81 | :init 82 | 83 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 84 | @REM Fallback to current working directory if not found. 85 | 86 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 87 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 88 | 89 | set EXEC_DIR=%CD% 90 | set WDIR=%EXEC_DIR% 91 | :findBaseDir 92 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 93 | cd .. 94 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 95 | set WDIR=%CD% 96 | goto findBaseDir 97 | 98 | :baseDirFound 99 | set MAVEN_PROJECTBASEDIR=%WDIR% 100 | cd "%EXEC_DIR%" 101 | goto endDetectBaseDir 102 | 103 | :baseDirNotFound 104 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 105 | cd "%EXEC_DIR%" 106 | 107 | :endDetectBaseDir 108 | 109 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 110 | 111 | @setlocal EnableExtensions EnableDelayedExpansion 112 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 113 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 114 | 115 | :endReadAdditionalConfig 116 | 117 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 118 | 119 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 120 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 121 | 122 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 123 | if ERRORLEVEL 1 goto error 124 | goto end 125 | 126 | :error 127 | set ERROR_CODE=1 128 | 129 | :end 130 | @endlocal & set ERROR_CODE=%ERROR_CODE% 131 | 132 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 133 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 134 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 135 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 136 | :skipRcPost 137 | 138 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 139 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 140 | 141 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 142 | 143 | exit /B %ERROR_CODE% 144 | -------------------------------------------------------------------------------- /todo-service/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | com.example 8 | todo-service 9 | 0.1.0-SNAPSHOT 10 | jar 11 | 12 | todo-service 13 | Demo project for Spring Boot 14 | 15 | 16 | org.springframework.boot 17 | spring-boot-starter-parent 18 | 2.1.4.RELEASE 19 | 20 | 21 | 22 | 23 | UTF-8 24 | UTF-8 25 | 1.8 26 | 4.8.3.Final 27 | 2.1.3 28 | 29 | 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-security 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-web 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-tomcat 42 | 43 | 44 | 45 | 46 | 47 | org.springframework.boot 48 | spring-boot-starter-jetty 49 | 50 | 51 | 52 | org.keycloak 53 | keycloak-spring-boot-starter 54 | 55 | 56 | 57 | org.springframework.boot 58 | spring-boot-starter-actuator 59 | 60 | 61 | 62 | de.codecentric 63 | spring-boot-admin-starter-client 64 | ${spring-boot-admin.version} 65 | 66 | 67 | 68 | org.projectlombok 69 | lombok 70 | true 71 | 72 | 73 | 74 | org.springframework.boot 75 | spring-boot-starter-test 76 | test 77 | 78 | 79 | 80 | org.springframework.security 81 | spring-security-test 82 | test 83 | 84 | 85 | 86 | 87 | 88 | 89 | org.keycloak.bom 90 | keycloak-adapter-bom 91 | ${keycloak.version} 92 | pom 93 | import 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | pl.project13.maven 102 | git-commit-id-plugin 103 | 104 | 105 | 106 | org.springframework.boot 107 | spring-boot-maven-plugin 108 | 109 | 110 | 111 | build-info 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /todo-service/src/main/java/demo/todo/TodoServiceApplication.java: -------------------------------------------------------------------------------- 1 | package demo.todo; 2 | 3 | import java.time.Instant; 4 | import java.util.Arrays; 5 | 6 | import org.springframework.boot.SpringApplication; 7 | import org.springframework.boot.autoconfigure.SpringBootApplication; 8 | import org.springframework.scheduling.annotation.EnableScheduling; 9 | import org.springframework.scheduling.annotation.Scheduled; 10 | import org.springframework.web.bind.annotation.GetMapping; 11 | import org.springframework.web.bind.annotation.RestController; 12 | 13 | import lombok.extern.slf4j.Slf4j; 14 | 15 | @Slf4j 16 | @EnableScheduling 17 | @SpringBootApplication 18 | public class TodoServiceApplication { 19 | 20 | public static void main(String[] args) { 21 | SpringApplication.run(TodoServiceApplication.class, args); 22 | } 23 | 24 | @Scheduled(fixedRate = 5_000) 25 | public void doSomework() { 26 | 27 | // useful to demonstrate log dynamic level configuration 28 | log.info("work info"); 29 | log.debug("work debug"); 30 | log.trace("work trace"); 31 | log.error("work error"); 32 | } 33 | } 34 | 35 | @RestController 36 | class TodoController { 37 | 38 | @GetMapping("/") 39 | Object getTodos() { 40 | return Arrays.asList("Prepare talk..." + Instant.now()); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /todo-service/src/main/java/demo/todo/keycloak/KeycloakConfig.java: -------------------------------------------------------------------------------- 1 | package demo.todo.keycloak; 2 | 3 | import java.security.Principal; 4 | 5 | import org.keycloak.KeycloakPrincipal; 6 | import org.keycloak.KeycloakSecurityContext; 7 | import org.keycloak.adapters.KeycloakConfigResolver; 8 | import org.keycloak.adapters.springboot.KeycloakBaseSpringBootConfiguration; 9 | import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; 10 | import org.keycloak.adapters.springboot.KeycloakSpringBootProperties; 11 | import org.keycloak.adapters.springsecurity.KeycloakConfiguration; 12 | import org.keycloak.adapters.springsecurity.authentication.KeycloakAuthenticationProvider; 13 | import org.keycloak.adapters.springsecurity.config.KeycloakWebSecurityConfigurerAdapter; 14 | import org.keycloak.adapters.springsecurity.token.KeycloakAuthenticationToken; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest; 17 | import org.springframework.boot.actuate.health.HealthEndpoint; 18 | import org.springframework.boot.actuate.info.InfoEndpoint; 19 | import org.springframework.boot.context.properties.ConfigurationProperties; 20 | import org.springframework.boot.context.properties.EnableConfigurationProperties; 21 | import org.springframework.context.annotation.Bean; 22 | import org.springframework.context.annotation.Configuration; 23 | import org.springframework.context.annotation.Scope; 24 | import org.springframework.context.annotation.ScopedProxyMode; 25 | import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 26 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 27 | import org.springframework.security.core.authority.mapping.SimpleAuthorityMapper; 28 | import org.springframework.security.core.context.SecurityContextHolder; 29 | import org.springframework.security.core.session.SessionRegistry; 30 | import org.springframework.security.core.session.SessionRegistryImpl; 31 | import org.springframework.security.web.authentication.session.RegisterSessionAuthenticationStrategy; 32 | import org.springframework.security.web.authentication.session.SessionAuthenticationStrategy; 33 | import org.springframework.web.bind.annotation.GetMapping; 34 | import org.springframework.web.bind.annotation.RestController; 35 | import org.springframework.web.context.WebApplicationContext; 36 | import org.springframework.web.context.annotation.RequestScope; 37 | import org.springframework.web.context.request.RequestContextHolder; 38 | import org.springframework.web.context.request.ServletRequestAttributes; 39 | 40 | @KeycloakConfiguration 41 | @EnableConfigurationProperties(KeycloakSpringBootProperties.class) 42 | class KeycloakConfig extends KeycloakWebSecurityConfigurerAdapter { 43 | 44 | @Override 45 | protected void configure(HttpSecurity http) throws Exception { 46 | super.configure(http); 47 | 48 | http // 49 | .csrf().disable() // 50 | .authorizeRequests() // 51 | .requestMatchers(EndpointRequest.to( // 52 | InfoEndpoint.class, // 53 | HealthEndpoint.class // 54 | )).permitAll() // 55 | 56 | .requestMatchers(EndpointRequest.toAnyEndpoint()) // 57 | .hasRole("ACTUATOR") // 58 | 59 | .anyRequest().permitAll() // 60 | ; 61 | } 62 | 63 | /** 64 | * Load Keycloak configuration from application.properties or application.yml 65 | * 66 | * @return 67 | */ 68 | @Bean 69 | public KeycloakConfigResolver keycloakConfigResolver() { 70 | return new KeycloakSpringBootConfigResolver(); 71 | } 72 | 73 | /** 74 | * Use {@link KeycloakAuthenticationProvider} 75 | * 76 | * @param auth 77 | * @throws Exception 78 | */ 79 | @Autowired 80 | public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 81 | 82 | SimpleAuthorityMapper grantedAuthorityMapper = new SimpleAuthorityMapper(); 83 | grantedAuthorityMapper.setPrefix("ROLE_"); 84 | grantedAuthorityMapper.setConvertToUpperCase(true); 85 | 86 | KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider(); 87 | keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(grantedAuthorityMapper); 88 | auth.authenticationProvider(keycloakAuthenticationProvider); 89 | } 90 | 91 | @Bean 92 | @Override 93 | protected SessionAuthenticationStrategy sessionAuthenticationStrategy() { 94 | return new RegisterSessionAuthenticationStrategy(buildSessionRegistry()); 95 | } 96 | 97 | @Bean 98 | protected SessionRegistry buildSessionRegistry() { 99 | return new SessionRegistryImpl(); 100 | } 101 | 102 | /** 103 | * Allows to inject requests scoped wrapper for {@link KeycloakSecurityContext}. 104 | * 105 | * Returns the {@link KeycloakSecurityContext} from the Spring 106 | * {@link ServletRequestAttributes}'s {@link Principal}. 107 | *

108 | * The principal must support retrieval of the KeycloakSecurityContext, so at 109 | * this point, only {@link KeycloakPrincipal} values and 110 | * {@link KeycloakAuthenticationToken} are supported. 111 | * 112 | * @return the current KeycloakSecurityContext 113 | */ 114 | @Bean 115 | @Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS) 116 | public KeycloakSecurityContext provideKeycloakSecurityContext() { 117 | 118 | ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); 119 | Principal principal = attributes.getRequest().getUserPrincipal(); 120 | if (principal == null) { 121 | return null; 122 | } 123 | 124 | if (principal instanceof KeycloakAuthenticationToken) { 125 | principal = Principal.class.cast(KeycloakAuthenticationToken.class.cast(principal).getPrincipal()); 126 | } 127 | 128 | if (principal instanceof KeycloakPrincipal) { 129 | return KeycloakPrincipal.class.cast(principal).getKeycloakSecurityContext(); 130 | } 131 | 132 | return null; 133 | } 134 | 135 | /** 136 | * Ensures the correct registration of KeycloakSpringBootConfigResolver when Keycloaks AutoConfiguration 137 | * is explicitly turned off in application.yml {@code keycloak.enabled: false}. 138 | */ 139 | @Configuration 140 | static class CustomKeycloakBaseSpringBootConfiguration extends KeycloakBaseSpringBootConfiguration { 141 | } 142 | } -------------------------------------------------------------------------------- /todo-service/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | spring: 2 | main: 3 | allow-bean-definition-overriding: true 4 | 5 | server: 6 | port: 30002 7 | 8 | keycloak: 9 | # turn off keycloak spring boot auto-configuration: 10 | # We only want to use Spring Security without servlet container specific infrastructure 11 | # This allows us to pull the Keycloak configuration from here instead of keycloak.json 12 | enabled: false 13 | 14 | realm: bootadmin 15 | auth-server-url: http://localhost:8080/auth 16 | # The client_id 17 | resource: app-todo 18 | credentials: 19 | # The client_secret 20 | secret: 2cc653a3-24cc-4241-896d-813a726f9b33 21 | ssl-required: external 22 | autodetect-bearer-only: true 23 | # Configures what principal.getName() will return 24 | principal-attribute: preferred_username 25 | use-resource-role-mappings: true 26 | token-minimum-time-to-live: 30 27 | 28 | management: 29 | endpoints: 30 | web: 31 | exposure: 32 | include: '*' 33 | -------------------------------------------------------------------------------- /todo-service/src/test/java/demo/todo/TodoServiceApplicationTests.java: -------------------------------------------------------------------------------- 1 | package demo.todo; 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 TodoServiceApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------