Showing preview only (3,564K chars total). Download the full file or copy to clipboard to get everything.
Repository: thomasdarimont/keycloak-project-example
Branch: main
Commit: 188ff5af3716
Files: 914
Total size: 3.2 MB
Directory structure:
gitextract_j1wzyoop/
├── .github/
│ └── workflows/
│ ├── build.yml
│ └── e2e-tests.yml
├── .gitignore
├── .run/
│ ├── Acme Backend API Quarkus.run.xml
│ ├── Keycloak Remote.run.xml
│ ├── OfflineSessionClient (logout).run.xml
│ ├── OfflineSessionClient.run.xml
│ ├── acme-webapp-saml-node-express.run.xml
│ ├── backend-api-micronaut.run.xml
│ ├── backend-api-springboot-reactive.run.xml
│ ├── backend-api-springboot.run.xml
│ ├── backend-api-springboot3.run.xml
│ ├── frontend-webapp-springboot-otel.run.xml
│ ├── frontend-webapp-springboot.run.xml
│ └── frontend-webapp-springboot3.run.xml
├── .vscode/
│ └── settings.json
├── LICENSE
├── apps/
│ ├── account-svc/
│ │ ├── .dockerignore
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ ├── .gitignore
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ └── maven-wrapper.properties
│ │ ├── README.md
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── docker/
│ │ │ ├── Dockerfile.jvm
│ │ │ ├── Dockerfile.legacy-jar
│ │ │ ├── Dockerfile.native
│ │ │ └── Dockerfile.native-micro
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── thomasdarimont/
│ │ │ └── keycloak/
│ │ │ └── training/
│ │ │ └── accounts/
│ │ │ ├── User.java
│ │ │ ├── UserRepository.java
│ │ │ └── UserResource.java
│ │ └── resources/
│ │ └── application.properties
│ ├── acme-account-console/
│ │ └── index.html
│ ├── acme-greetme/
│ │ └── index.html
│ ├── acme-webapp-saml-node-express/
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── config.js
│ │ │ ├── express.js
│ │ │ ├── index.js
│ │ │ ├── logging.js
│ │ │ └── server.js
│ │ └── views/
│ │ ├── pages/
│ │ │ ├── app.ejs
│ │ │ ├── error.ejs
│ │ │ ├── index.ejs
│ │ │ └── page1.ejs
│ │ └── partials/
│ │ ├── footer.ejs
│ │ ├── head.ejs
│ │ └── header.ejs
│ ├── backend-api-dnc/
│ │ ├── api/
│ │ │ ├── .dockerignore
│ │ │ ├── .gitignore
│ │ │ ├── Controllers/
│ │ │ │ └── UsersController.cs
│ │ │ ├── Dockerfile
│ │ │ ├── JwtBearerOptions.cs
│ │ │ ├── Program.cs
│ │ │ ├── Properties/
│ │ │ │ └── launchSettings.json
│ │ │ ├── api.csproj
│ │ │ ├── appsettings.Development.json
│ │ │ └── appsettings.json
│ │ └── backend-api-dnc.sln
│ ├── backend-api-micronaut/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ └── maven-wrapper.properties
│ │ ├── README.md
│ │ ├── micronaut-cli.yml
│ │ ├── mvnw
│ │ ├── mvnw.bat
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── acme/
│ │ │ └── backend/
│ │ │ └── micronaut/
│ │ │ ├── Application.java
│ │ │ └── api/
│ │ │ └── UsersResource.java
│ │ └── resources/
│ │ ├── application.yml
│ │ └── logback.xml
│ ├── backend-api-node-express/
│ │ ├── package.json
│ │ ├── readme.md
│ │ └── src/
│ │ ├── api.js
│ │ ├── config.js
│ │ ├── express.js
│ │ ├── index.js
│ │ ├── logging.js
│ │ └── server.js
│ ├── backend-api-quarkus/
│ │ ├── .dockerignore
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── docker/
│ │ │ ├── Dockerfile.jvm
│ │ │ ├── Dockerfile.legacy-jar
│ │ │ ├── Dockerfile.native
│ │ │ └── Dockerfile.native-distroless
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── acme/
│ │ │ └── backend/
│ │ │ └── quarkus/
│ │ │ └── users/
│ │ │ └── UsersResource.java
│ │ └── resources/
│ │ ├── META-INF/
│ │ │ └── resources/
│ │ │ └── index.html
│ │ └── application.properties
│ ├── backend-api-rust-actix/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── rustfmt.toml
│ │ ├── rustup-toolchain.toml
│ │ └── src/
│ │ ├── api/
│ │ │ ├── me_info.rs
│ │ │ └── mod.rs
│ │ ├── config.rs
│ │ ├── main.rs
│ │ └── middleware/
│ │ ├── cors.rs
│ │ ├── jwt_auth.rs
│ │ ├── mod.rs
│ │ └── ssl.rs
│ ├── backend-api-rust-rocket/
│ │ ├── .gitignore
│ │ ├── .run/
│ │ │ └── Run backend-api-rust-rocket.run.xml
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ ├── Rocket.toml
│ │ ├── rustfmt.toml
│ │ ├── rustup-toolchain.toml
│ │ ├── src/
│ │ │ ├── domain/
│ │ │ │ ├── mod.rs
│ │ │ │ └── user.rs
│ │ │ ├── main.rs
│ │ │ ├── middleware/
│ │ │ │ ├── auth/
│ │ │ │ │ ├── jwt/
│ │ │ │ │ │ ├── auth.rs
│ │ │ │ │ │ ├── claims.rs
│ │ │ │ │ │ ├── config.rs
│ │ │ │ │ │ ├── get_max_age.rs
│ │ │ │ │ │ ├── jwks.rs
│ │ │ │ │ │ ├── mod.rs
│ │ │ │ │ │ └── verifier.rs
│ │ │ │ │ ├── jwt_auth_request_guard.rs
│ │ │ │ │ └── mod.rs
│ │ │ │ ├── cors/
│ │ │ │ │ ├── cors.rs
│ │ │ │ │ └── mod.rs
│ │ │ │ ├── logging/
│ │ │ │ │ ├── logging.rs
│ │ │ │ │ └── mod.rs
│ │ │ │ └── mod.rs
│ │ │ └── support/
│ │ │ ├── mod.rs
│ │ │ └── scheduling/
│ │ │ ├── mod.rs
│ │ │ └── use_repeating_job.rs
│ │ └── tests/
│ │ └── fetch_keys.rs
│ ├── backend-api-springboot/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ └── maven-wrapper.properties
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── acme/
│ │ │ │ └── backend/
│ │ │ │ └── springboot/
│ │ │ │ └── users/
│ │ │ │ ├── BackendApiSpringbootApp.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── AcmeServiceProperties.java
│ │ │ │ │ ├── JwtSecurityConfig.java
│ │ │ │ │ ├── MethodSecurityConfig.java
│ │ │ │ │ └── WebSecurityConfig.java
│ │ │ │ ├── support/
│ │ │ │ │ ├── access/
│ │ │ │ │ │ └── AccessController.java
│ │ │ │ │ ├── keycloak/
│ │ │ │ │ │ ├── KeycloakAudienceValidator.java
│ │ │ │ │ │ ├── KeycloakGrantedAuthoritiesConverter.java
│ │ │ │ │ │ └── KeycloakJwtAuthenticationConverter.java
│ │ │ │ │ └── permissions/
│ │ │ │ │ ├── DefaultPermissionEvaluator.java
│ │ │ │ │ └── DomainObjectReference.java
│ │ │ │ └── web/
│ │ │ │ └── UsersController.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── acme/
│ │ └── backend/
│ │ └── springboot/
│ │ └── users/
│ │ └── BackendApiSpringbootAppTests.java
│ ├── backend-api-springboot-reactive/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ └── maven-wrapper.properties
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── acme/
│ │ │ │ └── backend/
│ │ │ │ └── springreactive/
│ │ │ │ ├── BackendApiSpringbootReactiveApp.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── AcmeServiceProperties.java
│ │ │ │ │ ├── JwtSecurityConfig.java
│ │ │ │ │ ├── MethodSecurityConfig.java
│ │ │ │ │ ├── WebFluxConfig.java
│ │ │ │ │ ├── WebFluxRoutes.java
│ │ │ │ │ └── WebSecurityConfig.java
│ │ │ │ ├── support/
│ │ │ │ │ └── keycloak/
│ │ │ │ │ ├── KeycloakAudienceValidator.java
│ │ │ │ │ ├── KeycloakGrantedAuthoritiesConverter.java
│ │ │ │ │ └── KeycloakJwtAuthenticationConverter.java
│ │ │ │ └── users/
│ │ │ │ └── UserHandlers.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── acme/
│ │ └── backend/
│ │ └── springreactive/
│ │ └── BackendApiSpringbootReactiveAppTests.java
│ ├── backend-api-springboot3/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ └── maven-wrapper.properties
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── acme/
│ │ │ │ └── backend/
│ │ │ │ └── springboot/
│ │ │ │ └── users/
│ │ │ │ ├── BackendApiSpringboot3App.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── AcmeServiceProperties.java
│ │ │ │ │ ├── JwtSecurityConfig.java
│ │ │ │ │ ├── MethodSecurityConfig.java
│ │ │ │ │ └── WebSecurityConfig.java
│ │ │ │ ├── support/
│ │ │ │ │ ├── access/
│ │ │ │ │ │ └── AccessController.java
│ │ │ │ │ ├── keycloak/
│ │ │ │ │ │ ├── KeycloakAudienceValidator.java
│ │ │ │ │ │ ├── KeycloakGrantedAuthoritiesConverter.java
│ │ │ │ │ │ └── KeycloakJwtAuthenticationConverter.java
│ │ │ │ │ └── permissions/
│ │ │ │ │ ├── DefaultPermissionEvaluator.java
│ │ │ │ │ └── DomainObjectReference.java
│ │ │ │ └── web/
│ │ │ │ └── UsersController.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── acme/
│ │ └── backend/
│ │ └── springboot/
│ │ └── users/
│ │ └── BackendApiSpringboot3AppTests.java
│ ├── bff-springboot/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ └── maven-wrapper.properties
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── github/
│ │ │ └── thomasdarimont/
│ │ │ └── apps/
│ │ │ └── bff/
│ │ │ ├── BffApp.java
│ │ │ ├── api/
│ │ │ │ └── UsersResource.java
│ │ │ ├── config/
│ │ │ │ ├── OAuth2RestTemplateConfig.java
│ │ │ │ ├── SessionConfig.java
│ │ │ │ ├── WebSecurityConfig.java
│ │ │ │ └── keycloak/
│ │ │ │ └── KeycloakLogoutHandler.java
│ │ │ ├── oauth/
│ │ │ │ ├── TokenAccessor.java
│ │ │ │ ├── TokenIntrospector.java
│ │ │ │ └── TokenRefresher.java
│ │ │ └── web/
│ │ │ └── UiResource.java
│ │ └── resources/
│ │ ├── application.yml
│ │ ├── static/
│ │ │ └── app/
│ │ │ └── app.js
│ │ └── templates/
│ │ └── app/
│ │ └── index.html
│ ├── bff-springboot3/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ └── maven-wrapper.properties
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── github/
│ │ │ └── thomasdarimont/
│ │ │ └── apps/
│ │ │ └── bff3/
│ │ │ ├── Bff3App.java
│ │ │ ├── api/
│ │ │ │ └── UsersResource.java
│ │ │ ├── config/
│ │ │ │ ├── OAuth2RestTemplateConfig.java
│ │ │ │ ├── SessionConfig.java
│ │ │ │ ├── WebSecurityConfig.java
│ │ │ │ └── keycloak/
│ │ │ │ └── KeycloakLogoutHandler.java
│ │ │ ├── oauth/
│ │ │ │ ├── TokenAccessor.java
│ │ │ │ ├── TokenIntrospector.java
│ │ │ │ └── TokenRefresher.java
│ │ │ ├── support/
│ │ │ │ ├── HttpServletRequestUtils.java
│ │ │ │ └── HttpSessionOAuth2AuthorizedClientService.java
│ │ │ └── web/
│ │ │ ├── AuthResource.java
│ │ │ └── UiResource.java
│ │ └── resources/
│ │ ├── application.yml
│ │ ├── static/
│ │ │ └── app/
│ │ │ └── app.js
│ │ └── templates/
│ │ └── app/
│ │ └── index.html
│ ├── frontend-webapp-springboot/
│ │ ├── .gitignore
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── github/
│ │ │ │ └── thomasdarimont/
│ │ │ │ └── keycloak/
│ │ │ │ └── webapp/
│ │ │ │ ├── WebAppSpringBoot.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── KeycloakWebClientConfig.java
│ │ │ │ │ ├── OidcUserServiceConfig.java
│ │ │ │ │ └── WebSecurityConfig.java
│ │ │ │ ├── domain/
│ │ │ │ │ ├── ApplicationEntry.java
│ │ │ │ │ ├── CredentialEntry.java
│ │ │ │ │ ├── SettingEntry.java
│ │ │ │ │ └── UserProfile.java
│ │ │ │ ├── support/
│ │ │ │ │ ├── OAuth2AuthorizedClientAccessor.java
│ │ │ │ │ ├── TokenAccessor.java
│ │ │ │ │ ├── TokenIntrospector.java
│ │ │ │ │ ├── keycloakclient/
│ │ │ │ │ │ ├── DefaultKeycloakClient.java
│ │ │ │ │ │ ├── KeycloakClient.java
│ │ │ │ │ │ ├── KeycloakIntrospectResponse.java
│ │ │ │ │ │ ├── KeycloakServiceException.java
│ │ │ │ │ │ └── KeycloakUserInfo.java
│ │ │ │ │ └── security/
│ │ │ │ │ └── KeycloakLogoutHandler.java
│ │ │ │ └── web/
│ │ │ │ ├── AuthController.java
│ │ │ │ └── UiController.java
│ │ │ └── resources/
│ │ │ ├── application.yml
│ │ │ └── templates/
│ │ │ ├── applications.html
│ │ │ ├── fragments.html
│ │ │ ├── index.html
│ │ │ ├── profile.html
│ │ │ ├── security.html
│ │ │ └── settings.html
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── github/
│ │ └── thomasdarimont/
│ │ └── keycloak/
│ │ └── cac/
│ │ └── WebApplicationTestsSpringBoot.java
│ ├── frontend-webapp-springboot3/
│ │ ├── otel-config.yaml
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── github/
│ │ │ │ └── thomasdarimont/
│ │ │ │ └── keycloak/
│ │ │ │ └── webapp/
│ │ │ │ ├── WebAppSpringBoot3.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── KeycloakWebClientConfig.java
│ │ │ │ │ ├── OidcUserServiceConfig.java
│ │ │ │ │ └── WebSecurityConfig.java
│ │ │ │ ├── domain/
│ │ │ │ │ ├── ApplicationEntry.java
│ │ │ │ │ ├── CredentialEntry.java
│ │ │ │ │ ├── SettingEntry.java
│ │ │ │ │ └── UserProfile.java
│ │ │ │ ├── support/
│ │ │ │ │ ├── HttpServletRequestUtils.java
│ │ │ │ │ ├── HttpSessionOAuth2AuthorizedClientService.java
│ │ │ │ │ ├── TokenAccessor.java
│ │ │ │ │ ├── TokenIntrospector.java
│ │ │ │ │ ├── keycloakclient/
│ │ │ │ │ │ ├── DefaultKeycloakClient.java
│ │ │ │ │ │ ├── KeycloakClient.java
│ │ │ │ │ │ ├── KeycloakIntrospectResponse.java
│ │ │ │ │ │ ├── KeycloakServiceException.java
│ │ │ │ │ │ └── KeycloakUserInfo.java
│ │ │ │ │ └── security/
│ │ │ │ │ └── KeycloakLogoutHandler.java
│ │ │ │ └── web/
│ │ │ │ ├── AuthController.java
│ │ │ │ └── UiController.java
│ │ │ └── resources/
│ │ │ ├── application.yml
│ │ │ └── templates/
│ │ │ ├── applications.html
│ │ │ ├── fragments.html
│ │ │ ├── index.html
│ │ │ ├── profile.html
│ │ │ ├── security.html
│ │ │ └── settings.html
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── github/
│ │ └── thomasdarimont/
│ │ └── keycloak/
│ │ └── cac/
│ │ └── WebApplicationTestsSpringBoot.java
│ ├── java-opa-embedded/
│ │ ├── .gitignore
│ │ ├── jd-gui.cfg
│ │ ├── pom.xml
│ │ ├── readme.md
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── demo/
│ │ │ └── OpaEmbeddedDemo.java
│ │ └── resources/
│ │ ├── data/
│ │ │ └── user_roles.json
│ │ └── policy/
│ │ ├── app/
│ │ │ └── rbac/
│ │ │ └── policy.rego
│ │ └── policy.wasm
│ ├── jwt-client-authentication/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ └── maven-wrapper.properties
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ ├── readme.md
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── demo/
│ │ │ └── jwtclientauth/
│ │ │ └── JwtClientAuthApp.java
│ │ └── resources/
│ │ └── application.properties
│ ├── keycloak-js/
│ │ ├── package.json
│ │ └── readme.md
│ ├── oauth2-proxy/
│ │ ├── Dockerfile
│ │ ├── app/
│ │ │ └── main.go
│ │ ├── docker-compose.yml
│ │ ├── oauth2-proxy.cfg
│ │ └── readme.md
│ ├── offline-session-client/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ └── java/
│ │ └── demo/
│ │ └── OfflineSessionClient.java
│ ├── site/
│ │ ├── accountdeleted.html
│ │ ├── imprint.html
│ │ ├── lib/
│ │ │ └── keycloak-js/
│ │ │ ├── keycloak-authz.js
│ │ │ └── keycloak.js
│ │ ├── privacy.html
│ │ ├── site.html
│ │ └── terms.html
│ └── spring-boot-device-flow-client/
│ ├── .gitignore
│ ├── .mvn/
│ │ └── wrapper/
│ │ └── maven-wrapper.properties
│ ├── mvnw
│ ├── mvnw.cmd
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── demo/
│ │ └── SpringBootDeviceFlowApplication.java
│ └── resources/
│ └── application.properties
├── bin/
│ ├── applyRealmConfig.java
│ ├── createTlsCerts.java
│ ├── envcheck.java
│ ├── importCertificateIntoTruststore.java
│ ├── installOtel.java
│ ├── keycloakConfigCli.default.env
│ ├── keycloakConfigCli.java
│ └── realmImex.java
├── config/
│ └── stage/
│ └── dev/
│ ├── grafana/
│ │ └── provisioning/
│ │ ├── dashboards/
│ │ │ ├── dashboard.yml
│ │ │ ├── keycloak-capacity-planning-dashboard.json
│ │ │ ├── keycloak-metrics_rev1.json
│ │ │ └── keycloak-troubleshooting-dashboard.json
│ │ └── datasources/
│ │ └── datasources.yml
│ ├── opa/
│ │ ├── iam/
│ │ │ ├── authzen/
│ │ │ │ └── interop/
│ │ │ │ ├── access/
│ │ │ │ │ ├── policy.rego
│ │ │ │ │ └── v1/
│ │ │ │ │ └── search/
│ │ │ │ │ └── policy.rego
│ │ │ │ └── data.json
│ │ │ └── keycloak/
│ │ │ └── policy.rego
│ │ ├── inputs/
│ │ │ └── input.json
│ │ ├── opa.md
│ │ ├── policies/
│ │ │ └── keycloak/
│ │ │ ├── realms/
│ │ │ │ ├── opademo/
│ │ │ │ │ └── access/
│ │ │ │ │ ├── policy.rego
│ │ │ │ │ └── policy_test.rego
│ │ │ │ └── opademo2/
│ │ │ │ └── access/
│ │ │ │ └── policy.rego
│ │ │ └── utils/
│ │ │ └── kc/
│ │ │ └── helpers.rego
│ │ └── watch-opa.sh
│ ├── openldap/
│ │ └── demo.ldif
│ ├── otel/
│ │ ├── otel-collector-config-tls.yaml
│ │ └── otel-collector-config.yaml
│ ├── prometheus/
│ │ └── prometheus.yml
│ ├── realms/
│ │ ├── acme-api.yaml
│ │ ├── acme-apps.yaml
│ │ ├── acme-auth0.yaml
│ │ ├── acme-client-examples.yaml
│ │ ├── acme-demo.yaml
│ │ ├── acme-internal.yaml
│ │ ├── acme-ldap.yaml
│ │ ├── acme-offline-test.yaml
│ │ ├── acme-ops.yaml
│ │ ├── acme-passwordless.yaml
│ │ ├── acme-saml.yaml
│ │ ├── acme-stepup.yaml
│ │ ├── company-apps.yaml
│ │ ├── company-users.yaml
│ │ ├── master.yaml
│ │ ├── other/
│ │ │ ├── acme-internal-custom.yaml
│ │ │ ├── acme-saml.yaml
│ │ │ ├── acme-user-profile.yaml
│ │ │ ├── acme-vci.yaml
│ │ │ ├── acme-workshop-clients.yaml
│ │ │ ├── acme-workshop-idp.yaml
│ │ │ └── acme-workshop.yaml
│ │ └── workshop.yaml
│ └── tls/
│ └── .gitkeep
├── deployments/
│ └── local/
│ ├── cluster/
│ │ ├── apache/
│ │ │ ├── docker-compose-apache.yml
│ │ │ └── id.acme.test.conf
│ │ ├── caddy/
│ │ │ ├── caddy.json
│ │ │ └── docker-compose-caddy.yml
│ │ ├── cli/
│ │ │ ├── 0001-onstart-init.cli
│ │ │ ├── 0010-add-jmx-user.sh
│ │ │ ├── 0100-onstart-setup-remote-caches.cli
│ │ │ ├── 0200-onstart-setup-jgroups-encryption.cli
│ │ │ └── 0300-onstart-setup-ispn-jdbc-store.cli
│ │ ├── docker-compose.yml
│ │ ├── haproxy/
│ │ │ ├── Dockerfile
│ │ │ ├── docker-compose-haproxy.yml
│ │ │ └── haproxy.cfg
│ │ ├── haproxy-database-ispn/
│ │ │ ├── cli/
│ │ │ │ ├── 0010-add-jmx-user.sh
│ │ │ │ └── 0300-onstart-setup-ispn-jdbc-store.cli
│ │ │ └── docker-compose-haproxy-jdbc-store.yml
│ │ ├── haproxy-encrypted-ispn/
│ │ │ ├── cli/
│ │ │ │ └── 0200-onstart-setup-jgroups-encryption.cli
│ │ │ ├── docker-compose-enc-haproxy.yml
│ │ │ ├── ispn/
│ │ │ │ └── jgroups.p12
│ │ │ └── jgroups-keystore.sh
│ │ ├── haproxy-external-ispn/
│ │ │ ├── cli/
│ │ │ │ ├── 0100-onstart-setup-hotrod-caches.cli
│ │ │ │ └── 0100-onstart-setup-remote-caches.cli
│ │ │ ├── docker-compose-haproxy-ispn-hotrod.yml
│ │ │ ├── docker-compose-haproxy-ispn-remote.yml
│ │ │ ├── haproxy-external-ispn.env
│ │ │ ├── ispn/
│ │ │ │ ├── Dockerfile
│ │ │ │ ├── cacerts
│ │ │ │ ├── conf/
│ │ │ │ │ ├── infinispan-keycloak.xml
│ │ │ │ │ └── users.properties
│ │ │ │ ├── ispn-server.jks
│ │ │ │ └── ispn-truststore.jks
│ │ │ └── readme.md
│ │ ├── nginx/
│ │ │ ├── docker-compose-nginx.yml
│ │ │ └── nginx.conf
│ │ └── readme.md
│ ├── clusterx/
│ │ ├── docker-compose.yml
│ │ ├── haproxy/
│ │ │ ├── Dockerfile
│ │ │ ├── acme.test+1.p12
│ │ │ ├── docker-compose-haproxy.yml
│ │ │ └── haproxy.cfg
│ │ ├── haproxy-database-ispn/
│ │ │ ├── Dockerfile
│ │ │ ├── acme.test+1.p12
│ │ │ ├── cache-ispn-database.xml
│ │ │ ├── docker-compose.yml
│ │ │ ├── haproxy.cfg
│ │ │ └── readme.md
│ │ ├── haproxy-external-ispn/
│ │ │ ├── cache-ispn-remote.xml
│ │ │ ├── docker-compose-haproxy-ispn-remote.yml
│ │ │ ├── haproxy-external-ispn.env
│ │ │ ├── haproxy.cfg
│ │ │ └── ispn/
│ │ │ ├── Dockerfile
│ │ │ ├── cacerts
│ │ │ ├── conf/
│ │ │ │ ├── infinispan-keycloak.xml
│ │ │ │ └── users.properties
│ │ │ ├── ispn-server.jks
│ │ │ └── ispn-truststore.jks
│ │ ├── haproxy-external-ispn-database/
│ │ │ ├── cache-ispn-remote.xml
│ │ │ ├── docker-compose-haproxy-ispn-remote-database.yml
│ │ │ ├── haproxy-external-ispn.env
│ │ │ ├── haproxy.cfg
│ │ │ └── ispn/
│ │ │ ├── Dockerfile
│ │ │ ├── cacerts
│ │ │ ├── conf/
│ │ │ │ ├── infinispan-keycloak-database.xml
│ │ │ │ └── users.properties
│ │ │ ├── ispn-server.jks
│ │ │ └── ispn-truststore.jks
│ │ ├── keycloakx/
│ │ │ ├── Dockerfile
│ │ │ ├── cache-custom-jgroups-tcp.xml
│ │ │ ├── cache-custom-jgroups.xml
│ │ │ ├── cache-custom.xml
│ │ │ ├── jgroups-jdbcping-enc.xml
│ │ │ ├── jgroups-multicast-diag.xml
│ │ │ ├── jgroups-multicast-enc.xml
│ │ │ └── jgroups.p12
│ │ ├── nginx/
│ │ │ ├── docker-compose-nginx.yml
│ │ │ └── nginx.conf
│ │ └── readme.md
│ ├── dev/
│ │ ├── docker-compose-ci-github.yml
│ │ ├── docker-compose-grafana.yml
│ │ ├── docker-compose-graylog.yml
│ │ ├── docker-compose-keycloak.yml
│ │ ├── docker-compose-keycloakx.yml
│ │ ├── docker-compose-mssql.yml
│ │ ├── docker-compose-mysql.yml
│ │ ├── docker-compose-nats.yml
│ │ ├── docker-compose-opa.yml
│ │ ├── docker-compose-openldap.yml
│ │ ├── docker-compose-oracle.yml
│ │ ├── docker-compose-postgres.yml
│ │ ├── docker-compose-prometheus.yml
│ │ ├── docker-compose-provisioning.yml
│ │ ├── docker-compose-simplesaml.yml
│ │ ├── docker-compose-tls.yml
│ │ ├── docker-compose-tracing-tls.yml
│ │ ├── docker-compose-tracing.yml
│ │ ├── docker-compose.yml
│ │ ├── graylog/
│ │ │ ├── Dockerfile
│ │ │ ├── cli/
│ │ │ │ └── 0020-onstart-setup-graylog-logging.cli
│ │ │ ├── contentpacks/
│ │ │ │ └── iam-keycloak-content-pack-v1.json
│ │ │ └── modules/
│ │ │ └── logstash-gelf-1.14.1/
│ │ │ └── biz/
│ │ │ └── paluch/
│ │ │ └── logging/
│ │ │ └── main/
│ │ │ └── module.xml
│ │ ├── keycloak/
│ │ │ └── Dockerfile
│ │ ├── keycloak-common.env
│ │ ├── keycloak-db.env
│ │ ├── keycloak-ext/
│ │ │ └── readme.md
│ │ ├── keycloak-http.env
│ │ ├── keycloak-openldap.env
│ │ ├── keycloak-provisioning.env
│ │ ├── keycloak-tls.env
│ │ ├── keycloak-tracing.env
│ │ ├── keycloakx/
│ │ │ ├── Dockerfile
│ │ │ ├── Dockerfile-ci
│ │ │ └── health_check.sh
│ │ ├── mysql/
│ │ │ └── Dockerfile
│ │ ├── nats/
│ │ │ ├── readme.md
│ │ │ └── server.conf
│ │ ├── oracle/
│ │ │ └── Dockerfile
│ │ ├── otel-collector/
│ │ │ └── Dockerfile
│ │ ├── postgresql/
│ │ │ └── Dockerfile
│ │ ├── simplesaml/
│ │ │ └── idp/
│ │ │ ├── Dockerfile
│ │ │ └── authsources.php
│ │ └── sqlserver/
│ │ ├── Dockerfile
│ │ ├── db-init.sh
│ │ ├── db-init.sql
│ │ ├── docker-entrypoint.sh
│ │ └── mssql.conf
│ └── standalone/
│ ├── docker-compose.yml
│ ├── keycloak/
│ │ ├── Dockerfile
│ │ └── conf/
│ │ ├── keycloak.conf
│ │ └── quarkus.properties
│ ├── proxy/
│ │ └── nginx.conf
│ ├── readme.md
│ └── up.sh
├── keycloak/
│ ├── cli/
│ │ ├── 0001-onstart-init.cli
│ │ ├── 0010-register-smallrye-extensions.cli
│ │ ├── 0020-onstart-setup-graylog-logging.cli
│ │ └── 0100-onstart-deploy-extensions.sh
│ ├── clisnippets/
│ │ ├── http-client-config.md
│ │ ├── json-logging.md
│ │ ├── map-keycloak-endpoint-to-custom-endpint.md
│ │ ├── offline-sessions-lazy-loading.md
│ │ ├── undertow-access.md
│ │ └── undertow-request-logging.md
│ ├── config/
│ │ ├── jmxremote.password
│ │ ├── openid-config.json
│ │ └── quarkus.properties
│ ├── docker/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ └── docker/
│ │ ├── keycloak/
│ │ │ ├── Dockerfile.alpine-slim
│ │ │ ├── Dockerfile.ci.plain
│ │ │ ├── Dockerfile.plain
│ │ │ └── custom-docker-entrypoint.sh
│ │ └── keycloakx/
│ │ ├── Dockerfile.ci.plain
│ │ └── Dockerfile.plain
│ ├── e2e-tests/
│ │ ├── .gitignore
│ │ ├── cypress/
│ │ │ ├── e2e/
│ │ │ │ └── login/
│ │ │ │ └── login.cy.ts
│ │ │ ├── fixtures/
│ │ │ │ ├── messages.json
│ │ │ │ └── users.json
│ │ │ ├── plugins/
│ │ │ │ └── index.ts
│ │ │ ├── support/
│ │ │ │ ├── commands.ts
│ │ │ │ └── e2e.ts
│ │ │ ├── tsconfig.json
│ │ │ └── utils/
│ │ │ └── keycloakUtils.ts
│ │ ├── cypress.config.ts
│ │ ├── package.json
│ │ └── readme.md
│ ├── extensions/
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── github/
│ │ │ │ └── thomasdarimont/
│ │ │ │ └── keycloak/
│ │ │ │ └── custom/
│ │ │ │ ├── account/
│ │ │ │ │ ├── AccountActivity.java
│ │ │ │ │ ├── AccountChange.java
│ │ │ │ │ ├── AccountDeletion.java
│ │ │ │ │ ├── AccountEmail.java
│ │ │ │ │ ├── AccountPostLoginAction.java
│ │ │ │ │ ├── MfaChange.java
│ │ │ │ │ ├── RequestAccountDeletionActionToken.java
│ │ │ │ │ ├── RequestAccountDeletionActionTokenHandler.java
│ │ │ │ │ └── console/
│ │ │ │ │ └── AcmeAccountConsoleFactory.java
│ │ │ │ ├── admin/
│ │ │ │ │ └── ui/
│ │ │ │ │ └── example/
│ │ │ │ │ └── ExampleUiPageProvider.java
│ │ │ │ ├── audit/
│ │ │ │ │ └── AcmeAuditListener.java
│ │ │ │ ├── auth/
│ │ │ │ │ ├── authzen/
│ │ │ │ │ │ ├── AuthZen.java
│ │ │ │ │ │ └── AuthzenClient.java
│ │ │ │ │ ├── checkaccess/
│ │ │ │ │ │ └── CheckAccessAuthenticator.java
│ │ │ │ │ ├── confirmcookie/
│ │ │ │ │ │ └── ConfirmCookieAuthenticator.java
│ │ │ │ │ ├── customcookie/
│ │ │ │ │ │ └── CustomCookieAuthenticator.java
│ │ │ │ │ ├── debug/
│ │ │ │ │ │ └── DebugAuthenticator.java
│ │ │ │ │ ├── demo/
│ │ │ │ │ │ └── SkippableRequiredAction.java
│ │ │ │ │ ├── dynamicidp/
│ │ │ │ │ │ └── DynamicIdpAuthenticator.java
│ │ │ │ │ ├── hello/
│ │ │ │ │ │ └── HelloAuthenticator.java
│ │ │ │ │ ├── idpselection/
│ │ │ │ │ │ └── AcmeDynamicIdpLookupUsernameForm.java
│ │ │ │ │ ├── magiclink/
│ │ │ │ │ │ └── MagicLinkAuthenticator.java
│ │ │ │ │ ├── mfa/
│ │ │ │ │ │ ├── MfaInfo.java
│ │ │ │ │ │ ├── emailcode/
│ │ │ │ │ │ │ ├── EmailCodeAuthenticatorForm.java
│ │ │ │ │ │ │ ├── EmailCodeCredentialModel.java
│ │ │ │ │ │ │ ├── EmailCodeCredentialProvider.java
│ │ │ │ │ │ │ └── RegisterEmailCodeRequiredAction.java
│ │ │ │ │ │ ├── otp/
│ │ │ │ │ │ │ └── AcmeOTPFormAuthenticator.java
│ │ │ │ │ │ ├── setup/
│ │ │ │ │ │ │ └── SelectMfaMethodAuthenticator.java
│ │ │ │ │ │ └── sms/
│ │ │ │ │ │ ├── PhoneNumberUtils.java
│ │ │ │ │ │ ├── SmsAuthenticator.java
│ │ │ │ │ │ ├── SmsCodeSender.java
│ │ │ │ │ │ ├── client/
│ │ │ │ │ │ │ ├── SmsClient.java
│ │ │ │ │ │ │ ├── SmsClientFactory.java
│ │ │ │ │ │ │ └── mock/
│ │ │ │ │ │ │ └── MockSmsClient.java
│ │ │ │ │ │ ├── credentials/
│ │ │ │ │ │ │ ├── SmsCredentialModel.java
│ │ │ │ │ │ │ └── SmsCredentialProvider.java
│ │ │ │ │ │ └── updatephone/
│ │ │ │ │ │ └── UpdatePhoneNumberRequiredAction.java
│ │ │ │ │ ├── net/
│ │ │ │ │ │ └── NetworkAuthenticator.java
│ │ │ │ │ ├── opa/
│ │ │ │ │ │ ├── OpaAccessResponse.java
│ │ │ │ │ │ ├── OpaAuthenticator.java
│ │ │ │ │ │ ├── OpaCheckAccessAction.java
│ │ │ │ │ │ └── OpaClient.java
│ │ │ │ │ ├── passwordform/
│ │ │ │ │ │ └── FederationAwarePasswordForm.java
│ │ │ │ │ ├── trusteddevice/
│ │ │ │ │ │ ├── TrustedDeviceCookie.java
│ │ │ │ │ │ ├── TrustedDeviceName.java
│ │ │ │ │ │ ├── TrustedDeviceToken.java
│ │ │ │ │ │ ├── action/
│ │ │ │ │ │ │ ├── ManageTrustedDeviceAction.java
│ │ │ │ │ │ │ └── TrustedDeviceInfo.java
│ │ │ │ │ │ ├── auth/
│ │ │ │ │ │ │ └── TrustedDeviceAuthenticator.java
│ │ │ │ │ │ ├── credentials/
│ │ │ │ │ │ │ ├── TrustedDeviceCredentialInput.java
│ │ │ │ │ │ │ ├── TrustedDeviceCredentialModel.java
│ │ │ │ │ │ │ └── TrustedDeviceCredentialProvider.java
│ │ │ │ │ │ └── support/
│ │ │ │ │ │ └── UserAgentParser.java
│ │ │ │ │ ├── userpasswordform/
│ │ │ │ │ │ └── AcmeCaptchaUsernamePasswordForm.java
│ │ │ │ │ └── verifyemailcode/
│ │ │ │ │ └── VerifyEmailCodeAction.java
│ │ │ │ ├── authz/
│ │ │ │ │ ├── filter/
│ │ │ │ │ │ └── AcmeAccessFilter.java
│ │ │ │ │ └── policies/
│ │ │ │ │ └── AcmeImpersonationPolicyProvider.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── ClientConfig.java
│ │ │ │ │ ├── ConfigAccessor.java
│ │ │ │ │ ├── MapConfig.java
│ │ │ │ │ └── RealmConfig.java
│ │ │ │ ├── consent/
│ │ │ │ │ ├── ConsentSelectionAction.java
│ │ │ │ │ ├── ScopeBean.java
│ │ │ │ │ ├── ScopeField.java
│ │ │ │ │ └── ScopeFieldBean.java
│ │ │ │ ├── context/
│ │ │ │ │ └── ContextSelectionAction.java
│ │ │ │ ├── email/
│ │ │ │ │ └── AcmeEmailSenderProvider.java
│ │ │ │ ├── endpoints/
│ │ │ │ │ ├── CorsUtils.java
│ │ │ │ │ ├── CustomAdminResourceProvider.java
│ │ │ │ │ ├── CustomResource.java
│ │ │ │ │ ├── CustomResourceProvider.java
│ │ │ │ │ ├── account/
│ │ │ │ │ │ └── AcmeAccountResource.java
│ │ │ │ │ ├── admin/
│ │ │ │ │ │ ├── AdminSettingsResource.java
│ │ │ │ │ │ ├── CustomAdminResource.java
│ │ │ │ │ │ └── UserProvisioningResource.java
│ │ │ │ │ ├── applications/
│ │ │ │ │ │ └── ApplicationsInfoResource.java
│ │ │ │ │ ├── branding/
│ │ │ │ │ │ └── BrandingResource.java
│ │ │ │ │ ├── credentials/
│ │ │ │ │ │ └── UserCredentialsInfoResource.java
│ │ │ │ │ ├── demo/
│ │ │ │ │ │ └── DemosResource.java
│ │ │ │ │ ├── idp/
│ │ │ │ │ │ └── IdpApplications.java
│ │ │ │ │ ├── migration/
│ │ │ │ │ │ ├── TokenMigrationResource.java
│ │ │ │ │ │ └── UserImportMigrationResource.java
│ │ │ │ │ ├── offline/
│ │ │ │ │ │ ├── OfflineSessionPropagationResource.java
│ │ │ │ │ │ ├── SessionPropagationActionToken.java
│ │ │ │ │ │ └── SessionPropagationActionTokenHandler.java
│ │ │ │ │ ├── profile/
│ │ │ │ │ │ ├── ProfileData.java
│ │ │ │ │ │ └── UserProfileResource.java
│ │ │ │ │ └── settings/
│ │ │ │ │ └── UserSettingsResource.java
│ │ │ │ ├── eventpublishing/
│ │ │ │ │ ├── AcmeEventPublisherEventListener.java
│ │ │ │ │ ├── EventPublisher.java
│ │ │ │ │ ├── NatsEventPublisher.java
│ │ │ │ │ └── NoopPublisher.java
│ │ │ │ ├── health/
│ │ │ │ │ ├── CustomHealthChecks.java
│ │ │ │ │ └── CustomReadinessCheck.java
│ │ │ │ ├── idp/
│ │ │ │ │ ├── azure/
│ │ │ │ │ │ ├── CustomAzureADGroupMapper.java
│ │ │ │ │ │ └── CustomEntraIdProfileMapper.java
│ │ │ │ │ ├── brokering/
│ │ │ │ │ │ └── RestrictBrokeredUserMapper.java
│ │ │ │ │ ├── linking/
│ │ │ │ │ │ └── AcmeIdpLinkAction.java
│ │ │ │ │ ├── oidc/
│ │ │ │ │ │ └── AcmeOidcIdentityProvider.java
│ │ │ │ │ └── social/
│ │ │ │ │ └── linkedin/
│ │ │ │ │ └── LinkedInUserProfileImportIdpMapper.java
│ │ │ │ ├── infinispan/
│ │ │ │ │ └── CustomInfinispanUserSessionProviderFactory.java
│ │ │ │ ├── jpa/
│ │ │ │ │ └── CustomQuarkusJpaConnectionProviderFactory.java
│ │ │ │ ├── metrics/
│ │ │ │ │ ├── KeycloakMetric.java
│ │ │ │ │ ├── KeycloakMetricAccessor.java
│ │ │ │ │ ├── KeycloakMetricStore.java
│ │ │ │ │ ├── KeycloakMetrics.java
│ │ │ │ │ ├── RealmMetricUpdater.java
│ │ │ │ │ ├── RealmMetricsUpdater.java
│ │ │ │ │ └── events/
│ │ │ │ │ ├── MetricEventListenerProvider.java
│ │ │ │ │ └── MetricEventRecorder.java
│ │ │ │ ├── migration/
│ │ │ │ │ └── acmecred/
│ │ │ │ │ ├── AcmeCredentialModel.java
│ │ │ │ │ ├── AcmeCredentialProvider.java
│ │ │ │ │ └── AcmePasswordValidator.java
│ │ │ │ ├── oauth/
│ │ │ │ │ ├── client/
│ │ │ │ │ │ └── OauthClientCredentialsTokenManager.java
│ │ │ │ │ └── tokenexchange/
│ │ │ │ │ ├── ApiKeyTokenExchangeProvider.java
│ │ │ │ │ ├── CustomTokenExchangeProvider.java
│ │ │ │ │ └── CustomV2TokenExchangeProvider.java
│ │ │ │ ├── oidc/
│ │ │ │ │ ├── ageinfo/
│ │ │ │ │ │ └── AgeInfoMapper.java
│ │ │ │ │ ├── authzenclaims/
│ │ │ │ │ │ └── AuthzenClaimMapper.java
│ │ │ │ │ ├── opaclaims/
│ │ │ │ │ │ └── OpaClaimMapper.java
│ │ │ │ │ ├── remoteclaims/
│ │ │ │ │ │ └── RemoteOidcMapper.java
│ │ │ │ │ ├── scopes/
│ │ │ │ │ │ └── OnlyGrantedScopesMapper.java
│ │ │ │ │ ├── userdata/
│ │ │ │ │ │ └── AcmeUserInfoMapper.java
│ │ │ │ │ └── wellknown/
│ │ │ │ │ └── AcmeOidcWellKnownProvider.java
│ │ │ │ ├── profile/
│ │ │ │ │ ├── AcmeUserAttributes.java
│ │ │ │ │ ├── emailupdate/
│ │ │ │ │ │ └── UpdateEmailRequiredAction.java
│ │ │ │ │ └── phonenumber/
│ │ │ │ │ └── AcmePhoneValidator.java
│ │ │ │ ├── registration/
│ │ │ │ │ ├── actiontokens/
│ │ │ │ │ │ └── AcmeExecuteActionsActionTokenHandler.java
│ │ │ │ │ └── formaction/
│ │ │ │ │ ├── CustomRegistrationUserCreation.java
│ │ │ │ │ └── WelcomeEmailFormAction.java
│ │ │ │ ├── saml/
│ │ │ │ │ ├── AcmeSamlAuthenticationPreprocessor.java
│ │ │ │ │ ├── brokering/
│ │ │ │ │ │ └── AcmeSamlRoleImporter.java
│ │ │ │ │ └── rolelist/
│ │ │ │ │ └── AcmeSamlRoleListMapper.java
│ │ │ │ ├── scheduling/
│ │ │ │ │ ├── ScheduledTaskProvider.java
│ │ │ │ │ ├── ScheduledTaskProviderFactory.java
│ │ │ │ │ ├── ScheduledTaskSpi.java
│ │ │ │ │ └── tasks/
│ │ │ │ │ └── AcmeScheduledTaskProvider.java
│ │ │ │ ├── security/
│ │ │ │ │ ├── filter/
│ │ │ │ │ │ └── IpAccessFilter.java
│ │ │ │ │ └── friendlycaptcha/
│ │ │ │ │ ├── FriendlyCaptcha.java
│ │ │ │ │ ├── FriendlyCaptchaClient.java
│ │ │ │ │ ├── FriendlyCaptchaConfig.java
│ │ │ │ │ └── FriendlyCaptchaFormAction.java
│ │ │ │ ├── support/
│ │ │ │ │ ├── AuthUtils.java
│ │ │ │ │ ├── ConfigUtils.java
│ │ │ │ │ ├── CookieHelper.java
│ │ │ │ │ ├── CookieUtils.java
│ │ │ │ │ ├── CredentialUtils.java
│ │ │ │ │ ├── LocaleUtils.java
│ │ │ │ │ ├── RealmUtils.java
│ │ │ │ │ ├── RequiredActionUtils.java
│ │ │ │ │ ├── ScopeUtils.java
│ │ │ │ │ ├── TokenUtils.java
│ │ │ │ │ ├── UserSessionUtils.java
│ │ │ │ │ └── UserUtils.java
│ │ │ │ ├── terms/
│ │ │ │ │ └── AcmeTermsAndConditionsAction.java
│ │ │ │ ├── themes/
│ │ │ │ │ └── login/
│ │ │ │ │ ├── AcmeFreeMarkerLoginFormsProvider.java
│ │ │ │ │ ├── AcmeLoginBean.java
│ │ │ │ │ └── AcmeUrlBean.java
│ │ │ │ └── userstorage/
│ │ │ │ ├── adhoc/
│ │ │ │ │ └── AdhocUserStorageProvider.java
│ │ │ │ ├── ldap/
│ │ │ │ │ ├── AcmeLDAPStorageProvider.java
│ │ │ │ │ └── AcmeReadonlyLDAPUserModelDelegate.java
│ │ │ │ └── remote/
│ │ │ │ ├── AcmeUserAdapter.java
│ │ │ │ ├── AcmeUserStorageProvider.java
│ │ │ │ └── accountclient/
│ │ │ │ ├── AccountClientOptions.java
│ │ │ │ ├── AcmeAccountClient.java
│ │ │ │ ├── AcmeUser.java
│ │ │ │ ├── SimpleAcmeAccountClient.java
│ │ │ │ ├── UserSearchInput.java
│ │ │ │ ├── UserSearchOutput.java
│ │ │ │ ├── VerifyCredentialsInput.java
│ │ │ │ └── VerifyCredentialsOutput.java
│ │ │ └── resources/
│ │ │ ├── META-INF/
│ │ │ │ └── keycloak-scripts.json
│ │ │ ├── ignore_default-persistence.xml
│ │ │ ├── my-script-authenticator.js
│ │ │ └── my-script-mapper.js
│ │ └── test/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── github/
│ │ │ └── thomasdarimont/
│ │ │ └── keycloak/
│ │ │ └── custom/
│ │ │ ├── BoostrapTest.java
│ │ │ ├── KeycloakEnvironment.java
│ │ │ ├── KeycloakIntegrationTest.java
│ │ │ └── KeycloakTestSupport.java
│ │ └── resources/
│ │ ├── log4j.properties
│ │ └── testcontainers.properties
│ ├── http-tests/
│ │ ├── advanced_oauth_par.http
│ │ ├── advanced_oauth_resources.http
│ │ ├── custom-token-migration.http
│ │ ├── custom_token_exchange.http
│ │ ├── dynamic-client-registration.http
│ │ ├── example-requests.http
│ │ ├── grant_type_client_credentials-requests.http
│ │ ├── grant_type_password-requests.http
│ │ ├── grant_type_refreshtoken-requests.http
│ │ ├── http-client.env.json
│ │ ├── implicit-flow-request.http
│ │ ├── keycloak-lightweight-token-requests.http
│ │ ├── oidc-endpoint-requests.http
│ │ ├── token_exchange.http
│ │ ├── token_exchange_api_gateway.http
│ │ ├── token_exchange_fed-identity-chaining.http
│ │ └── token_exchange_v2.http
│ ├── misc/
│ │ ├── custom-keycloak-server/
│ │ │ ├── pom.xml
│ │ │ ├── readme.md
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── copy-to-keycloak/
│ │ │ │ └── conf/
│ │ │ │ └── quarkus.properties
│ │ │ ├── java/
│ │ │ │ └── demo/
│ │ │ │ └── events/
│ │ │ │ └── MyEventListener.java
│ │ │ └── resources/
│ │ │ ├── META-INF/
│ │ │ │ ├── keycloak-themes.json
│ │ │ │ └── keycloak.conf
│ │ │ └── theme/
│ │ │ └── custom/
│ │ │ └── login/
│ │ │ ├── messages/
│ │ │ │ └── messages_en.properties
│ │ │ ├── resources/
│ │ │ │ ├── css/
│ │ │ │ │ └── custom-login.css
│ │ │ │ └── js/
│ │ │ │ └── custom-login.js
│ │ │ └── theme.properties
│ │ └── snippets/
│ │ ├── create-keycloak-config-cli-client.txt
│ │ ├── jgroups-debugging.txt
│ │ ├── jmx-config-keycloakx.md
│ │ ├── jmx-config-wildfly.md
│ │ ├── jvm-settings.txt
│ │ ├── keycloakx-cli.md
│ │ ├── metrics-examples.txt
│ │ └── overlay-keycloak-endpoint-undertow.txt
│ ├── patches/
│ │ ├── keycloak-model-infinispan-patch/
│ │ │ ├── pom.xml
│ │ │ ├── readme.md
│ │ │ └── src/
│ │ │ └── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── keycloak/
│ │ │ ├── models/
│ │ │ │ └── sessions/
│ │ │ │ └── infinispan/
│ │ │ │ └── CacheDecorators.java
│ │ │ └── patch/
│ │ │ └── infinispan/
│ │ │ └── keymappers/
│ │ │ └── CustomDefaultTwoWayKey2StringMapper.java
│ │ ├── wildfly-clustering-infinispan-extension-patch/
│ │ │ ├── pom.xml
│ │ │ ├── readme.md
│ │ │ └── src/
│ │ │ └── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── jboss/
│ │ │ └── as/
│ │ │ └── clustering/
│ │ │ └── infinispan/
│ │ │ └── subsystem/
│ │ │ ├── InfinispanSubsystemXMLReader.java
│ │ │ ├── LocalDescriptions.properties
│ │ │ ├── RemoteStoreResourceDefinition.java
│ │ │ ├── RemoteStoreServiceConfigurator.java
│ │ │ ├── XMLAttribute.java
│ │ │ └── remote/
│ │ │ └── RemoteCacheContainerResourceDefinition.java
│ │ ├── wildfly-clustering-infinispan-extension-patch-25.0.x/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── jboss/
│ │ │ └── as/
│ │ │ └── clustering/
│ │ │ └── infinispan/
│ │ │ └── subsystem/
│ │ │ ├── InfinispanSubsystemXMLReader.java
│ │ │ ├── LocalDescriptions.properties
│ │ │ ├── RemoteStoreResourceDefinition.java
│ │ │ ├── RemoteStoreServiceConfigurator.java
│ │ │ └── remote/
│ │ │ └── RemoteCacheContainerResourceDefinition.java
│ │ └── wildfly-clustering-infinispan-extension-patch-26.0.x/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ └── java/
│ │ └── org/
│ │ └── jboss/
│ │ └── as/
│ │ └── clustering/
│ │ └── infinispan/
│ │ └── subsystem/
│ │ ├── InfinispanSubsystemXMLReader.java
│ │ ├── LocalDescriptions.properties
│ │ ├── RemoteStoreResourceDefinition.java
│ │ └── RemoteStoreServiceConfigurator.java
│ └── themes/
│ ├── acme-account.v2/
│ │ └── account/
│ │ ├── messages/
│ │ │ ├── messages_de.properties
│ │ │ └── messages_en.properties
│ │ ├── resources/
│ │ │ ├── content.json
│ │ │ └── css/
│ │ │ └── styles.css
│ │ └── theme.properties
│ ├── admin-custom/
│ │ └── admin/
│ │ ├── admin-settings.ftl
│ │ ├── resources/
│ │ │ └── js/
│ │ │ └── admin-settings.js
│ │ └── theme.properties
│ ├── apps/
│ │ └── login/
│ │ ├── login.ftl
│ │ ├── messages/
│ │ │ ├── messages_de.properties
│ │ │ └── messages_en.properties
│ │ ├── register.ftl
│ │ ├── resources/
│ │ │ ├── css/
│ │ │ │ └── custom-login.css
│ │ │ └── js/
│ │ │ └── custom-login.js
│ │ ├── terms.ftl
│ │ └── theme.properties
│ ├── custom/
│ │ └── login/
│ │ ├── messages/
│ │ │ └── messages_en.properties
│ │ ├── register.ftl
│ │ ├── resources/
│ │ │ ├── css/
│ │ │ │ └── custom-login.css
│ │ │ └── js/
│ │ │ └── custom-login.js
│ │ └── theme.properties
│ ├── internal/
│ │ ├── account/
│ │ │ ├── account.ftl
│ │ │ ├── messages/
│ │ │ │ ├── messages_de.properties
│ │ │ │ └── messages_en.properties
│ │ │ └── theme.properties
│ │ ├── email/
│ │ │ ├── html/
│ │ │ │ ├── acme-account-blocked.ftl
│ │ │ │ ├── acme-account-deletion-requested.ftl
│ │ │ │ ├── acme-account-updated.ftl
│ │ │ │ ├── acme-email-verification-with-code.ftl
│ │ │ │ ├── acme-magic-link.ftl
│ │ │ │ ├── acme-mfa-added.ftl
│ │ │ │ ├── acme-mfa-removed.ftl
│ │ │ │ ├── acme-passkey-added.ftl
│ │ │ │ ├── acme-passkey-removed.ftl
│ │ │ │ ├── acme-trusted-device-added.ftl
│ │ │ │ ├── acme-trusted-device-removed.ftl
│ │ │ │ ├── acme-welcome.ftl
│ │ │ │ ├── code-email.ftl
│ │ │ │ └── template.ftl
│ │ │ ├── messages/
│ │ │ │ ├── messages_de.properties
│ │ │ │ └── messages_en.properties
│ │ │ ├── text/
│ │ │ │ ├── acme-account-blocked.ftl
│ │ │ │ ├── acme-account-deletion-requested.ftl
│ │ │ │ ├── acme-account-updated.ftl
│ │ │ │ ├── acme-email-verification-with-code.ftl
│ │ │ │ ├── acme-magic-link.ftl
│ │ │ │ ├── acme-mfa-added.ftl
│ │ │ │ ├── acme-mfa-removed.ftl
│ │ │ │ ├── acme-passkey-added.ftl
│ │ │ │ ├── acme-passkey-removed.ftl
│ │ │ │ ├── acme-trusted-device-added.ftl
│ │ │ │ ├── acme-trusted-device-removed.ftl
│ │ │ │ ├── acme-welcome.ftl
│ │ │ │ ├── code-email.ftl
│ │ │ │ └── template.ftl
│ │ │ └── theme.properties
│ │ └── login/
│ │ ├── email-code-form.ftl
│ │ ├── login-confirm-cookie-form.ftl
│ │ ├── login-magic-link.ftl
│ │ ├── login-otp.ftl
│ │ ├── login-password.ftl
│ │ ├── login-select-mfa-method.ftl
│ │ ├── login-skippable-action.ftl
│ │ ├── login-sms.ftl
│ │ ├── login-username.ftl
│ │ ├── manage-trusted-device-form.ftl
│ │ ├── messages/
│ │ │ ├── messages_de.properties
│ │ │ └── messages_en.properties
│ │ ├── register.ftl
│ │ ├── resources/
│ │ │ ├── css/
│ │ │ │ └── custom-login.css
│ │ │ └── js/
│ │ │ └── custom-login.js
│ │ ├── select-consent-form.ftl
│ │ ├── theme.properties
│ │ ├── update-email-form.ftl
│ │ ├── update-phone-number-form.ftl
│ │ ├── verify-email-form.ftl
│ │ └── verify-phone-number-form.ftl
│ ├── internal-modern/
│ │ ├── account/
│ │ │ └── theme.properties
│ │ ├── email/
│ │ │ ├── messages/
│ │ │ │ ├── messages_de.properties
│ │ │ │ └── messages_en.properties
│ │ │ └── theme.properties
│ │ └── login/
│ │ ├── context-selection.ftl
│ │ ├── login-applications.ftl
│ │ ├── login-idp-selection.ftl
│ │ ├── login-password.ftl
│ │ ├── login-username.ftl
│ │ ├── login-verify-email.ftl
│ │ ├── login.ftl
│ │ ├── messages/
│ │ │ ├── messages_de.properties
│ │ │ └── messages_en.properties
│ │ ├── register.ftl
│ │ ├── resources/
│ │ │ ├── css/
│ │ │ │ └── custom-modern-login.css
│ │ │ └── js/
│ │ │ └── custom-modern-login.js
│ │ ├── select-authenticator.ftl
│ │ ├── template.ftl
│ │ └── theme.properties
│ ├── minimal/
│ │ └── login/
│ │ ├── resources/
│ │ │ ├── css/
│ │ │ │ └── custom-login.css
│ │ │ └── js/
│ │ │ └── custom-login.js
│ │ └── theme.properties
│ └── minimal-branding/
│ └── login/
│ ├── customizations.ftl
│ ├── info.ftl
│ ├── login-update-password.ftl
│ ├── resources/
│ │ ├── css/
│ │ │ └── custom-login.css
│ │ └── js/
│ │ └── custom-login.js
│ ├── template.ftl
│ └── theme.properties
├── keycloak.env
├── maven-settings.xml
├── pom.xml
├── readme.md
├── start.java
├── stop.java
└── tools/
├── kcadm/
│ └── readme.md
├── postman/
│ ├── acme.postman_collection.json
│ ├── acme.postman_environment_http.json
│ ├── acme.postman_environment_https.json
│ ├── acme.postman_globals.json
│ └── readme.md
├── session-generator/
│ ├── .gitignore
│ ├── .mvn/
│ │ └── wrapper/
│ │ ├── MavenWrapperDownloader.java
│ │ └── maven-wrapper.properties
│ ├── mvnw
│ ├── mvnw.cmd
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── github/
│ │ │ └── thomasdarimont/
│ │ │ └── keycloak/
│ │ │ └── tools/
│ │ │ └── sessiongenerator/
│ │ │ └── SessionGeneratorApplication.java
│ │ └── resources/
│ │ └── application.properties
│ └── test/
│ └── java/
│ └── com/
│ └── github/
│ └── thomasdarimont/
│ └── keycloak/
│ └── tools/
│ └── sessiongenerator/
│ └── SessionGeneratorApplicationTests.java
└── tcpdump/
├── Dockerfile
└── readme.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/workflows/build.yml
================================================
name: ACME Keycloak Build
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Configure JDK 21
uses: actions/setup-java@v1
with:
java-version: 21
- name: Cache Maven packages
uses: actions/cache@v1
with:
path: ~/.m2
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-m2
- name: Maven - verify
run: mvn --batch-mode -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn verify --file pom.xml --settings maven-settings.xml
- name: Maven - integration-test
run: mvn --batch-mode -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -Pwith-integration-tests test --file pom.xml --settings maven-settings.xml
- name: Maven - build image
run: mvn --batch-mode -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -DskipTests io.fabric8:docker-maven-plugin:build --file pom.xml --settings maven-settings.xml
================================================
FILE: .github/workflows/e2e-tests.yml
================================================
name: Acme e2e Test CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
e2e-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Configure JDK 21
uses: actions/setup-java@v1
with:
java-version: 21
- name: Configure Node.js '18.x'
uses: actions/setup-node@v1
with:
node-version: '18.x'
- name: Prepare artifacts (e.g. extensions) for docker-compose stack
run: mvn --batch-mode -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=warn -DskipTests verify --file pom.xml --settings maven-settings.xml -pl keycloak/extensions,keycloak/docker
- name: Build the docker-compose stack
run: |
USER="$(id -u)"
GROUP=""
export USER
export GROUP
echo "Running as ${USER}:${GROUP}"
java bin/envcheck.java
touch deployments/local/dev/keycloakx/acme.test+1.pem
java start.java --http --extensions=jar --keycloak=keycloakx --ci=github --detach
- name: Show current containers
run: |
docker ps -a
# - name: Check keycloak is reachable
# run: docker run --network container:dev_acme-keycloak_1 --rm appropriate/curl -s --retry 15 --max-time 180 --retry-connrefused http://localhost:8080/auth/realms/acme-internal
- name: Sleep
uses: jakejarvis/wait-action@master
with:
time: '70s'
- name: Check docker-compose stack
if: ${{ always() }}
run: |
docker ps -a
docker inspect dev-acme-keycloak-1
docker logs --details dev-acme-keycloak-1
- name: Run cypress tests
working-directory: ./keycloak/e2e-tests
# https://docs.cypress.io/guides/references/configuration#Timeouts
run: |
yarn install
docker run --network container:dev-acme-keycloak-1 --rm -v "${PWD}":/e2e -w /e2e --entrypoint=cypress cypress/included:10.8.0 run --config pageLoadTimeout=70000,defaultCommandTimeout=10000,watchForFileChanges=false --env keycloak_host=http://localhost:8080
- name: Archive testrun video
if: ${{ always() }}
uses: actions/upload-artifact@v2
with:
name: testrun-video
path: ./keycloak/e2e-tests/cypress/videos/
retention-days: 1
- name: Shutdown the docker-compose stack
if: ${{ always() }}
run: java stop.java --skip=grafana
================================================
FILE: .gitignore
================================================
!testrun/.gitkeep
testrun/
!run/.gitkeep
run/
deployments/local/dev/run/
deployments/local/cluster/haproxy-external-ispn/ispn/data/ispn-1/
deployments/local/cluster/haproxy-external-ispn/ispn/data/ispn-2/
deployments/local/clusterx/haproxy-external-ispn/ispn/data/ispn-1/
deployments/local/clusterx/haproxy-external-ispn/ispn/data/ispn-2/
!deployments/local/cluster/run/.gitkeep
deployments/local/cluster/run/
*.pem
*-key.pem
local.env
module-thorntail.xml
!scratch/.gitkeep
scratch/
*.jfr
!keycloak/imex/.gitkeep
keycloak/imex/*
config/stage/dev/tls/*.pem
config/stage/dev/tls/*.p12
config/stage/dev/tls/*.crt
config/stage/dev/tls/*.key
# Exclude cypress resources
node_modules
src/test/e2e/cypress/reports
src/test/e2e/cypress/videos
src/test/e2e/cypress/screenshots
# Created by https://www.gitignore.io/api/osx,java,maven,gradle,eclipse,intellij+all,visualstudiocode
# Edit at https://www.gitignore.io/?templates=osx,java,maven,gradle,eclipse,intellij+all,visualstudiocode
### Eclipse ###
.metadata
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
.recommenders
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# PyDev specific (Python IDE for Eclipse)
*.pydevproject
# CDT-specific (C/C++ Development Tooling)
.cproject
# CDT- autotools
.autotools
# Java annotation processor (APT)
.factorypath
# PDT-specific (PHP Development Tools)
.buildpath
# sbteclipse plugin
.target
# Tern plugin
.tern-project
# TeXlipse plugin
.texlipse
# STS (Spring Tool Suite)
.springBeans
# Code Recommenders
.recommenders/
# Annotation Processing
.apt_generated/
# Scala IDE specific (Scala & Java development for Eclipse)
.cache-main
.scala_dependencies
.worksheet
### Eclipse Patch ###
# Eclipse Core
.project
# JDT-specific (Eclipse Java Development Tools)
.classpath
# Annotation Processing
.apt_generated
.sts4-cache/
### Intellij+all ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/**/usage.statistics.xml
.idea/**/dictionaries
.idea/**/shelf
# Generated files
.idea/**/contentModel.xml
# Sensitive or high-churn files
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/dbnavigator.xml
# Gradle
.idea/**/gradle.xml
.idea/**/libraries
# Gradle and Maven with auto-import
# When using Gradle or Maven with auto-import, you should exclude module files,
# since they will be recreated, and may cause churn. Uncomment if using
# auto-import.
# .idea/modules.xml
# .idea/*.iml
# .idea/modules
# CMake
cmake-build-*/
# Mongo Explorer plugin
.idea/**/mongoSettings.xml
# File-based project format
*.iws
# IntelliJ
out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
# Editor-based Rest Client
.idea/httpRequests
# Android studio 3.1+ serialized cache file
.idea/caches/build_file_checksums.ser
### Intellij+all Patch ###
# Ignores the whole .idea folder and all .iml files
# See https://github.com/joeblau/gitignore.io/issues/186 and https://github.com/joeblau/gitignore.io/issues/360
.idea/
# Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-249601023
*.iml
modules.xml
.idea/misc.xml
*.ipr
# Sonarlint plugin
.idea/sonarlint
### Java ###
# Compiled class file
*.class
# Log file
*.log
# BlueJ files
*.ctxt
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
!bin/opentelemetry-javaagent-*.jar
*.war
*.nar
*.ear
*.zip
*.tar.gz
*.rar
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
.mvn/timing.properties
.mvn/wrapper/maven-wrapper.jar
### OSX ###
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
### Gradle ###
.gradle
build/
# Ignore Gradle GUI config
gradle-app.setting
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
# Cache of project
.gradletasknamecache
# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898
# gradle/wrapper/gradle-wrapper.properties
### Gradle Patch ###
**/build/
# End of https://www.gitignore.io/api/osx,java,maven,gradle,eclipse,intellij+all,visualstudiocode
# Created by https://www.toptal.com/developers/gitignore/api/node
# Edit at https://www.toptal.com/developers/gitignore?templates=node
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
.env*.local
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
# Nuxt.js build / generate output
.nuxt
dist
# Storybook build outputs
.out
.storybook-out
storybook-static
# rollup.js default build output
dist/
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# Temporary folders
tmp/
temp/
# End of https://www.toptal.com/developers/gitignore/api/node
/apps/offline-session-client/data/
/deployments/local/cluster/haproxy-external-ispn/ispn/data/sessions/
================================================
FILE: .run/Acme Backend API Quarkus.run.xml
================================================
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="backend-api-quarkus" type="QuarkusRunConfigurationType" factoryName="Quarkus">
<module name="backend-api-quarkus" />
<backend-api-quarkus>
<MavenSettings>
<option name="myGeneralSettings" />
<option name="myRunnerSettings" />
<option name="myRunnerParameters">
<MavenRunnerParameters>
<option name="profiles">
<set />
</option>
<option name="goals">
<list>
<option value="quarkus:dev" />
</list>
</option>
<option name="pomFileName" value="pom.xml" />
<option name="profilesMap">
<map />
</option>
<option name="resolveToWorkspace" value="false" />
<option name="workingDirPath" value="$PROJECT_DIR$/apps/backend-api-quarkus" />
</MavenRunnerParameters>
</option>
</MavenSettings>
<targetMavenLocalRepo />
<emulateTerminal>true</emulateTerminal>
</backend-api-quarkus>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
================================================
FILE: .run/Keycloak Remote.run.xml
================================================
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Keycloak Remote" type="Remote">
<module name="extensions" />
<option name="USE_SOCKET_TRANSPORT" value="true" />
<option name="SERVER_MODE" value="false" />
<option name="SHMEM_ADDRESS" />
<option name="HOST" value="localhost" />
<option name="PORT" value="8787" />
<option name="AUTO_RESTART" value="false" />
<RunnerSettings RunnerId="Debug">
<option name="DEBUG_PORT" value="8787" />
<option name="LOCAL" value="false" />
</RunnerSettings>
<method v="2" />
</configuration>
</component>
================================================
FILE: .run/OfflineSessionClient (logout).run.xml
================================================
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="OfflineSessionClient (logout)" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
<option name="ACTIVE_PROFILES" />
<module name="offline-session-client" />
<option name="PROGRAM_PARAMETERS" value="--logout" />
<option name="SPRING_BOOT_MAIN_CLASS" value="demo.OfflineSessionClient" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="demo.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
================================================
FILE: .run/OfflineSessionClient.run.xml
================================================
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="OfflineSessionClient" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" nameIsGenerated="true">
<module name="offline-session-client" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="demo.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="SPRING_BOOT_MAIN_CLASS" value="demo.OfflineSessionClient" />
<option name="ALTERNATIVE_JRE_PATH" />
<option name="SHORTEN_COMMAND_LINE" value="NONE" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
================================================
FILE: .run/acme-webapp-saml-node-express.run.xml
================================================
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="acme-webapp-saml-node-express" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/apps/acme-webapp-saml-node-express/package.json" />
<command value="run" />
<scripts>
<script value="start" />
</scripts>
<node-interpreter value="$USER_HOME$/.nvm/versions/node/v21.5.0/bin/node" />
<package-manager value="npm" />
<envs>
<env name="NODE_EXTRA_CA_CERTS" value="$USER_HOME$/.local/share/mkcert/rootCA.pem" />
</envs>
<method v="2" />
</configuration>
</component>
================================================
FILE: .run/backend-api-micronaut.run.xml
================================================
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="backend-api-micronaut" type="MicronautRunConfigurationType" factoryName="Micronaut">
<module name="backend-api-micronaut" />
<option name="alternativeJrePath" />
<option name="alternativeJrePathEnabled" value="false" />
<option name="includeProvidedScope" value="true" />
<option name="mainClass" value="com.acme.backend.micronaut.Application" />
<option name="passParentEnvs" value="true" />
<option name="programParameters" value="" />
<option name="shortenCommandLine" value="NONE" />
<option name="vmParameters" value="" />
<option name="workingDirectory" value="" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
================================================
FILE: .run/backend-api-springboot-reactive.run.xml
================================================
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="backend-api-springboot-reactive" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
<module name="backend-api-springboot-reactive" />
<option name="SPRING_BOOT_MAIN_CLASS" value="com.acme.backend.springreactive.BackendApiSpringbootReactiveApp" />
<option name="WORKING_DIRECTORY" value="file://$MODULE_DIR$" />
<option name="ALTERNATIVE_JRE_PATH" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
================================================
FILE: .run/backend-api-springboot.run.xml
================================================
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="backend-api-springboot" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
<option name="ACTIVE_PROFILES" />
<module name="backend-api-springboot" />
<option name="SPRING_BOOT_MAIN_CLASS" value="com.acme.backend.springboot.users.BackendApiSpringbootApp" />
<option name="WORKING_DIRECTORY" value="file://$MODULE_DIR$" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
================================================
FILE: .run/backend-api-springboot3.run.xml
================================================
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="backend-api-springboot3" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
<option name="ACTIVE_PROFILES" />
<module name="backend-api-springboot3" />
<option name="SPRING_BOOT_MAIN_CLASS" value="com.acme.backend.springboot.users.BackendApiSpringboot3App" />
<option name="WORKING_DIRECTORY" value="file://$MODULE_DIR$" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
================================================
FILE: .run/frontend-webapp-springboot-otel.run.xml
================================================
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="frontend-webapp-springboot-otel" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
<envs>
<env name="OTEL_EXPORTER_OTLP_ENDPOINT" value="https://ops.acme.test:4317" />
<env name="OTEL_METRICS_EXPORTER" value="none" />
<env name="OTEL_PROPAGATORS" value="tracecontext,baggage,jaeger" />
<env name="OTEL_SERVICE_NAME" value="acme-frontend-springboot" />
</envs>
<module name="frontend-webapp-springboot" />
<option name="PASS_PARENT_ENVS" value="false" />
<option name="SPRING_BOOT_MAIN_CLASS" value="com.github.thomasdarimont.keycloak.webapp.WebAppSpringBoot" />
<option name="VM_PARAMETERS" value="-javaagent:$ProjectFileDir$/bin/opentelemetry-javaagent.jar -Dotel.config=otel-config.yaml" />
<option name="WORKING_DIRECTORY" value="file://$ProjectFileDir$" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
================================================
FILE: .run/frontend-webapp-springboot.run.xml
================================================
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="frontend-webapp-springboot" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
<option name="ACTIVE_PROFILES" />
<module name="frontend-webapp-springboot" />
<option name="SPRING_BOOT_MAIN_CLASS" value="com.github.thomasdarimont.keycloak.webapp.WebAppSpringBoot" />
<option name="WORKING_DIRECTORY" value="file://$ProjectFileDir$" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
================================================
FILE: .run/frontend-webapp-springboot3.run.xml
================================================
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="frontend-webapp-springboot3" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot">
<module name="frontend-webapp-springboot3" />
<option name="SPRING_BOOT_MAIN_CLASS" value="com.github.thomasdarimont.keycloak.webapp.WebAppSpringBoot3" />
<option name="WORKING_DIRECTORY" value="file://$MODULE_DIR$" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="com.github.thomasdarimont.keycloak.webapp.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
================================================
FILE: .vscode/settings.json
================================================
{
"java.compile.nullAnalysis.mode": "disabled"
}
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: apps/account-svc/.dockerignore
================================================
*
!target/*-runner
!target/*-runner.jar
!target/lib/*
!target/quarkus-app/*
================================================
FILE: apps/account-svc/.gitignore
================================================
#Maven
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
release.properties
.flattened-pom.xml
# Eclipse
.project
.classpath
.settings/
bin/
# IntelliJ
.idea
*.ipr
*.iml
*.iws
# NetBeans
nb-configuration.xml
# Visual Studio Code
.vscode
.factorypath
# OSX
.DS_Store
# Vim
*.swp
*.swo
# patch
*.orig
*.rej
# Local environment
.env
# Plugin directory
/.quarkus/cli/plugins/
================================================
FILE: apps/account-svc/.mvn/wrapper/.gitignore
================================================
maven-wrapper.jar
================================================
FILE: apps/account-svc/.mvn/wrapper/MavenWrapperDownloader.java
================================================
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.IOException;
import java.io.InputStream;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
public final class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "3.2.0";
private static final boolean VERBOSE = Boolean.parseBoolean(System.getenv("MVNW_VERBOSE"));
public static void main(String[] args) {
log("Apache Maven Wrapper Downloader " + WRAPPER_VERSION);
if (args.length != 2) {
System.err.println(" - ERROR wrapperUrl or wrapperJarPath parameter missing");
System.exit(1);
}
try {
log(" - Downloader started");
final URL wrapperUrl = new URL(args[0]);
final String jarPath = args[1].replace("..", ""); // Sanitize path
final Path wrapperJarPath = Paths.get(jarPath).toAbsolutePath().normalize();
downloadFileFromURL(wrapperUrl, wrapperJarPath);
log("Done");
} catch (IOException e) {
System.err.println("- Error downloading: " + e.getMessage());
if (VERBOSE) {
e.printStackTrace();
}
System.exit(1);
}
}
private static void downloadFileFromURL(URL wrapperUrl, Path wrapperJarPath)
throws IOException {
log(" - Downloading to: " + wrapperJarPath);
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
final String username = System.getenv("MVNW_USERNAME");
final char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
try (InputStream inStream = wrapperUrl.openStream()) {
Files.copy(inStream, wrapperJarPath, StandardCopyOption.REPLACE_EXISTING);
}
log(" - Downloader complete");
}
private static void log(String msg) {
if (VERBOSE) {
System.out.println(msg);
}
}
}
================================================
FILE: apps/account-svc/.mvn/wrapper/maven-wrapper.properties
================================================
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.5/apache-maven-3.9.5-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar
================================================
FILE: apps/account-svc/README.md
================================================
# account-svc
Minimal quarkus backend for a custom remote user storage.
================================================
FILE: apps/account-svc/mvnw
================================================
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Apache Maven Wrapper startup batch script, version 3.2.0
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /usr/local/etc/mavenrc ] ; then
. /usr/local/etc/mavenrc
fi
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "$(uname)" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
JAVA_HOME="$(/usr/libexec/java_home)"; export JAVA_HOME
else
JAVA_HOME="/Library/Java/Home"; export JAVA_HOME
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=$(java-config --jre-home)
fi
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=$(cygpath --unix "$JAVA_HOME")
[ -n "$CLASSPATH" ] &&
CLASSPATH=$(cygpath --path --unix "$CLASSPATH")
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$JAVA_HOME" ] && [ -d "$JAVA_HOME" ] &&
JAVA_HOME="$(cd "$JAVA_HOME" || (echo "cannot cd into $JAVA_HOME."; exit 1); pwd)"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="$(which javac)"
if [ -n "$javaExecutable" ] && ! [ "$(expr "\"$javaExecutable\"" : '\([^ ]*\)')" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=$(which readlink)
if [ ! "$(expr "$readLink" : '\([^ ]*\)')" = "no" ]; then
if $darwin ; then
javaHome="$(dirname "\"$javaExecutable\"")"
javaExecutable="$(cd "\"$javaHome\"" && pwd -P)/javac"
else
javaExecutable="$(readlink -f "\"$javaExecutable\"")"
fi
javaHome="$(dirname "\"$javaExecutable\"")"
javaHome=$(expr "$javaHome" : '\(.*\)/bin')
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="$(\unset -f command 2>/dev/null; \command -v java)"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=$(cd "$wdir/.." || exit 1; pwd)
fi
# end of workaround
done
printf '%s' "$(cd "$basedir" || exit 1; pwd)"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
# Remove \r in case we run on Windows within Git Bash
# and check out the repository with auto CRLF management
# enabled. Otherwise, we may read lines that are delimited with
# \r\n and produce $'-Xarg\r' rather than -Xarg due to word
# splitting rules.
tr -s '\r\n' ' ' < "$1"
fi
}
log() {
if [ "$MVNW_VERBOSE" = true ]; then
printf '%s\n' "$1"
fi
}
BASE_DIR=$(find_maven_basedir "$(dirname "$0")")
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR
log "$MAVEN_PROJECTBASEDIR"
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
wrapperJarPath="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar"
if [ -r "$wrapperJarPath" ]; then
log "Found $wrapperJarPath"
else
log "Couldn't find $wrapperJarPath, downloading it ..."
if [ -n "$MVNW_REPOURL" ]; then
wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
else
wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
fi
while IFS="=" read -r key value; do
# Remove '\r' from value to allow usage on windows as IFS does not consider '\r' as a separator ( considers space, tab, new line ('\n'), and custom '=' )
safeValue=$(echo "$value" | tr -d '\r')
case "$key" in (wrapperUrl) wrapperUrl="$safeValue"; break ;;
esac
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
log "Downloading from: $wrapperUrl"
if $cygwin; then
wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath")
fi
if command -v wget > /dev/null; then
log "Found wget ... using wget"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--quiet"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
else
wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
log "Found curl ... using curl"
[ "$MVNW_VERBOSE" = true ] && QUIET="" || QUIET="--silent"
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
else
curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L || rm -f "$wrapperJarPath"
fi
else
log "Falling back to using Java to download"
javaSource="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.java"
javaClass="$MAVEN_PROJECTBASEDIR/.mvn/wrapper/MavenWrapperDownloader.class"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaSource=$(cygpath --path --windows "$javaSource")
javaClass=$(cygpath --path --windows "$javaClass")
fi
if [ -e "$javaSource" ]; then
if [ ! -e "$javaClass" ]; then
log " - Compiling MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/javac" "$javaSource")
fi
if [ -e "$javaClass" ]; then
log " - Running MavenWrapperDownloader.java ..."
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$wrapperUrl" "$wrapperJarPath") || rm -f "$wrapperJarPath"
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
# If specified, validate the SHA-256 sum of the Maven wrapper jar file
wrapperSha256Sum=""
while IFS="=" read -r key value; do
case "$key" in (wrapperSha256Sum) wrapperSha256Sum=$value; break ;;
esac
done < "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.properties"
if [ -n "$wrapperSha256Sum" ]; then
wrapperSha256Result=false
if command -v sha256sum > /dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | sha256sum -c > /dev/null 2>&1; then
wrapperSha256Result=true
fi
elif command -v shasum > /dev/null; then
if echo "$wrapperSha256Sum $wrapperJarPath" | shasum -a 256 -c > /dev/null 2>&1; then
wrapperSha256Result=true
fi
else
echo "Checksum validation was requested but neither 'sha256sum' or 'shasum' are available."
echo "Please install either command, or disable validation by removing 'wrapperSha256Sum' from your maven-wrapper.properties."
exit 1
fi
if [ $wrapperSha256Result = false ]; then
echo "Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised." >&2
echo "Investigate or delete $wrapperJarPath to attempt a clean download." >&2
echo "If you updated your Maven version, you need to update the specified wrapperSha256Sum property." >&2
exit 1
fi
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME")
[ -n "$CLASSPATH" ] &&
CLASSPATH=$(cygpath --path --windows "$CLASSPATH")
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR")
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $*"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
# shellcheck disable=SC2086 # safe args
exec "$JAVACMD" \
$MAVEN_OPTS \
$MAVEN_DEBUG_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
================================================
FILE: apps/account-svc/mvnw.cmd
================================================
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM http://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Apache Maven Wrapper startup batch script, version 3.2.0
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %*
if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %*
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.2.0/maven-wrapper-3.2.0.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %WRAPPER_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM If specified, validate the SHA-256 sum of the Maven wrapper jar file
SET WRAPPER_SHA_256_SUM=""
FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperSha256Sum" SET WRAPPER_SHA_256_SUM=%%B
)
IF NOT %WRAPPER_SHA_256_SUM%=="" (
powershell -Command "&{"^
"$hash = (Get-FileHash \"%WRAPPER_JAR%\" -Algorithm SHA256).Hash.ToLower();"^
"If('%WRAPPER_SHA_256_SUM%' -ne $hash){"^
" Write-Output 'Error: Failed to validate Maven wrapper SHA-256, your Maven wrapper might be compromised.';"^
" Write-Output 'Investigate or delete %WRAPPER_JAR% to attempt a clean download.';"^
" Write-Output 'If you updated your Maven version, you need to update the specified wrapperSha256Sum property.';"^
" exit 1;"^
"}"^
"}"
if ERRORLEVEL 1 goto error
)
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% ^
%JVM_CONFIG_MAVEN_PROPS% ^
%MAVEN_OPTS% ^
%MAVEN_DEBUG_OPTS% ^
-classpath %WRAPPER_JAR% ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat"
if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%"=="on" pause
if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE%
cmd /C exit /B %ERROR_CODE%
================================================
FILE: apps/account-svc/pom.xml
================================================
<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>com.thomasdarimont.training.keycloak</groupId>
<artifactId>account-svc</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<compiler-plugin.version>3.11.0</compiler-plugin.version>
<maven.compiler.release>21</maven.compiler.release>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<quarkus.platform.artifact-id>quarkus-bom</quarkus.platform.artifact-id>
<quarkus.platform.group-id>io.quarkus.platform</quarkus.platform.group-id>
<quarkus.platform.version>3.5.3</quarkus.platform.version>
<skipITs>true</skipITs>
<surefire-plugin.version>3.1.2</surefire-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>${quarkus.platform.artifact-id}</artifactId>
<version>${quarkus.platform.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-resteasy-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-arc</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-container-image-jib</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.34</version>
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>${quarkus.platform.group-id}</groupId>
<artifactId>quarkus-maven-plugin</artifactId>
<version>${quarkus.platform.version}</version>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>build</goal>
<goal>generate-code</goal>
<goal>generate-code-tests</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>${compiler-plugin.version}</version>
<configuration>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<configuration>
<systemPropertyVariables>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>${surefire-plugin.version}</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<systemPropertyVariables>
<native.image.path>${project.build.directory}/${project.build.finalName}-runner</native.image.path>
<java.util.logging.manager>org.jboss.logmanager.LogManager</java.util.logging.manager>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>native</id>
<activation>
<property>
<name>native</name>
</property>
</activation>
<properties>
<skipITs>false</skipITs>
<quarkus.package.type>native</quarkus.package.type>
</properties>
</profile>
</profiles>
</project>
================================================
FILE: apps/account-svc/src/main/docker/Dockerfile.jvm
================================================
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
#
# Before building the container image run:
#
# ./mvnw package
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.jvm -t quarkus/account-svc-jvm .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/account-svc-jvm
#
# If you want to include the debug port into your docker image
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
# when running the container
#
# Then run the container using :
#
# docker run -i --rm -p 8080:8080 quarkus/account-svc-jvm
#
# This image uses the `run-java.sh` script to run the application.
# This scripts computes the command line to execute your Java application, and
# includes memory/GC tuning.
# You can configure the behavior using the following environment properties:
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
# in JAVA_OPTS (example: "-Dsome.property=foo")
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
# used to calculate a default maximal heap memory based on a containers restriction.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
# of the container available memory as set here. The default is `50` which means 50%
# of the available memory is used as an upper boundary. You can skip this mechanism by
# setting this value to `0` in which case no `-Xmx` option is added.
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
# is used to calculate a default initial heap memory based on the maximum heap memory.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
# is used as the initial heap size. You can skip this mechanism by setting this value
# to `0` in which case no `-Xms` option is added (example: "25")
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
# This is used to calculate the maximum value of the initial heap memory. If used in
# a container without any memory constraints for the container then this option has
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
# here. The default is 4096MB which means the calculated value of `-Xms` never will
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
# when things are happening. This option, if set to true, will set
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
# true").
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
# (example: "20")
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
# (example: "40")
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
# (example: "4")
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
# previous GC times. (example: "90")
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
# contain the necessary JRE command-line options to specify the required GC, which
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
# accessed directly. (example: "foo.example.com,bar.example.com")
#
###
FROM registry.access.redhat.com/ubi8/openjdk-17:1.17
ENV LANGUAGE='en_US:en'
# We make four distinct layers so if there are application changes the library layers can be re-used
COPY --chown=185 target/quarkus-app/lib/ /deployments/lib/
COPY --chown=185 target/quarkus-app/*.jar /deployments/
COPY --chown=185 target/quarkus-app/app/ /deployments/app/
COPY --chown=185 target/quarkus-app/quarkus/ /deployments/quarkus/
EXPOSE 8080
USER 185
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
================================================
FILE: apps/account-svc/src/main/docker/Dockerfile.legacy-jar
================================================
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode
#
# Before building the container image run:
#
# ./mvnw package -Dquarkus.package.type=legacy-jar
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.legacy-jar -t quarkus/account-svc-legacy-jar .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/account-svc-legacy-jar
#
# If you want to include the debug port into your docker image
# you will have to expose the debug port (default 5005 being the default) like this : EXPOSE 8080 5005.
# Additionally you will have to set -e JAVA_DEBUG=true and -e JAVA_DEBUG_PORT=*:5005
# when running the container
#
# Then run the container using :
#
# docker run -i --rm -p 8080:8080 quarkus/account-svc-legacy-jar
#
# This image uses the `run-java.sh` script to run the application.
# This scripts computes the command line to execute your Java application, and
# includes memory/GC tuning.
# You can configure the behavior using the following environment properties:
# - JAVA_OPTS: JVM options passed to the `java` command (example: "-verbose:class")
# - JAVA_OPTS_APPEND: User specified Java options to be appended to generated options
# in JAVA_OPTS (example: "-Dsome.property=foo")
# - JAVA_MAX_MEM_RATIO: Is used when no `-Xmx` option is given in JAVA_OPTS. This is
# used to calculate a default maximal heap memory based on a containers restriction.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xmx` is set to a ratio
# of the container available memory as set here. The default is `50` which means 50%
# of the available memory is used as an upper boundary. You can skip this mechanism by
# setting this value to `0` in which case no `-Xmx` option is added.
# - JAVA_INITIAL_MEM_RATIO: Is used when no `-Xms` option is given in JAVA_OPTS. This
# is used to calculate a default initial heap memory based on the maximum heap memory.
# If used in a container without any memory constraints for the container then this
# option has no effect. If there is a memory constraint then `-Xms` is set to a ratio
# of the `-Xmx` memory as set here. The default is `25` which means 25% of the `-Xmx`
# is used as the initial heap size. You can skip this mechanism by setting this value
# to `0` in which case no `-Xms` option is added (example: "25")
# - JAVA_MAX_INITIAL_MEM: Is used when no `-Xms` option is given in JAVA_OPTS.
# This is used to calculate the maximum value of the initial heap memory. If used in
# a container without any memory constraints for the container then this option has
# no effect. If there is a memory constraint then `-Xms` is limited to the value set
# here. The default is 4096MB which means the calculated value of `-Xms` never will
# be greater than 4096MB. The value of this variable is expressed in MB (example: "4096")
# - JAVA_DIAGNOSTICS: Set this to get some diagnostics information to standard output
# when things are happening. This option, if set to true, will set
# `-XX:+UnlockDiagnosticVMOptions`. Disabled by default (example: "true").
# - JAVA_DEBUG: If set remote debugging will be switched on. Disabled by default (example:
# true").
# - JAVA_DEBUG_PORT: Port used for remote debugging. Defaults to 5005 (example: "8787").
# - CONTAINER_CORE_LIMIT: A calculated core limit as described in
# https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt. (example: "2")
# - CONTAINER_MAX_MEMORY: Memory limit given to the container (example: "1024").
# - GC_MIN_HEAP_FREE_RATIO: Minimum percentage of heap free after GC to avoid expansion.
# (example: "20")
# - GC_MAX_HEAP_FREE_RATIO: Maximum percentage of heap free after GC to avoid shrinking.
# (example: "40")
# - GC_TIME_RATIO: Specifies the ratio of the time spent outside the garbage collection.
# (example: "4")
# - GC_ADAPTIVE_SIZE_POLICY_WEIGHT: The weighting given to the current GC time versus
# previous GC times. (example: "90")
# - GC_METASPACE_SIZE: The initial metaspace size. (example: "20")
# - GC_MAX_METASPACE_SIZE: The maximum metaspace size. (example: "100")
# - GC_CONTAINER_OPTIONS: Specify Java GC to use. The value of this variable should
# contain the necessary JRE command-line options to specify the required GC, which
# will override the default of `-XX:+UseParallelGC` (example: -XX:+UseG1GC).
# - HTTPS_PROXY: The location of the https proxy. (example: "myuser@127.0.0.1:8080")
# - HTTP_PROXY: The location of the http proxy. (example: "myuser@127.0.0.1:8080")
# - NO_PROXY: A comma separated lists of hosts, IP addresses or domains that can be
# accessed directly. (example: "foo.example.com,bar.example.com")
#
###
FROM registry.access.redhat.com/ubi8/openjdk-17:1.17
ENV LANGUAGE='en_US:en'
COPY target/lib/* /deployments/lib/
COPY target/*-runner.jar /deployments/quarkus-run.jar
EXPOSE 8080
USER 185
ENV JAVA_OPTS_APPEND="-Dquarkus.http.host=0.0.0.0 -Djava.util.logging.manager=org.jboss.logmanager.LogManager"
ENV JAVA_APP_JAR="/deployments/quarkus-run.jar"
ENTRYPOINT [ "/opt/jboss/container/java/run/run-java.sh" ]
================================================
FILE: apps/account-svc/src/main/docker/Dockerfile.native
================================================
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
#
# Before building the container image run:
#
# ./mvnw package -Dnative
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.native -t quarkus/account-svc .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/account-svc
#
###
FROM registry.access.redhat.com/ubi8/ubi-minimal:8.8
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
&& chown 1001:root /work
COPY --chown=1001:root target/*-runner /work/application
EXPOSE 8080
USER 1001
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
================================================
FILE: apps/account-svc/src/main/docker/Dockerfile.native-micro
================================================
####
# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.
# It uses a micro base image, tuned for Quarkus native executables.
# It reduces the size of the resulting container image.
# Check https://quarkus.io/guides/quarkus-runtime-base-image for further information about this image.
#
# Before building the container image run:
#
# ./mvnw package -Dnative
#
# Then, build the image with:
#
# docker build -f src/main/docker/Dockerfile.native-micro -t quarkus/account-svc .
#
# Then run the container using:
#
# docker run -i --rm -p 8080:8080 quarkus/account-svc
#
###
FROM quay.io/quarkus/quarkus-micro-image:2.0
WORKDIR /work/
RUN chown 1001 /work \
&& chmod "g+rwX" /work \
&& chown 1001:root /work
COPY --chown=1001:root target/*-runner /work/application
EXPOSE 8080
USER 1001
ENTRYPOINT ["./application", "-Dquarkus.http.host=0.0.0.0"]
================================================
FILE: apps/account-svc/src/main/java/com/thomasdarimont/keycloak/training/accounts/User.java
================================================
package com.thomasdarimont.keycloak.training.accounts;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@NoArgsConstructor
public class User implements Cloneable {
private String id;
private String username;
private String email;
private boolean emailVerified;
private String firstname;
private String lastname;
private String password;
private boolean enabled;
private long created;
private List<String> roles;
public User(String id, String username, String password, String email, boolean emailVerified, String firstname, String lastname, boolean enabled, List<String> roles) {
this.id = id;
this.username = username;
this.email = email;
this.emailVerified = emailVerified;
this.firstname = firstname;
this.lastname = lastname;
this.password = password;
this.enabled = enabled;
this.created = System.currentTimeMillis();
this.roles = roles;
}
@JsonIgnore
public String getPassword() {
return password;
}
}
================================================
FILE: apps/account-svc/src/main/java/com/thomasdarimont/keycloak/training/accounts/UserRepository.java
================================================
package com.thomasdarimont.keycloak.training.accounts;
import com.thomasdarimont.keycloak.training.accounts.UserResource.UserSearchInput;
import jakarta.inject.Singleton;
import lombok.extern.jbosslog.JBossLog;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Stream;
@Singleton
@JBossLog
class UserRepository {
private static final List<User> USERS = new ArrayList<>();
public UserRepository() {
USERS.add(newUser("1", "bugs", "password", "bugs.bunny@acme.com", true, "Bugs", "Bunny", true, List.of("staff")));
USERS.add(newUser("2", "daffy", "password", "duffy.duck@acme.com", true, "Duffy", "Duck", true, List.of("staff")));
USERS.add(newUser("3", "porky", "password", "porky.pig@acme.com", false, "Porky", "Pig", false, List.of("staff")));
USERS.add(newUser("4", "taz", "password", "taz.devil@acme.com", false, "Taz", "Devil", true, List.of("staff")));
USERS.add(newUser("5", "sylvester", "password", "sylvester.cat@acme.com",false, "Sylvester", "Cat", false, List.of("staff")));
USERS.add(newUser("6", "marvin", "password", "marvin.martian@acme.com", false, "Marvin", "Martian", false, List.of("staff")));
USERS.add(newUser("7", "wile", "password", "wile.e.coyote@acme.com", false, "Wile", "Coyote", false, null));
}
private static User newUser(String idSeed, String username, String password, String email, boolean emailVerified, String firstname, String lastname, boolean enabled, List<String> roles) {
return new User(UUID.nameUUIDFromBytes(idSeed.getBytes()).toString(), username, password, email, emailVerified, firstname, lastname, enabled, roles);
}
public List<User> findAll() {
log.info("findAll");
return USERS;
}
public int count() {
log.info("count");
return USERS.size();
}
public User findById(String id) {
log.infof("findById id=%s", id);
return USERS.stream().filter(user -> user.getId().equalsIgnoreCase(id)).findFirst().orElse(null);
}
public User findByUsernameOrEmail(String username) {
log.infof("findByUsernameOrEmail username=%s", username);
return getByUsername(username).or(() -> getByEmail(username)).orElse(null);
}
public Optional<User> getByUsername(String username) {
log.infof("getByUsername username=%s", username);
return USERS.stream().filter(user -> user.getUsername().equalsIgnoreCase(username)).findFirst();
}
public Optional<User> getByEmail(String email) {
log.infof("getByEmail email=%s", email);
return USERS.stream().filter(user -> user.getEmail().equalsIgnoreCase(email)).findFirst();
}
List<User> findUsers(String query) {
log.infof("findUsers query=%s", query);
return USERS.stream().filter(user -> query.equalsIgnoreCase("*") || user.getUsername().contains(query) || user.getEmail().contains(query)).toList();
}
public boolean validatePassword(String id, String password) {
log.infof("validatePassword id=%s password=%s", id, password);
return findById(id).getPassword().equals(password);
}
public boolean updatePassword(String id, String password) {
log.infof("updatePassword id=%s password=%s", id, password);
findById(id).setPassword(password);
return true;
}
public void createUser(User user) {
log.infof("createUser user=%s", user.toString());
user.setId(UUID.randomUUID().toString());
user.setCreated(System.currentTimeMillis());
USERS.add(user);
}
public void updateUser(User user) {
log.infof("updateUser user=%s", user.toString());
User existing = findByUsernameOrEmail(user.getUsername());
existing.setEmail(user.getEmail());
existing.setFirstname(user.getFirstname());
existing.setLastname(user.getLastname());
existing.setEnabled(user.isEnabled());
}
public boolean removeUser(String id) {
log.infof("removeUser id=%s", id);
return USERS.removeIf(p -> p.getId().equals(id));
}
public List<User> search(String search, Integer firstResult, Integer maxResults, EnumSet<UserSearchInput.UserSearchOption> options) {
log.infof("search search=%s firstResult=%s maxResults=%s options=%s", search, firstResult, maxResults, options);
return searchInternal(search, firstResult, maxResults, options).toList();
}
public int searchForCount(String search, Integer firstResult, Integer maxResults, EnumSet<UserSearchInput.UserSearchOption> options) {
log.infof("searchForCount search=%s firstResult=%s maxResults=%s options=%s", search, firstResult, maxResults, options);
return (int) searchInternal(search, firstResult, maxResults, options).count();
}
private static Stream<User> searchInternal(String search, Integer firstResult, Integer maxResults, EnumSet<UserSearchInput.UserSearchOption> options) {
if (search == null) {
return Stream.empty();
}
var exact = search.startsWith("'") && search.endsWith("'");
var exactSearch = exact ? search.substring(1, search.length() - 1) : search;
final String searchMode;
if (exact) {
searchMode = "exact";
} else if (search.trim().equals("*")) {
searchMode = "wildcard";
} else {
searchMode = "contains";
}
log.infof("searchInternal search=%s firstResult=%s maxResults=%s options=%s searchMode=%s", search, firstResult, maxResults, options, searchMode);
Stream<User> stream = USERS.stream() //
.filter(u -> switch (searchMode) {
case "exact" -> u.getUsername().equals(exactSearch) || u.getEmail().equals(exactSearch);
case "contains" -> u.getUsername().contains(search) || u.getEmail().contains(search);
default /* wildcard / null */ -> true;
}) //
.filter(user -> !user.getUsername().startsWith("service-account-") || options.contains(UserSearchInput.UserSearchOption.INCLUDE_SERVICE_ACCOUNTS)) //
;
if (firstResult != null) {
stream = stream.skip(firstResult);
}
if (maxResults != null) {
stream = stream.limit(maxResults);
}
return stream;
}
}
================================================
FILE: apps/account-svc/src/main/java/com/thomasdarimont/keycloak/training/accounts/UserResource.java
================================================
package com.thomasdarimont.keycloak.training.accounts;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.jbosslog.JBossLog;
import java.util.EnumSet;
import java.util.List;
@JBossLog
@Path("/api/users")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@RequiredArgsConstructor
public class UserResource {
private final UserRepository users;
@GET
public List<User> userList() {
return users.findAll();
}
@GET
@Path("{userId}")
public User userById(@PathParam("userId") String userId) {
return users.findById(userId);
}
@POST
@Path("/lookup/username")
public User lookupUserByUsername(UserLookupInput search) {
return users.getByUsername(search.getUsername()).orElse(null);
}
@POST
@Path("/lookup/email")
public User lookupUserByEmail(UserLookupInput search) {
return users.getByEmail(search.getEmail()).orElse(null);
}
@POST
@Path("/{userId}/credentials/verify")
public VerifyCredentialsOutput verifyCredentials(@PathParam("userId") String userId, VerifyCredentialsInput input) {
VerifyCredentialsOutput output = verify(userId, input);
log.infof("verifyCredentials output=%s", output);
return output;
}
@POST
@Path("/search")
public UserSearchOutput searchUsers(UserSearchInput search) {
if (search.getOptions().contains(UserSearchInput.UserSearchOption.COUNT_ONLY)) {
int count = users.searchForCount(search.getSearch(), search.getFirstResult(), search.getMaxResults(), search.getOptions());
return new UserSearchOutput(null, count);
}
var output = users.search(search.getSearch(), search.getFirstResult(), search.getMaxResults(), search.getOptions());
log.infof("searchUsers output=%s", output);
return new UserSearchOutput(output, output.size());
}
private VerifyCredentialsOutput verify(String userId, VerifyCredentialsInput input) {
return new VerifyCredentialsOutput(users.validatePassword(userId, input.getPassword()));
}
@Data
public static class UserLookupInput {
String username;
String email;
}
@Data
public static class UserSearchInput {
private String search;
private Integer firstResult;
private Integer maxResults;
private EnumSet<UserSearchOption> options;
public enum UserSearchOption {
COUNT_ONLY, //
INCLUDE_SERVICE_ACCOUNTS, //
}
}
@Data
public static class UserSearchOutput {
private final List<User> users;
private final int count;
}
@Data
public static class VerifyCredentialsInput {
String password;
}
@Data
public static class VerifyCredentialsOutput {
private final boolean valid;
}
}
================================================
FILE: apps/account-svc/src/main/resources/application.properties
================================================
quarkus.container-image.build=true
quarkus.container-image.group=training
quarkus.container-image.name=account-svc
quarkus.container-image.tag=latest
quarkus.jib.ports=7070
quarkus.http.port=7070
quarkus.http.host=0.0.0.0
================================================
FILE: apps/acme-account-console/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Acme Account Console</title>
<style>
body {
background-color: #eaeaea;
font-family: sans-serif;
font-size: 10px;
}
button {
font-family: sans-serif;
font-size: 25px;
width: 200px;
background-color: #0085cf;
background-image: linear-gradient(to bottom, #00a8e1 0%, #0085cf 100%);
background-repeat: repeat-x;
border: 2px solid #ccc;
color: #fff;
text-transform: uppercase;
-webkit-box-shadow: 2px 2px 10px 0px rgba(0, 0, 0, 0.5);
-moz-box-shadow: 2px 2px 10px 0px rgba(0, 0, 0, 0.5);
box-shadow: 2px 2px 10px 0px rgba(0, 0, 0, 0.5);
}
button:hover {
background-color: #006ba6;
background-image: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
hr {
border: none;
background-color: #eee;
height: 10px;
}
.menu {
padding: 10px;
margin-bottom: 10px;
}
.content {
font-size: 20px;
background-color: #eee;
border: 1px solid #ccc;
padding: 10px;
-webkit-box-shadow: 2px 2px 10px 0 rgba(0, 0, 0, 0.5);
-moz-box-shadow: 2px 2px 10px 0 rgba(0, 0, 0, 0.5);
box-shadow: 2px 2px 10px 0 rgba(0, 0, 0, 0.5);
}
.message-content {
font-size: 20px;
padding: 10px;
background-color: #fff;
border: 1px solid #ccc;
}
.token-content {
font-size: 20px;
padding: 5px;
white-space: pre;
text-transform: none;
}
.wrapper {
position: absolute;
left: 10px;
top: 40px;
bottom: 10px;
right: 10px;
}
.error {
color: #a21e22;
}
table {
width: 100%;
}
table.credentials, table.profile, table.apps {
width: unset;
}
tr.even {
background-color: #eee;
}
td {
padding: 5px;
}
td.label {
font-weight: bold;
width: 250px;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<div>
<h1>ClientId: <span id="clientInfo"></span></h1>
</div>
<div id="welcome" class="wrapper hidden">
<div class="menu">
<button name="loginBtn" onclick="showLogin()">Login</button>
</div>
<div class="message-content">
<div class="message">Please login</div>
<button name="registerBtn" onclick="showRegister()">Register</button>
</div>
</div>
<div id="content" class="wrapper hidden">
<div class="menu">
<button name="profileBtn" onclick="showProfile()" class="profile">Profile</button>
<button name="tokenBtn" onclick="showToken()" class="token">AccessToken</button>
<button name="idTokenBtn" onclick="showIdToken()" class="idToken">IDToken</button>
<button name="userinfoBtn" onclick="showUserInfo()" class="userinfo">Userinfo</button>
<button name="meBtn" onclick="showMeInfo()" class="meinfo">Me Info</button>
<button name="settingsBtn" onclick="showSettings()" class="settings">Settings</button>
<button name="securityBtn" onclick="showSecurity()" class="security">Security</button>
<button name="appsBtn" onclick="showApps()" class="apps">Apps</button>
<button name="reauthBtn" onclick="enforceCurrentAuth()" class="reauth">ReAuth</button>
<button name="refreshBtn" onclick="refreshToken()" class="refresh">Refresh</button>
<button name="stepupBtn" onclick="showStepUp()" class="stepup">Stepup</button>
<button name="switchContextBtn" onclick="switchContext()" class="switchContext">Switch Context</button>
<button name="accountBtn" onclick="keycloak.accountManagement()" class="account">Account</button>
<button name="logoutBtn" onclick="keycloak.logout()" class="logout">Logout</button>
<button name="revokeBtn" onclick="revokeToken()" class="revoke">Revoke</button>
</div>
<div id="data" class="content"></div>
</div>
<script defer type="module">
function $(selector) {
return document.querySelector(selector);
}
let searchParams = new URLSearchParams(window.location.search);
let keycloakBaseUrl = searchParams.get("base_url") || (window.location.protocol === "http:" ? "http://id.acme.test:8080" : "https://id.acme.test:8443");
let keycloakUrl = keycloakBaseUrl + (searchParams.get("path") || "/auth");
let keycloakJsSrc = searchParams.get("kc_js_src");
let realm = searchParams.get("realm") || 'acme-internal';
let clientId = searchParams.get("client_id") || 'app-minispa';
let customResourcesUrl = `${keycloakUrl}/realms/${realm}/custom-resources`;
// ?scope=openid+email+custom.profile+custom.ageinfo
//let scope = searchParams.get("scope") || 'openid email acme.profile acme.ageinfo';
let scope = searchParams.get("scope") || 'openid email';
// &show=profile,settings,apps,security,logout
// &show=profile,settings,apps,security,logout,token,idToken,userinfo
// &show=profile,logout,token,idToken,userinfo,reauth,account
let meInfo = {
backends: {
quarkus: {
label: "Quarkus",
url: "https://apps.acme.test:4543",
},
springboot: {
label: "Spring Boot",
url: "https://apps.acme.test:4643",
},
springbootReactive: {
label: "Spring Boot Reactive",
url: "https://apps.acme.test:4943",
},
springboot3: {
label: "Spring Boot 3",
url: "https://apps.acme.test:4623",
},
micronaut: {
label: "Micronaut",
url: "https://apps.acme.test:4953",
},
nodejsexpress: {
label: "NodeJS Express",
url: "https://apps.acme.test:4743",
},
gomux: {
label: "Go",
url: "https://apps.acme.test:4843",
},
rustrocket: {
label: "Rust+Rocket",
url: "https://apps.acme.test:4853",
},
rustactix: {
label: "Rust+Actix",
url: "https://apps.acme.test:4863",
},
aspwebdnc: {
label: "ASP.NetCore",
url: "https://apps.acme.test:7229",
}
},
currentBackend: "springboot",
updateCurrentBackend(backend) {
if (!backend in meInfo.backends) {
throw "Unsupported backend " + backend;
}
meInfo.currentBackend = backend;
},
getCurrentBackendUrl() {
return meInfo.backends[meInfo.currentBackend].url;
}
};
const allContextClasses = ["profile", "account", "settings", "meinfo", "token", "idToken", "userinfo", "security", "apps", "reauth", "logout", "deleteAccount", "switchContext", "revoke", "stepup", "refresh"];
const contextClassesToHideDefault = ["meinfo", "token", "idToken", "userinfo", "reauth", "account", "deleteAccount", "switchContext", "revoke", "stepup", "refresh"];
const contextClassesToShowDefault = [...allContextClasses].filter((value, index, arr) => {
return !contextClassesToHideDefault.includes(value);
});
let contextClassesToShow = searchParams.get("show")?.split(",") || contextClassesToShowDefault;
for (let className of allContextClasses) {
if (!contextClassesToShow.includes(className)) {
let btn = $(`button.${className}`);
if (btn) {
btn.parentElement.removeChild(btn);
}
}
}
$("#clientInfo").textContent = clientId;
window.showLogin = async function(config) {
await keycloak.login(config);
}
window.showRegister = async function() {
let registerUrl = await keycloak.createRegisterUrl();
window.location = registerUrl;
}
window.showWelcome = function () {
document.getElementById("welcome").classList.remove("hidden");
document.getElementById("content").classList.add("hidden");
}
window.getTimeSinceLastAuth = function () {
let timeSinceAuthInSeconds = Math.floor((Date.now() - (keycloak.tokenParsed.auth_time * 1000)) / 1000);
return timeSinceAuthInSeconds;
}
window.enforceCurrentAuth = function () {
let timeSinceAuthSeconds = getTimeSinceLastAuth();
console.log("time since auth: " + timeSinceAuthSeconds);
if (timeSinceAuthSeconds < 10) {
console.log("auth is still file")
return;
} else {
console.log("trigger reauth")
}
keycloak.login({
loginHint: keycloak.tokenParsed.preferred_username,
maxAge: 12
});
}
window.refreshToken = async function() {
await keycloak.updateToken(-1);
}
window.revokeToken = async function () {
const bodyData = new URLSearchParams();
bodyData.append("token", keycloak.refreshToken);
bodyData.append("client_id", clientId);
let response = await sendRequest(`${keycloakUrl}/realms/${realm}/protocol/openid-connect/revoke`, {
method: "POST",
credentials: "include", // send auth cookies
headers: {
"Accept": "application/json",
"Content-Type": "application/x-www-form-urlencoded"
},
body: bodyData
});
console.log(response);
// window.location.reload();
}
window.switchContext = function () {
keycloak.login({
action: "acme-context-selection-action"
});
}
window.showSecurity = async function () {
await keycloak.updateToken(5);
let credentialsData;
try {
let response = await sendRequest(`${keycloakUrl}/realms/${realm}/custom-resources/me/credentials`, {
credentials: "include", // send KEYCLOAK_DEVICE cookie
})
if (response.ok) {
credentialsData = await response.json();
} else {
credentialsData = {error: "status " + response.status};
}
} catch (error) {
console.log(error);
credentialsData = {error: error.message};
}
let passwordInfo = credentialsData.credentialInfos['password'];
let otpInfo = credentialsData.credentialInfos['otp'];
let smsInfo = credentialsData.credentialInfos['mfa-sms'];
let emailCodeInfo = credentialsData.credentialInfos['mfa-email-code'];
let trustedDeviceInfo = credentialsData.credentialInfos['acme-trusted-device'];
let recoveryCodeInfo = credentialsData.credentialInfos['recovery-authn-codes'];
let passkeyInfo = credentialsData.credentialInfos['webauthn-passwordless'];
let otpAuthHtml = "";
if (otpInfo) {
for (let optInfoItem of otpInfo) {
otpAuthHtml += `
<tr>
<td>${!!optInfoItem ? "✓" : ""}</td>
<td>MFA OTP</td>
<td>${!!optInfoItem ? escapeHtml(optInfoItem.credentialLabel) : ''}</td>
<td>${!!optInfoItem ? formatDate(optInfoItem.createdAt) : '-'}</td>
<td>${!!optInfoItem ? '<a href="#" onclick="removeCredential(\'otp\',\'' + optInfoItem.credentialId + '\');return false">Remove</a>' : ''}</td>
<td><a href="#" onclick="changeCredential('otp');return false">Add another</a></td>
</tr>`;
}
} else {
otpAuthHtml += `
<tr>
<td></td>
<td>MFA OTP</td>
<td></td>
<td>-</td>
<td><a href="#" onclick="changeCredential('otp');return false">Add</a></td>
<td></td>
</tr>`;
}
let emailCodeAuthHtml = "";
if (emailCodeInfo) {
emailCodeAuthHtml += `
<tr>
<td>${!!emailCodeInfo[0] ? "✓" : ""}</td>
<td>MFA E-Mail Code</td>
<td></td>
<td>${!!emailCodeInfo[0] ? formatDate(emailCodeInfo[0].createdAt) : '-'}</td>
<td>${!!emailCodeInfo[0] ? '<a href="#" onclick="removeCredential(\'mfa-email-code\',\'' + emailCodeInfo[0].credentialId + '\');return false">Remove</a>' : ''}</td>
<td></td>
</tr>`;
} else {
emailCodeAuthHtml += `
<tr>
<td></td>
<td>MFA E-mail Code</td>
<td></td>
<td>-</td>
<td><a href="#" onclick="changeCredential('mfa-email-code');return false">Add</a></td>
<td></td>
</tr>`;
}
let trustedDeviceAuthHtml = "";
if (trustedDeviceInfo) {
for (let trustedDeviceInfoItem of trustedDeviceInfo) {
if (!trustedDeviceInfoItem) {
continue;
}
let trustedDeviceLabel = escapeHtml(trustedDeviceInfoItem.credentialLabel);
let currentBrowserIsTrustedDevice = trustedDeviceInfoItem.metadata.current;
let currentDeviceMarker = currentBrowserIsTrustedDevice ? '(*)' : '';
trustedDeviceAuthHtml += `
<tr>
<td>✓</td>
<td>Trusted Device</td>
<td>${trustedDeviceLabel + ' ' + currentDeviceMarker}</td>
<td>${formatDate(trustedDeviceInfoItem.createdAt)}</td>
<td><a href="#" onclick="changeCredential('acme-trusted-device');return false">Add</a></td>
<td><a href="#" onclick="removeCredential('acme-trusted-device','${trustedDeviceInfoItem.credentialId}');return false">Remove</a></td>
</tr>`;
}
} else {
trustedDeviceAuthHtml += `
<tr>
<td></td>
<td>Trusted Device</td>
<td></td>
<td>-</td>
<td><a href="#" onclick="changeCredential('acme-trusted-device');return false">Add</a></td>
<td></td>
</tr>`;
}
let securityHtml = `
<table class="credentials">
<thead>
<th>Set-up</th>
<th>Credential</th>
<th>Label</th>
<th>Created At</th>
<th colspan="2">Actions</th>
</thead>
<tbody>
<tr>
<td>✓</td>
<td>Password</td>
<td></td>
<td>${formatDate(passwordInfo[0].createdAt)}</td>
<td><a href="#" onclick="changePassword();return false">Update</a></td>
<td></td>
</tr>
<tr>
<td>${!!passkeyInfo ? "✓" : ""}</td>
<td>Passkey</td>
<td>${!!passkeyInfo ? escapeHtml(passkeyInfo[0].credentialLabel) : ''}</td>
<td>${!!passkeyInfo ? formatDate(passkeyInfo[0].createdAt) : '-'}</td>
<td><a href="#" onclick="changeCredential('webauthn-passwordless');return false">Update</a></td>
<td>${!!passkeyInfo ? '<a href="#" onclick="removeCredential(\'webauthn-passwordless\');return false">Remove</a>' : ''}</td>
</tr>
<tr>
<td>${!!smsInfo ? "✓" : ""}</td>
<td>MFA SMS</td>
<td>${!!smsInfo ? escapeHtml(smsInfo[0].credentialLabel) : ''}</td>
<td>${!!smsInfo ? formatDate(smsInfo[0].createdAt) : '-'}</td>
<td><a href="#" onclick="changeCredential('mfa-sms');return false">Update</a></td>
<td>${!!smsInfo ? '<a href="#" onclick="removeCredential(\'mfa-sms\');return false">Remove</a>' : ''}</td>
</tr>
${trustedDeviceAuthHtml}
<tr>
<td>${!!recoveryCodeInfo ? "✓" : ""}</td>
<td>Recovery Code</td>
<td>${!!recoveryCodeInfo ? escapeHtml(recoveryCodeInfo[0].credentialLabel) + `(${recoveryCodeInfo[0].metadata['remainingCodes']})` : ''}</td>
<td>${!!recoveryCodeInfo ? formatDate(recoveryCodeInfo[0].createdAt) : '-'}</td>
<td><a href="#" onclick="changeCredential('recovery-authn-codes');return false">Update</a></td>
<td>${!!recoveryCodeInfo ? '<a href="#" onclick="removeCredential(\'recovery-authn-codes\');return false">Remove</a>' : ''}</td>
</tr>
${emailCodeAuthHtml}
${otpAuthHtml}
</tbody>
</table>
`;
show(securityHtml, "message-content");
}
window.showStepUp = async function () {
let stepupHtml = `
<ul>
<li><a onclick="stepUpAuth('acr')" href="#">Stepup MFA (ACR via Claims)</a></li>
<li><a onclick="stepUpAuth('acrValues')" href="#">Stepup MFA (ACR_VALUES)</a></li> <!-- available in Keycloak 23.x -->
</ul>
`;
show(stepupHtml, "message-content");
}
window.stepUpAuth = function (mode) {
if (mode === 'acr') {
keycloak.login({
acr: {
values: ["2fa"],
essential: true
}
});
} else if (mode === 'acrValues') {
keycloak.login({
acrValues: "2fa"
});
}
}
window.showApps = async function () {
await keycloak.updateToken(5);
let appsData;
try {
let response = await sendRequest(`${keycloakUrl}/realms/${realm}/custom-resources/me/applications`)
if (response.ok) {
appsData = await response.json();
} else {
appsData = {error: "status " + response.status};
}
} catch (error) {
console.log(error);
appsData = {error: error.message};
}
let clients = [...appsData.clients].filter((value, index, arr) => {
// filter current client
return clientId !== value.clientId;
});
let appEntriesHtml = "";
if (clients && clients.length > 0) {
for (let client of clients) {
appEntriesHtml += `
<tr>
<td>${escapeHtml(client.clientName ? client.clientName : client.clientId)}</td>
<td>${escapeHtml(client.description ? client.description : '-')}</td>
<td><a href="${client.effectiveUrl}" target="_blank">Browse</a></td>
</tr>`;
}
} else {
appEntriesHtml += `
<tr>
<td colspan="3">No Clients</td>
</tr>`;
}
let appsHtml = `
<table class="apps">
<thead>
<th>Client</th>
<th>Description</th>
<th>Actions</th>
</thead>
<tbody>
${appEntriesHtml}
</tbody>
</table>
`;
show(appsHtml, "message-content");
}
function formatDate(timestamp) {
if (!timestamp) {
return "--";
}
return new Intl.DateTimeFormat('de-DE', {dateStyle: 'medium', timeStyle: 'short'}).format(new Date(timestamp))
}
window.changePassword = function () {
keycloak.login({
action: "UPDATE_PASSWORD"
});
}
window.changeEmail = function () {
keycloak.login({
action: "acme-update-email" // use custom update email action
// action: "UPDATE_EMAIL" // use native update email action
});
}
window.changeCredential = function (method) {
let actions = {
"otp": "CONFIGURE_TOTP",
"mfa-sms": "acme-update-phonenumber",
"acme-trusted-device": "acme-manage-trusted-device",
"recovery-authn-codes": "CONFIGURE_RECOVERY_AUTHN_CODES",
"mfa-email-code": "acme-register-email-code",
"webauthn-passwordless": "webauthn-register-passwordless",
}
let action = actions[method];
if (!action) {
console.error("No action found for method: " + method);
return;
}
keycloak.login({
action: action
});
}
window.removeCredential = async function (credentialType, credentialId) {
if (!(["otp", "mfa-sms", "acme-trusted-device", "recovery-authn-codes", "mfa-email-code", "webauthn-passwordless"].includes(credentialType))) {
return;
}
let credentialsData;
try {
let response = await sendRequest(`${keycloakUrl}/realms/${realm}/custom-resources/me/credentials`, {
method: "DELETE",
credentials: "include", // send KEYCLOAK_DEVICE cookie
body: JSON.stringify({credentialType, credentialId})
})
if (response.ok) {
credentialsData = await response.json();
} else {
credentialsData = {error: "status " + response.status};
}
} catch (error) {
console.log(error);
credentialsData = {error: error.message};
}
showSecurity();
}
window.showProfile = async function () {
await keycloak.updateToken(5);
let profileData;
try {
let response = await sendRequest(`${keycloakUrl}/realms/${realm}/custom-resources/me/profile`)
if (response.ok) {
profileData = await response.json();
} else {
profileData = {error: "status " + response.status};
}
} catch (error) {
console.log(error);
profileData = {error: error.message};
}
let firstName = escapeHtml(profileData.firstName) || "";
let lastName = escapeHtml(profileData.lastName) || "";
// Alternatively we could also read the values from the IDToken
// let firstName = escapeHtml(keycloak.idTokenParsed['given_name']);
// let lastName = escapeHtml(keycloak.idTokenParsed['family_name']);
// use email from IDToken directly
let email = escapeHtml(keycloak.idTokenParsed['email']);
let emailVerified = keycloak.idTokenParsed['email_verified'];
if (!email) {
email = "N/A";
emailVerified = false;
}
// use phoneNumber from IDToken directly
let phoneNumber = escapeHtml(keycloak.idTokenParsed['phone_number']);
let phoneNumberVerified = keycloak.idTokenParsed['phone_number_verified']
if (!phoneNumber) {
phoneNumber = "N/A";
phoneNumberVerified = false;
}
let picture = escapeHtml(keycloak.idTokenParsed['picture']);
if (!picture) {
// https://png-pixel.com
picture = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==";
}
let profileHtml = `
<table class="profile">
<tr>
<td class="label">First name</td>
<td><input type="text" id="firstName" name="firstName" value="${firstName}" pattern="[\w\d][\w\d\s]{0,64}" placeholder="Firstname" required></td>
<td></td>
<td></td>
<th rowspan="2"><img src="${picture}"></th>
</tr>
<tr>
<td class="label">Last name</td>
<td><input type="text" id="lastName" name="lastName" value="${lastName}" pattern="[\w\d][\w\d\s]{0,64}" placeholder="Lastname" required></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td class="label">Email</td>
<td><span id="email">${email}</span></td>
<td title="${emailVerified ? 'Email verified' : ''}">${emailVerified ? '✔' : ''}</td>
<td><a id="changeEmail" href="#" onclick="changeEmail();return false">Update</a></td>
<td></td>
</tr>
<tr>
<td class="label">Phone</td>
<td><span id="phoneNumber">${phoneNumber}</span></td>
<td title="${phoneNumberVerified ? 'Phone number verified' : ''}">${phoneNumberVerified ? '✔' : ''}</td>
<td></td>
<td></td>
</tr>
</table>
<button id="btnSaveProfile" onClick="saveProfile(); return false">Save</button>
<button name="deleteAccountBtn" onclick="requestAccountDeletion()" class="accountDeletion">Delete</button>
<span id="profileStatus"></span>
`;
show(profileHtml, "message-content");
}
window.saveProfile = async function () {
await keycloak.updateToken(5);
let profileData = {
firstName: $("#firstName").value,
lastName: $("#lastName").value
};
try {
let profileStatus = document.getElementById("profileStatus");
profileStatus.innerText = "Saving profile ...";
let btnSave = document.getElementById("btnSaveProfile");
btnSave.disabled = true;
try {
let response = await sendRequest(`${keycloakUrl}/realms/${realm}/custom-resources/me/profile`, {
method: "PUT",
body: JSON.stringify(profileData)
})
let newProfileData;
if (response.ok) {
newProfileData = await response.json();
profileStatus.innerText = "Profile saved";
} else {
newProfileData = {error: "status " + response.status};
profileStatus.innerText = "Could not save profile";
}
} catch (exception) {
newProfileData = {error: "status " + exception};
profileStatus.innerText = "Could not save profile";
}
setTimeout(() => {
profileStatus.innerText = "";
btnSave.disabled = false;
}, 1000)
} catch (error) {
console.log(error);
newProfileData = {error: error.message};
}
// update token to reflect name changes in ID Token
await keycloak.updateToken(5);
}
window.showSettings = async function () {
await keycloak.updateToken(5);
let settingsData;
try {
let response = await sendRequest(`${keycloakUrl}/realms/${realm}/custom-resources/me/settings`)
if (response.ok) {
settingsData = await response.json();
} else {
settingsData = {error: "status " + response.status};
}
} catch (error) {
console.log(error);
settingsData = {error: error.message};
}
let setting1 = escapeHtml(settingsData.setting1);
let setting2 = escapeHtml(settingsData.setting2);
let settingsHtml = `
<form id="frmSettings" name="frmSettings" action="" onsubmit="return false" onkeydown="return event.key !== 'Enter';">
<table>
<tr>
<td class="label"><label for="setting1">Setting 1</label></td>
<td><input type="text" id="setting1" name="setting1" value="${setting1}" pattern="[\d\w]{0,20}"></td>
</tr>
<tr>
<td class="label"><label for="setting2">Setting 2</label></td>
<td><input type="checkbox" id="setting2" name="setting2" ${setting2 ? "checked" : ""}></td>
</tr>
</table>
<button id="btnSaveSettings" onClick="saveSettings(); return false">Save</button>
<span id="settingsStatus"></span>
</form>
`;
show(settingsHtml, "message-content");
}
window.saveSettings = async function () {
await keycloak.updateToken(5);
let settings = {
"setting1": $("#setting1").value,
"setting2": $("#setting2").checked
};
let newSettingsData = {};
try {
let settingsStatus = document.getElementById("settingsStatus");
settingsStatus.innerText = "Saving settings ...";
let btnSave = document.getElementById("btnSaveSettings");
btnSave.disabled = true;
try {
let response = await sendRequest(`${keycloakUrl}/realms/${realm}/custom-resources/me/settings`, {
method: "PUT",
body: JSON.stringify(settings)
})
if (response.ok) {
newSettingsData = await response.json();
settingsStatus.innerText = "Settings saved";
} else {
newSettingsData = {error: "status " + response.status};
settingsStatus.innerText = "Could not save settings";
}
} catch (exception) {
newSettingsData = {error: "status " + exception};
settingsStatus.innerText = "Could not save settings";
}
setTimeout(() => {
settingsStatus.innerText = "";
btnSave.disabled = false;
}, 1000)
} catch (error) {
console.log(error);
newSettingsData = {error: error.message};
}
}
window.sendRequest = function (url, requestOptions) {
let requestData = {
timeout: 2000,
method: "GET",
headers: {
"Authorization": "Bearer " + keycloak.token,
"Accept": "application/json",
'Content-Type': 'application/json'
}
, ...requestOptions
}
return fetch(url, requestData);
}
window.showToken = function () {
let data = JSON.stringify(keycloak.tokenParsed, null, ' ');
show(data, "token-content");
}
window.showIdToken = function () {
let data = JSON.stringify(keycloak.idTokenParsed, null, ' ');
show(data, "token-content");
}
window.showUserInfo = async function () {
await keycloak.updateToken(5);
let userInfoData = await keycloak.loadUserInfo();
let data = JSON.stringify(userInfoData, null, ' ');
show(data, "token-content");
}
window.requestAccountDeletion = async function () {
console.log("Requesting account deletion");
let settingsStatus = document.getElementById("profileStatus");
await keycloak.updateToken(5);
let accountDeletionData;
try {
settingsStatus.innerText = "Requesting account deletion ...";
let response = await sendRequest(`${keycloakUrl}/realms/${realm}/custom-resources/me/account`, {
method: "DELETE"
});
if (response.ok) {
accountDeletionData = await response.json();
settingsStatus.innerText = "Account deletion pending.";
} else {
accountDeletionData = {error: "status " + response.status};
}
} catch (error) {
console.log(error);
accountDeletionData = {error: error.message};
}
return accountDeletionData;
}
window.fetchMeInfoData = async function () {
console.log("Fetching me info");
await keycloak.updateToken(5);
let meData;
try {
let response = await sendRequest(`${meInfo.getCurrentBackendUrl()}/api/users/me`)
if (response.ok) {
meData = await response.json();
} else {
meData = {error: "status " + response.status};
}
} catch (error) {
console.log(error);
meData = {error: error.message};
}
return meData;
}
window.showMeInfo = async function showMeInfo() {
let meData = await fetchMeInfoData();
let meDataJson = JSON.stringify(meData, null, ' ');
let meInfoHtml = `
<label for="meBackend">Backend:</label>
<select name="meBackend" id="meBackend" onchange="updateMeBackend()">
</select><button id="btnMeBackendFetch" onclick="showMeInfo(); return false;">Fetch</button>
<div id="data">${meDataJson}</div>
`;
show(meInfoHtml, "token-content");
let meBackendElement = $('#meBackend');
meBackendElement.innerHTML = '';
for (let backend in meInfo.backends) {
let option = document.createElement("option");
let backendInfo = meInfo.backends[backend];
option.value = backend;
option.innerText = backendInfo.label;
if (meInfo.currentBackend === backend) {
option.selected = true;
}
meBackendElement.appendChild(option);
}
}
window.updateMeBackend = function () {
console.log("updated me backend");
let meBackendElement = $('#meBackend');
let value = meBackendElement.options[meBackendElement.selectedIndex].value;
meInfo.updateCurrentBackend(value);
showMeInfo();
}
window.show = function (data, cssClass) {
let contentElement = $('#content');
contentElement.classList.remove("hidden")
let dataElement = $('#data');
dataElement.innerHTML = data;
dataElement.classList.remove(["message-content", "token-content"]);
dataElement.classList.add(cssClass);
}
// Use the browser's built-in functionality to quickly and safely escape
// the string
window.escapeHtml = function (str) {
if (!str) {
return "";
}
const div = document.createElement('div');
div.appendChild(document.createTextNode(str));
return div.innerHTML;
}
// dynamically add keycloak.js script
try {
let jsSrc = keycloakJsSrc || "../site/lib/keycloak-js/keycloak.js";
const { default: Keycloak } = await import(jsSrc);
// window.onload = () => {
let keycloak = new Keycloak({
url: keycloakUrl,
realm: realm,
clientId: clientId
});
window.keycloak = keycloak;
// workaround for changes with oidc logout in Keycloak 18.0.0
// See https://www.keycloak.org/docs/latest/upgrading/index.html#openid-connect-logout
keycloak.createLogoutUrl = function (options) {
return keycloak.endpoints.logout()
+ '?id_token_hint=' + keycloak.idToken
+ '&post_logout_redirect_uri=' + encodeURIComponent(options?.redirectUri || window.location.href);
}
let initConfig = {
onLoad: 'login-required', // redirects to login if not login
// onLoad: 'check-sso', // shows login and register button if not logged in
checkLoginIframe: true,
checkLoginIframeInterval: 1,
pkceMethod: 'S256',
scope: scope
};
let onLoginSuccess = () => {
if (keycloak.authenticated) {
showProfile();
} else {
showWelcome();
}
};
keycloak.init(initConfig).then(onLoginSuccess);
keycloak.onAuthLogout = showWelcome;
} catch (error) {
console.error('Error loading Keycloak module:', error);
}
</script>
</body>
</html>
================================================
FILE: apps/acme-greetme/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>App: ClientId</title>
<style>
ul.menu > li {
display: inline;
padding: 1px;
}
.hidden {
visibility: hidden;
}
</style>
</head>
<body>
<nav>
<ul class="menu">
<li>
<button id="loginBtn" onclick="showLogin()">Login</button>
<button id="registerBtn" onclick="showRegister()">Register</button>
<button id="manageConsentBtn" onclick="showLogin({prompt: 'consent'})">Manage consent</button>
<button id="operation1Btn" onclick="performOperation('op1','name')" class="operation">Op 1 (name)</button>
<button id="operation2Btn" onclick="performOperation('op2','phone')" class="operation">Op 2 (phone)</button>
<button id="operation3Btn" onclick="performOperation('op3','phone name')" class="operation">Op 3 (phone+name)</button>
<button id="operation4Btn" onclick="performOperation('op4','acme.api')" class="operation">Op 4 (acme.api)</button>
<button id="operation5Btn" onclick="performOperation('op5','address')" class="operation">Op 5 (address)</button>
<button id="logoutBtn" onclick="keycloak.logout()" class="hidden">Logout</button>
</li>
</ul>
</nav>
<div>
<h1>ClientId: <span id="clientInfo"></span></h1>
<div id="greeting" class="hidden">
<h2>Email: <span id="email"></span></h2>
<h2>Email Verified: <span id="emailVerified"></span></h2>
<h2>Username: <span id="username"></span></h2>
<h2>Name: <span id="displayName"></span></h2>
<h2>Firstname: <span id="firstname"></span></h2>
<h2>Lastname: <span id="lastname"></span></h2>
<h2>Phone: <span id="phone"></span></h2>
<h2>Phone Verified: <span id="phoneVerified"></span></h2>
<h2>Requested Scope: <span id="scopeRequested"></span></h2>
<h2>Granted Scope: <span id="scopeGranted"></span></h2>
<h2>Issuer: <span id="issuer"></span></h2>
</div>
</div>
<script defer type="module">
function $(selector) {
return document.querySelector(selector);
}
let searchParams = new URLSearchParams(window.location.search);
let keycloakBaseUrl = searchParams.get("base_url") || (window.location.protocol === "http:" ? "http://id.acme.test:8080" : "https://id.acme.test:8443");
let keycloakUrl = keycloakBaseUrl + (searchParams.get("path") || "/auth");
let userInfoUrl = searchParams.get("userinfo_url");
let realm = searchParams.get("realm") || 'acme-internal';
let clientId = searchParams.get("client_id") || 'app-greetme';
window.document.title = "App: " + clientId;
// ?scope=openid+email+custom.profile+custom.ageinfo
// let scope = searchParams.get("scope") || 'openid email profile phone';
let scope = searchParams.get("scope") || 'openid email name phone';
if (scope === "openid") {
scope = "";
}
document.getElementById("clientInfo").textContent = clientId;
window.showLogin = async function(config) {
await keycloak.login(config);
}
window.showRegister = async function() {
let registerUrl = await keycloak.createRegisterUrl();
window.location = registerUrl;
}
window.showWelcome = function () {
$("#loginBtn").classList.remove("hidden");
$("#registerBtn").classList.remove("hidden");
$("#manageConsentBtn").classList.add("hidden");
[...document.querySelectorAll(".operation")].forEach(op => op.classList.add("hidden"));
$("#logoutBtn").classList.add("hidden");
}
window.updateUserProfileFromUserInfoEndpoint = async function (userProfile) {
let userInfoResponse = await fetch(userInfoUrl, {
timeout: 2000,
method: "GET",
headers: {
"Authorization": "Bearer " + keycloak.token,
"Accept": "application/json"
}
});
let userInfo = await userInfoResponse.json();
userProfile["name"] = userInfo["name"]
userProfile["given_name"] = userInfo["given_name"]
userProfile["family_name"] = userInfo["family_name"]
userProfile["email"] = userInfo["email"]
userProfile["email_verified"] = userInfo["email_verified"]
userProfile["phone_number"] = userInfo["phone_number"]
userProfile["phone_number_verified"] = userInfo["phone_number_verified"]
console.log(userInfo)
}
window.showGreeting = async function () {
$("#loginBtn").classList.add("hidden");
$("#registerBtn").classList.add("hidden");
$("#logoutBtn").classList.remove("hidden");
$("#manageConsentBtn").classList.remove("hidden");
[...document.querySelectorAll(".operation")].forEach(op => op.classList.remove("hidden"));
$("#greeting").classList.toggle("hidden");
let userProfile = getUserProfileFromKeycloakToken();
if (userInfoUrl) {
await updateUserProfileFromUserInfoEndpoint(userProfile, userInfoUrl);
}
$("#username").innerText = userProfile.preferred_username;
$("#displayName").innerText = userProfile.name;
$("#firstname").innerText = userProfile.given_name;
$("#lastname").innerText = userProfile.family_name;
$("#email").innerText = userProfile.email;
$("#emailVerified").innerText = userProfile.email_verified;
$("#phone").innerText = userProfile.phone_number;
$("#phoneVerified").innerText = userProfile.phone_number_verified;
$("#issuer").innerText = keycloak.tokenParsed.iss;
$("#scopeRequested").innerText = scope;
$("#scopeGranted").innerText = keycloak.tokenParsed.scope;
}
window.getUserProfileFromKeycloakToken = function () {
return {
preferred_username: keycloak.tokenParsed.preferred_username,
name: keycloak.tokenParsed.name,
given_name: keycloak.tokenParsed.given_name,
family_name: keycloak.tokenParsed.family_name,
email: keycloak.tokenParsed.email,
email_verified: keycloak.tokenParsed.email_verified,
phone_number: keycloak.tokenParsed.phone_number,
phone_number_verified: keycloak.tokenParsed.phone_number_verified,
};
}
window.performOperation = function (operationName, requiredScope) {
if (!isScopePresent(requiredScope)) {
redirectForConsent(requiredScope);
return;
}
alert("Perform operation " + operationName);
}
window.isScopePresent = function (requiredScope) {
let grantedScopeNames = (keycloak.tokenParsed.scope || "openid").split(" ")
let requiredScopeNames = requiredScope.split(" ");
return requiredScopeNames.every(it => grantedScopeNames.includes(it));
}
window.redirectForConsent = function (requiredScope) {
// need to request additional required scope
let requestedScope = keycloak.tokenParsed.scope + " " + requiredScope;
// update current redirect URL
let currentUrl = new URL(window.location.href);
currentUrl.searchParams.set("scope", requestedScope);
let redirectUriWithNewScope = currentUrl.toString();
// perform new authorization code flow
keycloak.login({scope: requestedScope, redirectUri: redirectUriWithNewScope});
}
// dynamically add keycloak.js script
try {
let jsSrc = "../site/lib/keycloak-js/keycloak.js";
const { default: Keycloak } = await import(jsSrc);
// window.onload = () => {
let keycloak = new Keycloak({
url: keycloakUrl,
realm: realm,
clientId: clientId
});
window.keycloak = keycloak;
// workaround for changes with oidc logout in Keycloak 18.0.0
// See https://www.keycloak.org/docs/latest/upgrading/index.html#openid-connect-logout
keycloak.createLogoutUrl = function (options) {
return keycloak.endpoints.logout()
+ '?id_token_hint=' + keycloak.idToken
+ '&post_logout_redirect_uri=' + encodeURIComponent(options?.redirectUri || window.location.href);
}
let initConfig = {
// onLoad: 'login-required', // redirects to login if not login
onLoad: 'check-sso', // shows login and register button if not logged in
checkLoginIframe: true,
checkLoginIframeInterval: 1,
pkceMethod: 'S256',
scope: scope
};
let onLoginSuccess = () => {
if (keycloak.authenticated) {
showGreeting();
} else {
showWelcome();
}
};
keycloak.init(initConfig).then(onLoginSuccess);
keycloak.onAuthLogout = showWelcome;
} catch (error) {
console.error('Error loading Keycloak module:', error);
}
</script>
</body>
</html>
================================================
FILE: apps/acme-webapp-saml-node-express/package.json
================================================
{
"name": "acme-webapp-saml-node-express",
"version": "1.0.0",
"main": "src/index.js",
"author": "Thomas Darimont",
"license": "MIT",
"dependencies": {
"@node-saml/passport-saml": "^4.0.2",
"body-parser": "^1.20.2",
"ejs": "^3.1.8",
"es6-promisify": "^7.0.0",
"express": "^4.18.2",
"express-session": "^1.17.3",
"https": "^1.0.0",
"passport": "^0.6.0",
"spdy": "^4.0.2",
"stoppable": "^1.1.0",
"winston": "^3.8.2"
},
"type": "module",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js"
},
"devDependencies": {
"nodemon": "^2.0.12"
}
}
================================================
FILE: apps/acme-webapp-saml-node-express/src/config.js
================================================
import fs from "fs";
const IDP_ISSUER = process.env.IDP_ISSUER || "https://id.acme.test:8443/auth/realms/acme-internal";
const PORT = process.env.PORT || 4723;
const HOSTNAME = process.env.HOSTNAME || "apps.acme.test" + (PORT === 443 ? "" : ":"+ PORT);
const SP_ISSUER = process.env.SP_ISSUER || "acme-webapp-saml-node-express";
const TLS_CERT_FILE = process.env.TLS_CERT_FILE || '../../config/stage/dev/tls/acme.test+1.pem';
const TLS_KEY_FILE = process.env.TLS_KEY_FILE || '../../config/stage/dev/tls/acme.test+1-key.pem';
const LOG_LEVEL = process.env.LOG_LEVEL || 'info';
const LOG_FORMAT = process.env.LOG_FORMAT || 'json'; // plain / json
// see https://github.com/RisingStack/kubernetes-graceful-shutdown-example/blob/master/src/index.js
const READINESS_PROBE_DELAY = process.env.READINESS_PROBE_DELAY || 1000; // 2 * 2 * 1000; // failureThreshold: 2, periodSeconds: 2 (4s)
const SESSION_SECRET = process.env.SECRET || 'keyboard cat';
// Private Key generated in SAML client in Keycloak
let SAML_SP_KEY = process.env.SAML_SP_KEY || fs.readFileSync("sp.key.pem", "utf-8")
// realm certificate used to sign saml requests from Keycloak
let SAML_IDP_CERT = process.env.SAML_IDP_CERT;
export default {
IDP_ISSUER,
SP_ISSUER,
HOSTNAME,
PORT,
SAML_SP_KEY,
SAML_IDP_CERT,
TLS_CERT_FILE,
TLS_KEY_FILE,
LOG_LEVEL,
LOG_FORMAT,
READINESS_PROBE_DELAY,
SESSION_SECRET
};
================================================
FILE: apps/acme-webapp-saml-node-express/src/express.js
================================================
import express from "express";
import session from "express-session";
import passport from "passport";
import {Strategy as SamlStrategy} from "@node-saml/passport-saml";
import {default as bodyParser} from "body-parser";
function createExpressApp(config, LOG) {
LOG.info("Create express app");
const app = express();
app.use(bodyParser.urlencoded({extended: true}));
configureSession(app, config);
configureSaml(app, config, LOG);
configureTemplateEngine(app, config);
configureRoutes(app, config);
return app;
}
function configureSession(app, config) {
app.use(session({
secret: config.SESSION_SECRET,
resave: false,
saveUninitialized: true,
cookie: {secure: true}
}));
}
let samlStrategy;
function configureSaml(app, config, LOG) {
app.use(passport.initialize());
app.use(passport.session());
passport.serializeUser(function (user, done) {
done(null, user);
});
passport.deserializeUser(function (user, done) {
done(null, user);
});
let idpSamlMetadataUrl = config.IDP_ISSUER + "/protocol/saml/descriptor";
LOG.info("Fetching SAML metadata from IdP: " + idpSamlMetadataUrl);
fetch(idpSamlMetadataUrl).then(response => response.text()).then(samlMetadata => {
LOG.info("Successfully fetched SAML metadata from IdP");
// LOG.info("##### SAML Metadata: \n" + samlMetadata)
// poor man's IdP metadata parsing
let idpCert = samlMetadata.match(/<ds:X509Certificate>(.*)<\/ds:X509Certificate>/)[1];
samlStrategy = new SamlStrategy(
// See Config parameter details: https://www.npmjs.com/package/passport-saml
// See also https://github.com/node-saml/passport-saml
{
entryPoint: config.IDP_ISSUER + "/protocol/saml",
issuer: config.SP_ISSUER,
host: config.HOSTNAME,
protocol: "https://",
signatureAlgorithm: "sha256",
privateKey: config.SAML_SP_KEY,
// cert: config.SAML_IDP_CERT,
cert: idpCert,
passReqToCallback: true,
logoutUrl: config.IDP_ISSUER + "/protocol/saml",
identifierFormat: "urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified",
},
// Sign-in Verify
function (request, profile, done) {
// profile contains user profile data sent from server
let user = {
username: profile["nameID"],
firstname: profile["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],
lastname: profile["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],
email: profile["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"],
// e.g. if you added a Group claim
group: profile["http://schemas.xmlsoap.org/claims/Group"],
nameID: profile.nameID,
nameIDFormat: profile.nameIDFormat,
};
return done(null, user);
},
// Sign-out Verify
function (request, profile, done) {
// profile contains user profile data sent from server
let user = {
username: profile["nameID"],
firstname: profile["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname"],
lastname: profile["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname"],
email: profile["http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"],
// e.g. if you added a Group claim
group: profile["http://schemas.xmlsoap.org/claims/Group"],
nameID: profile.nameID,
nameIDFormat: profile.nameIDFormat,
};
return done(null, user);
}
);
passport.use(samlStrategy);
}).catch((error) => {
console.error('Could not fetch Saml Metadata from IdP', error);
});
}
function configureTemplateEngine(app, config) {
// set the view engine to ejs
app.set('view engine', 'ejs');
}
function configureRoutes(app, config) {
let ensureAuthenticated = function (req, res, next) {
if (!req.isAuthenticated()) {
// let redirectTo = `${req.protocol}://${req.get('host')}${req.originalUrl}`;
// res.session.redirectToUrl = req.originalUrl;
res.redirect('/login?target=' + encodeURIComponent(req.originalUrl))
return;
}
return next();
}
app.get('/login',
function (req, res, next) {
// try to extract desired target location in app
let additionalParams = null;
if (req.query.target) {
let decodedTarget = decodeURIComponent(req.query.target);
if (decodedTarget.startsWith("/")) {
additionalParams = {
RelayState: encodeURIComponent(decodedTarget)
};
}
}
passport.authenticate('saml', {
failureRedirect: '/',
failureFlash: true,
additionalParams: additionalParams
}, null)(req, res, next);
},
function (req, res) {
res.redirect('/app');
}
);
app.post('/saml',
passport.authenticate('saml', {
failureRedirect: '/error',
failureFlash: true
}, null),
(req, res) => {
// success redirection to index
return res.redirect('/');
}
);
app.post('/saml/consume',
passport.authenticate('saml', {
failureRedirect: '/error',
failureFlash: true
}),
(req, res) => {
if (req.body.RelayState) {
let decodedTargetUri = decodeURIComponent(req.body.RelayState);
if (decodedTargetUri.startsWith("/")) {
return res.redirect(decodedTargetUri);
}
}
// success redirection to /app
return res.redirect('/app');
}
);
app.get('/logout',
ensureAuthenticated,
(req, res, next) => {
if (req.user != null) {
return samlStrategy.logout(req, (err, uri) => {
return req.logout(err => {
if (err) {
LOG.warn("Could not logout: " + err);
return next(err);
}
req.session.destroy();
res.redirect(uri);
});
});
}
return res.redirect('/');
});
app.get('/error',
function (req, res) {
res.render('pages/error');
}
);
app.get('/',
function (req, res) {
res.render('pages/index');
}
);
app.get('/app',
ensureAuthenticated,
function (req, res) {
let user = req.user;
res.render('pages/app', {
user
});
}
);
app.get('/page1',
ensureAuthenticated,
function (req, res) {
let user = req.user;
res.render('pages/page1', {
user
});
}
);
}
export default createExpressApp;
================================================
FILE: apps/acme-webapp-saml-node-express/src/index.js
================================================
'use strict'
import config from './config.js';
import initLogging from './logging.js';
import createExpressApp from './express.js';
import createServer from "./server.js";
const LOG = initLogging(config);
const app = createExpressApp(config, LOG);
createServer(app, config, LOG);
================================================
FILE: apps/acme-webapp-saml-node-express/src/logging.js
================================================
import winston from "winston";
function initLogging(config) {
const loggingFormat = winston.format.combine(
winston.format.timestamp(),
'json' === config.LOG_FORMAT
? winston.format.json()
: winston.format.simple()
);
return winston.createLogger({
level: config.LOG_LEVEL,
format: loggingFormat,
defaultMeta: {service: 'acme-webapp-saml-node-express'},
transports: [
new winston.transports.Console(),
//
// - Write all logs with level `error` and below to `error.log`
// - Write all logs with level `info` and below to `combined.log`
//
// new winston.transports.File({ filename: 'error.log', level: 'error' }),
// new winston.transports.File({ filename: 'combined.log' }),
],
});
}
export default initLogging;
================================================
FILE: apps/acme-webapp-saml-node-express/src/server.js
================================================
import fs from "fs";
import stoppable from "stoppable";
import {promisify} from "es6-promisify";
import spdy from "spdy";
function createServer(app, config, LOG) {
LOG.info("Create server");
const httpsServer = spdy.createServer({
key: fs.readFileSync(config.TLS_KEY_FILE),
cert: fs.readFileSync(config.TLS_CERT_FILE),
}, app);
// for Graceful shutdown see https://github.com/RisingStack/kubernetes-graceful-shutdown-example
configureGracefulShutdown(httpsServer, config, LOG);
// Start server
httpsServer.listen(config.PORT, () => {
LOG.info(`Listening on HTTPS port ${config.PORT}`);
LOG.info(`Using frontend URL ${config.FRONTEND_URL}`);
});
}
function configureGracefulShutdown(httpsServer, config, LOG) {
// Keep-alive connections doesn't let the server to close in time
// Destroy extension helps to force close connections
// Because we wait READINESS_PROBE_DELAY, we expect that all requests are fulfilled
// https://en.wikipedia.org/wiki/HTTP_persistent_connection
stoppable(httpsServer);
const serverDestroy = promisify(httpsServer.stop.bind(httpsServer));
// Graceful stop
async function gracefulStop() {
LOG.info('Server is shutting down...')
try {
await serverDestroy(); // close server first (ongoing requests)
LOG.info('Successful graceful shutdown');
process.exit(0); // exit with ok code
} catch (err) {
LOG.error('Error happened during graceful shutdown', err)
process.exit(1) // exit with not ok code
}
}
// Support graceful shutdown
// do not accept more request and release resources
process.on('SIGTERM', () => {
LOG.info('Got SIGTERM. Graceful shutdown start');
// Wait a little bit to give enough time for Kubernetes readiness probe to fail (we don't want more traffic)
// Don't worry livenessProbe won't kill it until (failureThreshold: 3) => 30s
// http://www.bite-code.com/2015/07/27/implementing-graceful-shutdown-for-docker-containers-in-go-part-2/
setTimeout(gracefulStop, config.READINESS_PROBE_DELAY);
});
}
export default createServer;
================================================
FILE: apps/acme-webapp-saml-node-express/views/pages/app.ejs
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('../partials/head'); %>
</head>
<body class="container">
<header>
<%- include('../partials/header'); %>
</header>
<main>
<div class="jumbotron">
<h1>App</h1>
<h1>Welcome User: <%= user.username %></h1>
<ul>
<li>Firstname: <%= user.firstname %></li>
<li>Lastname: <%= user.lastname %></li>
<li>E-Mail: <%= user.email %></li>
</ul>
</div>
</main>
<footer>
<%- include('../partials/footer'); %>
</footer>
</body>
</html>
================================================
FILE: apps/acme-webapp-saml-node-express/views/pages/error.ejs
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('../partials/head'); %>
</head>
<body class="container">
<header>
<%- include('../partials/header'); %>
</header>
<main>
<div class="jumbotron">
<h1>An error occurred!</h1>
</div>
</main>
<footer>
<%- include('../partials/footer'); %>
</footer>
</body>
</html>
================================================
FILE: apps/acme-webapp-saml-node-express/views/pages/index.ejs
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('../partials/head'); %>
</head>
<body class="container">
<header>
<%- include('../partials/header'); %>
</header>
<main>
<div class="jumbotron">
Welcome!
</div>
</main>
<footer>
<%- include('../partials/footer'); %>
</footer>
</body>
</html>
================================================
FILE: apps/acme-webapp-saml-node-express/views/pages/page1.ejs
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<%- include('../partials/head'); %>
</head>
<body class="container">
<header>
<%- include('../partials/header'); %>
</header>
<main>
<div class="jumbotron">
<h1>Page 1</h1>
<h1>Welcome User: <%= user.username %></h1>
<ul>
<li>Firstname: <%= user.firstname %></li>
<li>Lastname: <%= user.lastname %></li>
<li>E-Mail: <%= user.email %></li>
</ul>
</div>
</main>
<footer>
<%- include('../partials/footer'); %>
</footer>
</body>
</html>
================================================
FILE: apps/acme-webapp-saml-node-express/views/partials/footer.ejs
================================================
<p class="text-center text-muted">© Copyright 2022 Thomas Darimont</p>
================================================
FILE: apps/acme-webapp-saml-node-express/views/partials/head.ejs
================================================
<meta charset="UTF-8">
<title>Acme Webapp with SAML and NodeJS Express</title>
<!-- CSS (load bootstrap from a CDN) -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.5.2/css/bootstrap.min.css">
<style>
body { padding-top:50px; }
</style>
================================================
FILE: apps/acme-webapp-saml-node-express/views/partials/header.ejs
================================================
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="/">Acme Webapp SAML Node</a>
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
<% if (locals.user) { %>
<li class="nav-item">
<a class="nav-link" href="/app">App</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/page1">Page 1</a>
</li>
<% } %>
<li class="nav-item">
<% if (locals.user) { %>
<a class="nav-link" href="/logout">Logout</a>
<% } else { %>
<a class="nav-link" href="/login">Login</a>
<% } %>
</li>
</ul>
</nav>
================================================
FILE: apps/backend-api-dnc/api/.dockerignore
================================================
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/.idea
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
================================================
FILE: apps/backend-api-dnc/api/.gitignore
================================================
# Visual Studio
bin/
obj/
.vs/
*.user
================================================
FILE: apps/backend-api-dnc/api/Controllers/UsersController.cs
================================================
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
namespace Api.Controllers;
[ApiController]
[Route("/api/users")]
public class UsersController
{
private readonly ILogger<UsersController> _logger;
private readonly IHttpContextAccessor _accessor;
public UsersController(ILogger<UsersController> logger, IHttpContextAccessor accessor)
{
_logger = logger;
_accessor = accessor;
}
[Authorize]
[HttpGet]
[Route("me")]
public object Me() {
_logger.LogInformation("### Accessing {}", _accessor.HttpContext?.Request.Path.Value);
// var username = _accessor.HttpContext?.User.FindFirst("preferred_username")?.Value;
var username = _accessor.HttpContext?.User?.Identity?.Name;
var data = new Dictionary<string,object>
{
{ "message", "Hello " + username },
{ "backend", "AspNetCore" },
{ "datetime", DateTime.Now }
};
return data;
}
}
================================================
FILE: apps/backend-api-dnc/api/Dockerfile
================================================
FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /src
COPY ["api/api.csproj", "api/"]
RUN dotnet restore "api/api.csproj"
COPY . .
WORKDIR "/src/api"
RUN dotnet build "api.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "api.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "api.dll"]
================================================
FILE: apps/backend-api-dnc/api/JwtBearerOptions.cs
================================================
namespace Api;
/// <summary>
/// Options for JWT Bearer authentication.
/// </summary>
public class JwtBearerOptions
{
/// <summary>
/// Gets or sets the authority.
/// </summary>
/// <value>
/// The authority.
/// </value>
public string Authority { get; set; } = String.Empty;
/// <summary>
/// Gets or sets the audience.
/// </summary>
/// <value>
/// The audience.
/// </value>
public string Audience { get; set; } = String.Empty;
}
================================================
FILE: apps/backend-api-dnc/api/Program.cs
================================================
using Microsoft.AspNetCore.Authentication.JwtBearer;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddLogging(config =>
{
config.AddDebug();
config.AddConsole();
//etc
});
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
// builder.Services.AddEndpointsApiExplorer();
// builder.Services.AddSwaggerGen();
builder.Services.AddCors(options => options.AddDefaultPolicy(b =>
{
b.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
var jwtOptions = builder.Configuration.GetSection("JwtBearer").Get<JwtBearerOptions>();
builder.Services
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = jwtOptions.Authority;
options.Audience = jwtOptions.Audience;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters.NameClaimType = "preferred_username";
options.TokenValidationParameters.RoleClaimType = "role";
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
// app.UseSwagger();
// app.UseSwaggerUI();
}
app.UseCors();
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
================================================
FILE: apps/backend-api-dnc/api/Properties/launchSettings.json
================================================
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:43687",
"sslPort": 44332
}
},
"profiles": {
"api": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7229;http://localhost:5178",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_Kestrel__Certificates__Default__Path": "../../../config/stage/dev/tls/acme.test+1.pem",
"ASPNETCORE_Kestrel__Certificates__Default__KeyPath": "../../../config/stage/dev/tls/acme.test+1-key.pem"
},
"workingDirectory": "."
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": false,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
================================================
FILE: apps/backend-api-dnc/api/api.csproj
================================================
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.9" />
<PackageReference Include="Microsoft.AspNetCore.Authorization" Version="7.0.0-preview.7.22376.6" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
</ItemGroup>
</Project>
================================================
FILE: apps/backend-api-dnc/api/appsettings.Development.json
================================================
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"JwtBearer": {
"Authority": "https://id.acme.test:8443/auth/realms/acme-internal",
"Audience": "account"
},
"Kestrel": {
"HttpsInlineCertAndKeyFile": {
"Url": "https://apps.acme.test:7229",
"Certificate": {
"Path": "../../../config/stage/dev/tls/acme.test+1.pem",
"KeyPath": "../../../config/stage/dev/tls/acme.test+1-key.pem",
"Password": ""
}
}
}
}
================================================
FILE: apps/backend-api-dnc/api/appsettings.json
================================================
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Kestrel": {
"HttpsInlineCertAndKeyFile": {
"Url": "https://apps.acme.test:7229",
"Certificate": {
"Path": "../../../config/stage/dev/tls/acme.test+1.pem",
"KeyPath": "../../../config/stage/dev/tls/acme.test+1-key.pem",
"Password": ""
}
}
}
}
================================================
FILE: apps/backend-api-dnc/backend-api-dnc.sln
================================================
Microsoft Visual Studio Solution File, Format Version 12.00
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "api", "api\api.csproj", "{DF1D196F-6305-4ADD-A02E-84CAF13F59C7}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DF1D196F-6305-4ADD-A02E-84CAF13F59C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DF1D196F-6305-4ADD-A02E-84CAF13F59C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DF1D196F-6305-4ADD-A02E-84CAF13F59C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DF1D196F-6305-4ADD-A02E-84CAF13F59C7}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
================================================
FILE: apps/backend-api-micronaut/.gitignore
================================================
Thumbs.db
.DS_Store
.gradle
build/
target/
out/
.idea
*.iml
*.ipr
*.iws
.project
.settings
.classpath
.factorypath
================================================
FILE: apps/backend-api-micronaut/.mvn/wrapper/MavenWrapperDownloader.java
================================================
/*
* Copyright 2007-present the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.Properties;
public class MavenWrapperDownloader {
private static final String WRAPPER_VERSION = "0.5.6";
/**
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
*/
private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/"
+ WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar";
/**
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
* use instead of the default one.
*/
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
".mvn/wrapper/maven-wrapper.properties";
/**
* Path where the maven-wrapper.jar will be saved to.
*/
private static final String MAVEN_WRAPPER_JAR_PATH =
".mvn/wrapper/maven-wrapper.jar";
/**
* Name of the property which should be used to override the default download url for the wrapper.
*/
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
public static void main(String args[]) {
System.out.println("- Downloader started");
File baseDirectory = new File(args[0]);
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
// If the maven-wrapper.properties exists, read it and check if it contains a custom
// wrapperUrl parameter.
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
String url = DEFAULT_DOWNLOAD_URL;
if(mavenWrapperPropertyFile.exists()) {
FileInputStream mavenWrapperPropertyFileInputStream = null;
try {
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
Properties mavenWrapperProperties = new Properties();
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
} catch (IOException e) {
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
} finally {
try {
if(mavenWrapperPropertyFileInputStream != null) {
mavenWrapperPropertyFileInputStream.close();
}
} catch (IOException e) {
// Ignore ...
}
}
}
System.out.println("- Downloading from: " + url);
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
if(!outputFile.getParentFile().exists()) {
if(!outputFile.getParentFile().mkdirs()) {
System.out.println(
"- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'");
}
}
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
try {
downloadFileFromURL(url, outputFile);
System.out.println("Done");
System.exit(0);
} catch (Throwable e) {
System.out.println("- Error downloading");
e.printStackTrace();
System.exit(1);
}
}
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) {
String username = System.getenv("MVNW_USERNAME");
char[] password = System.getenv("MVNW_PASSWORD").toCharArray();
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(username, password);
}
});
}
URL website = new URL(urlString);
ReadableByteChannel rbc;
rbc = Channels.newChannel(website.openStream());
FileOutputStream fos = new FileOutputStream(destination);
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
fos.close();
rbc.close();
}
}
================================================
FILE: apps/backend-api-micronaut/.mvn/wrapper/maven-wrapper.properties
================================================
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip
wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar
================================================
FILE: apps/backend-api-micronaut/README.md
================================================
## Micronaut 3.3.4 Documentation
- [User Guide](https://docs.micronaut.io/3.3.4/guide/index.html)
- [API Reference](https://docs.micronaut.io/3.3.4/api/index.html)
- [Configuration Reference](https://docs.micronaut.io/3.3.4/guide/configurationreference.html)
- [Micronaut Guides](https://guides.micronaut.io/index.html)
---
## Feature http-client documentation
- [Micronaut HTTP Client documentation](https://docs.micronaut.io/latest/guide/index.html#httpClient)
## Feature security-jwt documentation
- [Micronaut Security JWT documentation](https://micronaut-projects.github.io/micronaut-security/latest/guide/index.html)
================================================
FILE: apps/backend-api-micronaut/micronaut-cli.yml
================================================
applicationType: default
defaultPackage: com.acme.backend.micronaut
testFramework: junit
sourceLanguage: java
buildTool: maven
features: [annotation-api, app-name, http-client, jackson-databind, java, java-application, junit, logback, maven, netty-server, readme, security-annotations, security-jwt, shade, yaml]
================================================
FILE: apps/backend-api-micronaut/mvnw
================================================
#!/bin/sh
# ----------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# ----------------------------------------------------------------------------
# ----------------------------------------------------------------------------
# Maven Start Up Batch script
#
# Required ENV vars:
# ------------------
# JAVA_HOME - location of a JDK home dir
#
# Optional ENV vars
# -----------------
# M2_HOME - location of maven2's installed home dir
# MAVEN_OPTS - parameters passed to the Java VM when running Maven
# e.g. to debug Maven itself, use
# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
# MAVEN_SKIP_RC - flag to disable loading of mavenrc files
# ----------------------------------------------------------------------------
if [ -z "$MAVEN_SKIP_RC" ] ; then
if [ -f /etc/mavenrc ] ; then
. /etc/mavenrc
fi
if [ -f "$HOME/.mavenrc" ] ; then
. "$HOME/.mavenrc"
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
mingw=false
case "`uname`" in
CYGWIN*) cygwin=true ;;
MINGW*) mingw=true;;
Darwin*) darwin=true
# Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home
# See https://developer.apple.com/library/mac/qa/qa1170/_index.html
if [ -z "$JAVA_HOME" ]; then
if [ -x "/usr/libexec/java_home" ]; then
export JAVA_HOME="`/usr/libexec/java_home`"
else
export JAVA_HOME="/Library/Java/Home"
fi
fi
;;
esac
if [ -z "$JAVA_HOME" ] ; then
if [ -r /etc/gentoo-release ] ; then
JAVA_HOME=`java-config --jre-home`
fi
fi
if [ -z "$M2_HOME" ] ; then
## resolve links - $0 may be a link to maven's home
PRG="$0"
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG="`dirname "$PRG"`/$link"
fi
done
saveddir=`pwd`
M2_HOME=`dirname "$PRG"`/..
# make it fully qualified
M2_HOME=`cd "$M2_HOME" && pwd`
cd "$saveddir"
# echo Using m2 at $M2_HOME
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --unix "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
fi
# For Mingw, ensure paths are in UNIX format before anything is touched
if $mingw ; then
[ -n "$M2_HOME" ] &&
M2_HOME="`(cd "$M2_HOME"; pwd)`"
[ -n "$JAVA_HOME" ] &&
JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`"
fi
if [ -z "$JAVA_HOME" ]; then
javaExecutable="`which javac`"
if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then
# readlink(1) is not available as standard on Solaris 10.
readLink=`which readlink`
if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then
if $darwin ; then
javaHome="`dirname \"$javaExecutable\"`"
javaExecutable="`cd \"$javaHome\" && pwd -P`/javac"
else
javaExecutable="`readlink -f \"$javaExecutable\"`"
fi
javaHome="`dirname \"$javaExecutable\"`"
javaHome=`expr "$javaHome" : '\(.*\)/bin'`
JAVA_HOME="$javaHome"
export JAVA_HOME
fi
fi
fi
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD="`which java`"
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly." >&2
echo " We cannot execute $JAVACMD" >&2
exit 1
fi
if [ -z "$JAVA_HOME" ] ; then
echo "Warning: JAVA_HOME environment variable is not set."
fi
CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher
# traverses directory structure from process work directory to filesystem root
# first directory with .mvn subdirectory is considered project base directory
find_maven_basedir() {
if [ -z "$1" ]
then
echo "Path not specified to find_maven_basedir"
return 1
fi
basedir="$1"
wdir="$1"
while [ "$wdir" != '/' ] ; do
if [ -d "$wdir"/.mvn ] ; then
basedir=$wdir
break
fi
# workaround for JBEAP-8937 (on Solaris 10/Sparc)
if [ -d "${wdir}" ]; then
wdir=`cd "$wdir/.."; pwd`
fi
# end of workaround
done
echo "${basedir}"
}
# concatenates all lines of a file
concat_lines() {
if [ -f "$1" ]; then
echo "$(tr -s '\n' ' ' < "$1")"
fi
}
BASE_DIR=`find_maven_basedir "$(pwd)"`
if [ -z "$BASE_DIR" ]; then
exit 1;
fi
##########################################################################################
# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
# This allows using the maven wrapper in projects that prohibit checking in binary data.
##########################################################################################
if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found .mvn/wrapper/maven-wrapper.jar"
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..."
fi
if [ -n "$MVNW_REPOURL" ]; then
jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
else
jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
fi
while IFS="=" read key value; do
case "$key" in (wrapperUrl) jarUrl="$value"; break ;;
esac
done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties"
if [ "$MVNW_VERBOSE" = true ]; then
echo "Downloading from: $jarUrl"
fi
wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar"
if $cygwin; then
wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"`
fi
if command -v wget > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found wget ... using wget"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
wget "$jarUrl" -O "$wrapperJarPath"
else
wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath"
fi
elif command -v curl > /dev/null; then
if [ "$MVNW_VERBOSE" = true ]; then
echo "Found curl ... using curl"
fi
if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then
curl -o "$wrapperJarPath" "$jarUrl" -f
else
curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f
fi
else
if [ "$MVNW_VERBOSE" = true ]; then
echo "Falling back to using Java to download"
fi
javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java"
# For Cygwin, switch paths to Windows format before running javac
if $cygwin; then
javaClass=`cygpath --path --windows "$javaClass"`
fi
if [ -e "$javaClass" ]; then
if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Compiling MavenWrapperDownloader.java ..."
fi
# Compiling the Java class
("$JAVA_HOME/bin/javac" "$javaClass")
fi
if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then
# Running the downloader
if [ "$MVNW_VERBOSE" = true ]; then
echo " - Running MavenWrapperDownloader.java ..."
fi
("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR")
fi
fi
fi
fi
##########################################################################################
# End of extension
##########################################################################################
export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}
if [ "$MVNW_VERBOSE" = true ]; then
echo $MAVEN_PROJECTBASEDIR
fi
MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS"
# For Cygwin, switch paths to Windows format before running java
if $cygwin; then
[ -n "$M2_HOME" ] &&
M2_HOME=`cygpath --path --windows "$M2_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"`
[ -n "$CLASSPATH" ] &&
CLASSPATH=`cygpath --path --windows "$CLASSPATH"`
[ -n "$MAVEN_PROJECTBASEDIR" ] &&
MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"`
fi
# Provide a "standardized" way to retrieve the CLI args that will
# work with both Windows and non-Windows executions.
MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@"
export MAVEN_CMD_LINE_ARGS
WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
exec "$JAVACMD" \
$MAVEN_OPTS \
-classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \
"-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@"
================================================
FILE: apps/backend-api-micronaut/mvnw.bat
================================================
@REM ----------------------------------------------------------------------------
@REM Licensed to the Apache Software Foundation (ASF) under one
@REM or more contributor license agreements. See the NOTICE file
@REM distributed with this work for additional information
@REM regarding copyright ownership. The ASF licenses this file
@REM to you under the Apache License, Version 2.0 (the
@REM "License"); you may not use this file except in compliance
@REM with the License. You may obtain a copy of the License at
@REM
@REM https://www.apache.org/licenses/LICENSE-2.0
@REM
@REM Unless required by applicable law or agreed to in writing,
@REM software distributed under the License is distributed on an
@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@REM KIND, either express or implied. See the License for the
@REM specific language governing permissions and limitations
@REM under the License.
@REM ----------------------------------------------------------------------------
@REM ----------------------------------------------------------------------------
@REM Maven Start Up Batch script
@REM
@REM Required ENV vars:
@REM JAVA_HOME - location of a JDK home dir
@REM
@REM Optional ENV vars
@REM M2_HOME - location of maven2's installed home dir
@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending
@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
@REM e.g. to debug Maven itself, use
@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
@REM ----------------------------------------------------------------------------
@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
@echo off
@REM set title of command window
title %0
@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on'
@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
@REM set %HOME% to equivalent of $HOME
if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
@REM Execute a user defined script before this one
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
@REM check for pre script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
:skipRcPre
@setlocal
set ERROR_CODE=0
@REM To isolate internal variables from possible post scripts, we use another setlocal
@setlocal
@REM ==== START VALIDATION ====
if not "%JAVA_HOME%" == "" goto OkJHome
echo.
echo Error: JAVA_HOME not found in your environment. >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
:OkJHome
if exist "%JAVA_HOME%\bin\java.exe" goto init
echo.
echo Error: JAVA_HOME is set to an invalid directory. >&2
echo JAVA_HOME = "%JAVA_HOME%" >&2
echo Please set the JAVA_HOME variable in your environment to match the >&2
echo location of your Java installation. >&2
echo.
goto error
@REM ==== END VALIDATION ====
:init
@REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
@REM Fallback to current working directory if not found.
set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
set EXEC_DIR=%CD%
set WDIR=%EXEC_DIR%
:findBaseDir
IF EXIST "%WDIR%"\.mvn goto baseDirFound
cd ..
IF "%WDIR%"=="%CD%" goto baseDirNotFound
set WDIR=%CD%
goto findBaseDir
:baseDirFound
set MAVEN_PROJECTBASEDIR=%WDIR%
cd "%EXEC_DIR%"
goto endDetectBaseDir
:baseDirNotFound
set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
cd "%EXEC_DIR%"
:endDetectBaseDir
IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
@setlocal EnableExtensions EnableDelayedExpansion
for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
:endReadAdditionalConfig
SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar"
set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO (
IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B
)
@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central
@REM This allows using the maven wrapper in projects that prohibit checking in binary data.
if exist %WRAPPER_JAR% (
if "%MVNW_VERBOSE%" == "true" (
echo Found %WRAPPER_JAR%
)
) else (
if not "%MVNW_REPOURL%" == "" (
SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar"
)
if "%MVNW_VERBOSE%" == "true" (
echo Couldn't find %WRAPPER_JAR%, downloading it ...
echo Downloading from: %DOWNLOAD_URL%
)
powershell -Command "&{"^
"$webclient = new-object System.Net.WebClient;"^
"if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^
"$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^
"}"^
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^
"}"
if "%MVNW_VERBOSE%" == "true" (
echo Finished downloading %WRAPPER_JAR%
)
)
@REM End of extension
@REM Provide a "standardized" way to retrieve the CLI args that will
@REM work with both Windows and non-Windows executions.
set MAVEN_CMD_LINE_ARGS=%*
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %*
if ERRORLEVEL 1 goto error
goto end
:error
set ERROR_CODE=1
:end
@endlocal & set ERROR_CODE=%ERROR_CODE%
if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
@REM check for post script, once with legacy .bat ending and once with .cmd ending
if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
:skipRcPost
@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
if "%MAVEN_BATCH_PAUSE%" == "on" pause
if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
exit /B %ERROR_CODE%
================================================
FILE: apps/backend-api-micronaut/pom.xml
================================================
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.acme.backend.micronaut</groupId>
<artifactId>backend-api-micronaut</artifactId>
<version>0.1</version>
<packaging>${packaging}</packaging>
<parent>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-parent</artifactId>
<version>3.4.0</version>
</parent>
<properties>
<packaging>jar</packaging>
<jdk.version>11</jdk.version>
<release.version>11</release.version>
<micronaut.version>${project.parent.version}</micronaut.version>
<exec.mainClass>com.acme.backend.micronaut.Application</exec.mainClass>
<micronaut.runtime>netty</micronaut.runtime>
</properties>
<repositories>
<repository>
<id>central</id>
<url>https://repo.maven.apache.org/maven2</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-inject</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-validation</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.micronaut.test</groupId>
<artifactId>micronaut-test-junit5</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-http-client</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-http-server-netty</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-jackson-databind</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-runtime</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>io.micronaut.security</groupId>
<artifactId>micronaut-security-jwt</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.micronaut.build</groupId>
<artifactId>micronaut-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<!-- Uncomment to enable incremental compilation -->
<!-- <useIncrementalCompilation>false</useIncrementalCompilation> -->
<annotationProcessorPaths combine.children="append">
<path>
<groupId>io.micronaut</groupId>
<artifactId>micronaut-http-validation</artifactId>
<version>${micronaut.version}</version>
</path>
<path>
<groupId>io.micronaut.security</groupId>
<artifactId>micronaut-security-annotations</artifactId>
<version>${micronaut.security.version}</version>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>-Amicronaut.processing.group=com.acme.backend.micronaut</arg>
<arg>-Amicronaut.processing.module=backend-api-micronaut</arg>
</compilerArgs>
</configuration>
</plugin>
</plugins>
</build>
</project>
================================================
FILE: apps/backend-api-micronaut/src/main/java/com/acme/backend/micronaut/Application.java
================================================
package com.acme.backend.micronaut;
import io.micronaut.runtime.Micronaut;
public class Application {
public static void main(String[] args) {
Micronaut.run(Application.class, args);
}
}
================================================
FILE: apps/backend-api-micronaut/src/main/java/com/acme/backend/micronaut/api/UsersResource.java
================================================
package com.acme.backend.micronaut.api;
import io.micronaut.http.HttpRequest;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.security.annotation.Secured;
import io.micronaut.security.authentication.Authentication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;
import static io.micronaut.security.rules.SecurityRule.IS_AUTHENTICATED;
@Secured(IS_AUTHENTICATED)
@Controller("/api/users")
class UsersResource {
private static final Logger log = LoggerFactory.getLogger(UsersResource.class);
@Get("/me")
public Object me(HttpRequest<?> request, Authentication authentication) {
log.info("### Accessing {}", request.getUri());
Object username = authentication.getName();
Map<String, Object> data = new HashMap<>();
data.put("message", "Hello " + username);
data.put("backend", "Micronaut");
data.put("datetime", Instant.now());
return data;
}
}
================================================
FILE: apps/backend-api-micronaut/src/main/resources/application.yml
================================================
micronaut:
application:
name: backendApiMicronaut
ssl:
enabled: true
keyStore:
path: file:config/stage/dev/tls/acme.test+1.p12 # (1)
password: changeit # (2)
type: PKCS12
security:
authentication: bearer
token:
name-key: "preferred_username"
jwt:
signatures:
jwks:
keycloak:
url: "${micronaut.security.token.jwt.claims-validators.issuer}/protocol/openid-connect/certs"
claims-validators:
issuer: "https://id.acme.test:8443/auth/realms/acme-internal"
expiration: true
subject-not-null: true
# audience: ""
server:
ssl:
port: 4953
cors:
enabled: true
configurations:
web:
allowedOrigins:
- https://apps.acme.test:4443
netty:
default:
allocator:
max-order: 3
================================================
FILE: apps/backend-api-micronaut/src/main/resources/logback.xml
================================================
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<withJansi>true</withJansi>
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n</pattern>
</encoder>
</appender>
<root level="info">
<appender-ref ref="STDOUT" />
</root>
</configuration>
================================================
FILE: apps/backend-api-node-express/package.json
================================================
{
"name": "backend-api-node-express",
"version": "1.0.0",
"main": "src/index.js",
"author": "Thomas Darimont",
"license": "MIT",
"dependencies": {
"cors": "^2.8.5",
"es6-promisify": "^7.0.0",
"express": "^4.17.1",
"express-jwt": "^6.1.0",
"https": "^1.0.0",
"jwks-rsa": "^2.0.4",
"spdy": "^4.0.2",
"stoppable": "^1.1.0",
"winston": "^3.3.3"
},
"type": "module",
"scripts": {
"start": "node src/index.js",
"dev": "nodemon src/index.js"
},
"devDependencies": {
"nodemon": "^2.0.12"
}
}
================================================
FILE: apps/backend-api-node-express/readme.md
================================================
Acme Backend API Node Express
---
# Setup
Add rootCA for self-signed certificates - required for fetching public keys from JWKS endpoint in Keycloak.
```
export NODE_EXTRA_CA_CERTS=$(mkcert -CAROOT)/rootCA.pem
```
# Build
```
yarn install
```
# Run
```
yarn run start
```
================================================
FILE: apps/backend-api-node-express/src/api.js
================================================
/**
* Initializes the API endpoints
* @param app
* @param LOG
*/
function createApiEndpoints(app, config, LOG) {
LOG.info('Create API endpoints');
// API routes can then access JWT claims in the request object via request.user
app.get('/api/users/me', (req, res) => {
let username = req.user.preferred_username;
LOG.info(`### Accessing ${req.path}`);
const data = {
datetime: new Date().toISOString(),
message: `Hello ${username}`,
backend: 'NodeJS Express',
};
res.status(200).send(JSON.stringify(data));
});
}
export default createApiEndpoints;
================================================
FILE: apps/backend-api-node-express/src/config.js
================================================
const ISSUER = process.env.ISSUER || "https://id.acme.test:8443/auth/realms/acme-internal";
const PORT = process.env.PORT || 4743;
const CORS_ALLOWED_ORIGINS = process.env.CORS_ALLOWED_ORIGINS || 'https://apps.acme.test:4443'; // * or https://domain1:4443,https://domain2:4443
const CORS_ALLOWED_METHODS = process.env.CORS_ALLOWED_METHODS || 'GET'; // or GET,POST,PUT
const TLS_CERT = process.env.TLS_CERT || '../../config/stage/dev/tls/acme.test+1.pem';
const TLS_KEY = process.env.TLS_KEY || '../../config/stage/dev/tls/acme.test+1-key.pem';
const LOG_LEVEL = process.env.LOG_LEVEL || 'info';
const LOG_FORMAT = process.env.LOG_FORMAT || 'json'; // plain / json
// see https://github.com/RisingStack/kubernetes-graceful-shutdown-example/blob/master/src/index.js
const READINESS_PROBE_DELAY = process.env.READINESS_PROBE_DELAY || 1000; // 2 * 2 * 1000; // failureThreshold: 2, periodSeconds: 2 (4s)
export default {
ISSUER,
PORT,
CORS_ALLOWED_METHODS,
CORS_ALLOWED_ORIGINS,
TLS_CERT,
TLS_KEY,
LOG_LEVEL,
LOG_FORMAT,
READINESS_PROBE_DELAY,
};
================================================
FILE: apps/backend-api-node-express/src/express.js
================================================
import express from "express";
import cors from "cors";
import jwksRsa from "jwks-rsa";
import jwt from "express-jwt";
function createExpressApp(config, LOG) {
LOG.info("Create express app");
const app = express();
configureCors(app, config, LOG);
configureJwtAuthorization(app, config, LOG);
return app;
}
function configureCors(app, config, LOG) {
LOG.info("Configure CORS");
const corsOptions = {
origin: config.CORS_ALLOWED_ORIGINS.split(","),
methods: config.CORS_ALLOWED_METHODS.split(","),
optionsSuccessStatus: 200 // For legacy browser support
};
app.use(cors(corsOptions));
}
function configureJwtAuthorization(app, config, LOG) {
LOG.info("Configure JWT Authorization");
// JWT Bearer Authorization
let jwtOptions = {
// Dynamically provide a signing key based on the kid in the header and the signing keys provided by the JWKS endpoint.
secret: jwksRsa.expressJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: `${config.ISSUER}/protocol/openid-connect/certs`,
handleSigningKeyError: (err, cb) => {
if (err instanceof jwksRsa.SigningKeyNotFoundError) {
return cb(new Error('Could not fetch certs from JWKS endpoint.'));
}
return cb(err);
}
}),
// Validate the audience.
// audience: 'urn:my-resource-server',
// Validate the issuer.
issuer: config.ISSUER,
algorithms: ['RS256']
};
app.use('/api/*', jwt(jwtOptions));
}
export default createExpressApp;
================================================
FILE: apps/backend-api-node-express/src/index.js
================================================
'use strict'
import config from './config.js';
import initLogging from './logging.js';
import createExpressApp from './express.js';
import createApiEndpoints from './api.js';
import createServer from "./server.js";
const LOG = initLogging(config);
const app = createExpressApp(config, LOG);
createApiEndpoints(app, config, LOG);
createServer(app, config, LOG);
================================================
FILE: apps/backend-api-node-express/src/logging.js
================================================
import winston from "winston";
function initLogging(config) {
const loggingFormat = winston.format.combine(
winston.format.timestamp(),
'json' === config.LOG_FORMAT
? winston.format.json()
: winston.format.simple()
);
return winston.createLogger({
level: config.LOG_LEVEL,
format: loggingFormat,
defaultMeta: {service: 'acme-backend-api'},
transports: [
new winston.transports.Console(),
//
// - Write all logs with level `error` and below to `error.log`
// - Write all logs with level `info` and below to `combined.log`
//
// new winston.transports.File({ filename: 'error.log', level: 'error' }),
// new winston.transports.File({ filename: 'combined.log' }),
],
});
}
export default initLogging;
================================================
FILE: apps/backend-api-node-express/src/server.js
================================================
import fs from "fs";
import stoppable from "stoppable";
import {promisify} from "es6-promisify";
import spdy from "spdy";
function createServer(app, config, LOG) {
LOG.info("Create server");
const httpsServer = spdy.createServer({
key: fs.readFileSync(config.TLS_KEY),
cert: fs.readFileSync(config.TLS_CERT),
}, app);
// for Gracef
gitextract_j1wzyoop/
├── .github/
│ └── workflows/
│ ├── build.yml
│ └── e2e-tests.yml
├── .gitignore
├── .run/
│ ├── Acme Backend API Quarkus.run.xml
│ ├── Keycloak Remote.run.xml
│ ├── OfflineSessionClient (logout).run.xml
│ ├── OfflineSessionClient.run.xml
│ ├── acme-webapp-saml-node-express.run.xml
│ ├── backend-api-micronaut.run.xml
│ ├── backend-api-springboot-reactive.run.xml
│ ├── backend-api-springboot.run.xml
│ ├── backend-api-springboot3.run.xml
│ ├── frontend-webapp-springboot-otel.run.xml
│ ├── frontend-webapp-springboot.run.xml
│ └── frontend-webapp-springboot3.run.xml
├── .vscode/
│ └── settings.json
├── LICENSE
├── apps/
│ ├── account-svc/
│ │ ├── .dockerignore
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ ├── .gitignore
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ └── maven-wrapper.properties
│ │ ├── README.md
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── docker/
│ │ │ ├── Dockerfile.jvm
│ │ │ ├── Dockerfile.legacy-jar
│ │ │ ├── Dockerfile.native
│ │ │ └── Dockerfile.native-micro
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── thomasdarimont/
│ │ │ └── keycloak/
│ │ │ └── training/
│ │ │ └── accounts/
│ │ │ ├── User.java
│ │ │ ├── UserRepository.java
│ │ │ └── UserResource.java
│ │ └── resources/
│ │ └── application.properties
│ ├── acme-account-console/
│ │ └── index.html
│ ├── acme-greetme/
│ │ └── index.html
│ ├── acme-webapp-saml-node-express/
│ │ ├── package.json
│ │ ├── src/
│ │ │ ├── config.js
│ │ │ ├── express.js
│ │ │ ├── index.js
│ │ │ ├── logging.js
│ │ │ └── server.js
│ │ └── views/
│ │ ├── pages/
│ │ │ ├── app.ejs
│ │ │ ├── error.ejs
│ │ │ ├── index.ejs
│ │ │ └── page1.ejs
│ │ └── partials/
│ │ ├── footer.ejs
│ │ ├── head.ejs
│ │ └── header.ejs
│ ├── backend-api-dnc/
│ │ ├── api/
│ │ │ ├── .dockerignore
│ │ │ ├── .gitignore
│ │ │ ├── Controllers/
│ │ │ │ └── UsersController.cs
│ │ │ ├── Dockerfile
│ │ │ ├── JwtBearerOptions.cs
│ │ │ ├── Program.cs
│ │ │ ├── Properties/
│ │ │ │ └── launchSettings.json
│ │ │ ├── api.csproj
│ │ │ ├── appsettings.Development.json
│ │ │ └── appsettings.json
│ │ └── backend-api-dnc.sln
│ ├── backend-api-micronaut/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ └── maven-wrapper.properties
│ │ ├── README.md
│ │ ├── micronaut-cli.yml
│ │ ├── mvnw
│ │ ├── mvnw.bat
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── acme/
│ │ │ └── backend/
│ │ │ └── micronaut/
│ │ │ ├── Application.java
│ │ │ └── api/
│ │ │ └── UsersResource.java
│ │ └── resources/
│ │ ├── application.yml
│ │ └── logback.xml
│ ├── backend-api-node-express/
│ │ ├── package.json
│ │ ├── readme.md
│ │ └── src/
│ │ ├── api.js
│ │ ├── config.js
│ │ ├── express.js
│ │ ├── index.js
│ │ ├── logging.js
│ │ └── server.js
│ ├── backend-api-quarkus/
│ │ ├── .dockerignore
│ │ ├── .gitignore
│ │ ├── README.md
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── docker/
│ │ │ ├── Dockerfile.jvm
│ │ │ ├── Dockerfile.legacy-jar
│ │ │ ├── Dockerfile.native
│ │ │ └── Dockerfile.native-distroless
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── acme/
│ │ │ └── backend/
│ │ │ └── quarkus/
│ │ │ └── users/
│ │ │ └── UsersResource.java
│ │ └── resources/
│ │ ├── META-INF/
│ │ │ └── resources/
│ │ │ └── index.html
│ │ └── application.properties
│ ├── backend-api-rust-actix/
│ │ ├── .gitignore
│ │ ├── Cargo.toml
│ │ ├── rustfmt.toml
│ │ ├── rustup-toolchain.toml
│ │ └── src/
│ │ ├── api/
│ │ │ ├── me_info.rs
│ │ │ └── mod.rs
│ │ ├── config.rs
│ │ ├── main.rs
│ │ └── middleware/
│ │ ├── cors.rs
│ │ ├── jwt_auth.rs
│ │ ├── mod.rs
│ │ └── ssl.rs
│ ├── backend-api-rust-rocket/
│ │ ├── .gitignore
│ │ ├── .run/
│ │ │ └── Run backend-api-rust-rocket.run.xml
│ │ ├── Cargo.toml
│ │ ├── README.md
│ │ ├── Rocket.toml
│ │ ├── rustfmt.toml
│ │ ├── rustup-toolchain.toml
│ │ ├── src/
│ │ │ ├── domain/
│ │ │ │ ├── mod.rs
│ │ │ │ └── user.rs
│ │ │ ├── main.rs
│ │ │ ├── middleware/
│ │ │ │ ├── auth/
│ │ │ │ │ ├── jwt/
│ │ │ │ │ │ ├── auth.rs
│ │ │ │ │ │ ├── claims.rs
│ │ │ │ │ │ ├── config.rs
│ │ │ │ │ │ ├── get_max_age.rs
│ │ │ │ │ │ ├── jwks.rs
│ │ │ │ │ │ ├── mod.rs
│ │ │ │ │ │ └── verifier.rs
│ │ │ │ │ ├── jwt_auth_request_guard.rs
│ │ │ │ │ └── mod.rs
│ │ │ │ ├── cors/
│ │ │ │ │ ├── cors.rs
│ │ │ │ │ └── mod.rs
│ │ │ │ ├── logging/
│ │ │ │ │ ├── logging.rs
│ │ │ │ │ └── mod.rs
│ │ │ │ └── mod.rs
│ │ │ └── support/
│ │ │ ├── mod.rs
│ │ │ └── scheduling/
│ │ │ ├── mod.rs
│ │ │ └── use_repeating_job.rs
│ │ └── tests/
│ │ └── fetch_keys.rs
│ ├── backend-api-springboot/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ └── maven-wrapper.properties
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── acme/
│ │ │ │ └── backend/
│ │ │ │ └── springboot/
│ │ │ │ └── users/
│ │ │ │ ├── BackendApiSpringbootApp.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── AcmeServiceProperties.java
│ │ │ │ │ ├── JwtSecurityConfig.java
│ │ │ │ │ ├── MethodSecurityConfig.java
│ │ │ │ │ └── WebSecurityConfig.java
│ │ │ │ ├── support/
│ │ │ │ │ ├── access/
│ │ │ │ │ │ └── AccessController.java
│ │ │ │ │ ├── keycloak/
│ │ │ │ │ │ ├── KeycloakAudienceValidator.java
│ │ │ │ │ │ ├── KeycloakGrantedAuthoritiesConverter.java
│ │ │ │ │ │ └── KeycloakJwtAuthenticationConverter.java
│ │ │ │ │ └── permissions/
│ │ │ │ │ ├── DefaultPermissionEvaluator.java
│ │ │ │ │ └── DomainObjectReference.java
│ │ │ │ └── web/
│ │ │ │ └── UsersController.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── acme/
│ │ └── backend/
│ │ └── springboot/
│ │ └── users/
│ │ └── BackendApiSpringbootAppTests.java
│ ├── backend-api-springboot-reactive/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ └── maven-wrapper.properties
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── acme/
│ │ │ │ └── backend/
│ │ │ │ └── springreactive/
│ │ │ │ ├── BackendApiSpringbootReactiveApp.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── AcmeServiceProperties.java
│ │ │ │ │ ├── JwtSecurityConfig.java
│ │ │ │ │ ├── MethodSecurityConfig.java
│ │ │ │ │ ├── WebFluxConfig.java
│ │ │ │ │ ├── WebFluxRoutes.java
│ │ │ │ │ └── WebSecurityConfig.java
│ │ │ │ ├── support/
│ │ │ │ │ └── keycloak/
│ │ │ │ │ ├── KeycloakAudienceValidator.java
│ │ │ │ │ ├── KeycloakGrantedAuthoritiesConverter.java
│ │ │ │ │ └── KeycloakJwtAuthenticationConverter.java
│ │ │ │ └── users/
│ │ │ │ └── UserHandlers.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── acme/
│ │ └── backend/
│ │ └── springreactive/
│ │ └── BackendApiSpringbootReactiveAppTests.java
│ ├── backend-api-springboot3/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ ├── MavenWrapperDownloader.java
│ │ │ └── maven-wrapper.properties
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── acme/
│ │ │ │ └── backend/
│ │ │ │ └── springboot/
│ │ │ │ └── users/
│ │ │ │ ├── BackendApiSpringboot3App.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── AcmeServiceProperties.java
│ │ │ │ │ ├── JwtSecurityConfig.java
│ │ │ │ │ ├── MethodSecurityConfig.java
│ │ │ │ │ └── WebSecurityConfig.java
│ │ │ │ ├── support/
│ │ │ │ │ ├── access/
│ │ │ │ │ │ └── AccessController.java
│ │ │ │ │ ├── keycloak/
│ │ │ │ │ │ ├── KeycloakAudienceValidator.java
│ │ │ │ │ │ ├── KeycloakGrantedAuthoritiesConverter.java
│ │ │ │ │ │ └── KeycloakJwtAuthenticationConverter.java
│ │ │ │ │ └── permissions/
│ │ │ │ │ ├── DefaultPermissionEvaluator.java
│ │ │ │ │ └── DomainObjectReference.java
│ │ │ │ └── web/
│ │ │ │ └── UsersController.java
│ │ │ └── resources/
│ │ │ └── application.yml
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── acme/
│ │ └── backend/
│ │ └── springboot/
│ │ └── users/
│ │ └── BackendApiSpringboot3AppTests.java
│ ├── bff-springboot/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ └── maven-wrapper.properties
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── github/
│ │ │ └── thomasdarimont/
│ │ │ └── apps/
│ │ │ └── bff/
│ │ │ ├── BffApp.java
│ │ │ ├── api/
│ │ │ │ └── UsersResource.java
│ │ │ ├── config/
│ │ │ │ ├── OAuth2RestTemplateConfig.java
│ │ │ │ ├── SessionConfig.java
│ │ │ │ ├── WebSecurityConfig.java
│ │ │ │ └── keycloak/
│ │ │ │ └── KeycloakLogoutHandler.java
│ │ │ ├── oauth/
│ │ │ │ ├── TokenAccessor.java
│ │ │ │ ├── TokenIntrospector.java
│ │ │ │ └── TokenRefresher.java
│ │ │ └── web/
│ │ │ └── UiResource.java
│ │ └── resources/
│ │ ├── application.yml
│ │ ├── static/
│ │ │ └── app/
│ │ │ └── app.js
│ │ └── templates/
│ │ └── app/
│ │ └── index.html
│ ├── bff-springboot3/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ └── maven-wrapper.properties
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── github/
│ │ │ └── thomasdarimont/
│ │ │ └── apps/
│ │ │ └── bff3/
│ │ │ ├── Bff3App.java
│ │ │ ├── api/
│ │ │ │ └── UsersResource.java
│ │ │ ├── config/
│ │ │ │ ├── OAuth2RestTemplateConfig.java
│ │ │ │ ├── SessionConfig.java
│ │ │ │ ├── WebSecurityConfig.java
│ │ │ │ └── keycloak/
│ │ │ │ └── KeycloakLogoutHandler.java
│ │ │ ├── oauth/
│ │ │ │ ├── TokenAccessor.java
│ │ │ │ ├── TokenIntrospector.java
│ │ │ │ └── TokenRefresher.java
│ │ │ ├── support/
│ │ │ │ ├── HttpServletRequestUtils.java
│ │ │ │ └── HttpSessionOAuth2AuthorizedClientService.java
│ │ │ └── web/
│ │ │ ├── AuthResource.java
│ │ │ └── UiResource.java
│ │ └── resources/
│ │ ├── application.yml
│ │ ├── static/
│ │ │ └── app/
│ │ │ └── app.js
│ │ └── templates/
│ │ └── app/
│ │ └── index.html
│ ├── frontend-webapp-springboot/
│ │ ├── .gitignore
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── github/
│ │ │ │ └── thomasdarimont/
│ │ │ │ └── keycloak/
│ │ │ │ └── webapp/
│ │ │ │ ├── WebAppSpringBoot.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── KeycloakWebClientConfig.java
│ │ │ │ │ ├── OidcUserServiceConfig.java
│ │ │ │ │ └── WebSecurityConfig.java
│ │ │ │ ├── domain/
│ │ │ │ │ ├── ApplicationEntry.java
│ │ │ │ │ ├── CredentialEntry.java
│ │ │ │ │ ├── SettingEntry.java
│ │ │ │ │ └── UserProfile.java
│ │ │ │ ├── support/
│ │ │ │ │ ├── OAuth2AuthorizedClientAccessor.java
│ │ │ │ │ ├── TokenAccessor.java
│ │ │ │ │ ├── TokenIntrospector.java
│ │ │ │ │ ├── keycloakclient/
│ │ │ │ │ │ ├── DefaultKeycloakClient.java
│ │ │ │ │ │ ├── KeycloakClient.java
│ │ │ │ │ │ ├── KeycloakIntrospectResponse.java
│ │ │ │ │ │ ├── KeycloakServiceException.java
│ │ │ │ │ │ └── KeycloakUserInfo.java
│ │ │ │ │ └── security/
│ │ │ │ │ └── KeycloakLogoutHandler.java
│ │ │ │ └── web/
│ │ │ │ ├── AuthController.java
│ │ │ │ └── UiController.java
│ │ │ └── resources/
│ │ │ ├── application.yml
│ │ │ └── templates/
│ │ │ ├── applications.html
│ │ │ ├── fragments.html
│ │ │ ├── index.html
│ │ │ ├── profile.html
│ │ │ ├── security.html
│ │ │ └── settings.html
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── github/
│ │ └── thomasdarimont/
│ │ └── keycloak/
│ │ └── cac/
│ │ └── WebApplicationTestsSpringBoot.java
│ ├── frontend-webapp-springboot3/
│ │ ├── otel-config.yaml
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── github/
│ │ │ │ └── thomasdarimont/
│ │ │ │ └── keycloak/
│ │ │ │ └── webapp/
│ │ │ │ ├── WebAppSpringBoot3.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── KeycloakWebClientConfig.java
│ │ │ │ │ ├── OidcUserServiceConfig.java
│ │ │ │ │ └── WebSecurityConfig.java
│ │ │ │ ├── domain/
│ │ │ │ │ ├── ApplicationEntry.java
│ │ │ │ │ ├── CredentialEntry.java
│ │ │ │ │ ├── SettingEntry.java
│ │ │ │ │ └── UserProfile.java
│ │ │ │ ├── support/
│ │ │ │ │ ├── HttpServletRequestUtils.java
│ │ │ │ │ ├── HttpSessionOAuth2AuthorizedClientService.java
│ │ │ │ │ ├── TokenAccessor.java
│ │ │ │ │ ├── TokenIntrospector.java
│ │ │ │ │ ├── keycloakclient/
│ │ │ │ │ │ ├── DefaultKeycloakClient.java
│ │ │ │ │ │ ├── KeycloakClient.java
│ │ │ │ │ │ ├── KeycloakIntrospectResponse.java
│ │ │ │ │ │ ├── KeycloakServiceException.java
│ │ │ │ │ │ └── KeycloakUserInfo.java
│ │ │ │ │ └── security/
│ │ │ │ │ └── KeycloakLogoutHandler.java
│ │ │ │ └── web/
│ │ │ │ ├── AuthController.java
│ │ │ │ └── UiController.java
│ │ │ └── resources/
│ │ │ ├── application.yml
│ │ │ └── templates/
│ │ │ ├── applications.html
│ │ │ ├── fragments.html
│ │ │ ├── index.html
│ │ │ ├── profile.html
│ │ │ ├── security.html
│ │ │ └── settings.html
│ │ └── test/
│ │ └── java/
│ │ └── com/
│ │ └── github/
│ │ └── thomasdarimont/
│ │ └── keycloak/
│ │ └── cac/
│ │ └── WebApplicationTestsSpringBoot.java
│ ├── java-opa-embedded/
│ │ ├── .gitignore
│ │ ├── jd-gui.cfg
│ │ ├── pom.xml
│ │ ├── readme.md
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── demo/
│ │ │ └── OpaEmbeddedDemo.java
│ │ └── resources/
│ │ ├── data/
│ │ │ └── user_roles.json
│ │ └── policy/
│ │ ├── app/
│ │ │ └── rbac/
│ │ │ └── policy.rego
│ │ └── policy.wasm
│ ├── jwt-client-authentication/
│ │ ├── .gitignore
│ │ ├── .mvn/
│ │ │ └── wrapper/
│ │ │ └── maven-wrapper.properties
│ │ ├── mvnw
│ │ ├── mvnw.cmd
│ │ ├── pom.xml
│ │ ├── readme.md
│ │ └── src/
│ │ └── main/
│ │ ├── java/
│ │ │ └── demo/
│ │ │ └── jwtclientauth/
│ │ │ └── JwtClientAuthApp.java
│ │ └── resources/
│ │ └── application.properties
│ ├── keycloak-js/
│ │ ├── package.json
│ │ └── readme.md
│ ├── oauth2-proxy/
│ │ ├── Dockerfile
│ │ ├── app/
│ │ │ └── main.go
│ │ ├── docker-compose.yml
│ │ ├── oauth2-proxy.cfg
│ │ └── readme.md
│ ├── offline-session-client/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ └── java/
│ │ └── demo/
│ │ └── OfflineSessionClient.java
│ ├── site/
│ │ ├── accountdeleted.html
│ │ ├── imprint.html
│ │ ├── lib/
│ │ │ └── keycloak-js/
│ │ │ ├── keycloak-authz.js
│ │ │ └── keycloak.js
│ │ ├── privacy.html
│ │ ├── site.html
│ │ └── terms.html
│ └── spring-boot-device-flow-client/
│ ├── .gitignore
│ ├── .mvn/
│ │ └── wrapper/
│ │ └── maven-wrapper.properties
│ ├── mvnw
│ ├── mvnw.cmd
│ ├── pom.xml
│ └── src/
│ └── main/
│ ├── java/
│ │ └── demo/
│ │ └── SpringBootDeviceFlowApplication.java
│ └── resources/
│ └── application.properties
├── bin/
│ ├── applyRealmConfig.java
│ ├── createTlsCerts.java
│ ├── envcheck.java
│ ├── importCertificateIntoTruststore.java
│ ├── installOtel.java
│ ├── keycloakConfigCli.default.env
│ ├── keycloakConfigCli.java
│ └── realmImex.java
├── config/
│ └── stage/
│ └── dev/
│ ├── grafana/
│ │ └── provisioning/
│ │ ├── dashboards/
│ │ │ ├── dashboard.yml
│ │ │ ├── keycloak-capacity-planning-dashboard.json
│ │ │ ├── keycloak-metrics_rev1.json
│ │ │ └── keycloak-troubleshooting-dashboard.json
│ │ └── datasources/
│ │ └── datasources.yml
│ ├── opa/
│ │ ├── iam/
│ │ │ ├── authzen/
│ │ │ │ └── interop/
│ │ │ │ ├── access/
│ │ │ │ │ ├── policy.rego
│ │ │ │ │ └── v1/
│ │ │ │ │ └── search/
│ │ │ │ │ └── policy.rego
│ │ │ │ └── data.json
│ │ │ └── keycloak/
│ │ │ └── policy.rego
│ │ ├── inputs/
│ │ │ └── input.json
│ │ ├── opa.md
│ │ ├── policies/
│ │ │ └── keycloak/
│ │ │ ├── realms/
│ │ │ │ ├── opademo/
│ │ │ │ │ └── access/
│ │ │ │ │ ├── policy.rego
│ │ │ │ │ └── policy_test.rego
│ │ │ │ └── opademo2/
│ │ │ │ └── access/
│ │ │ │ └── policy.rego
│ │ │ └── utils/
│ │ │ └── kc/
│ │ │ └── helpers.rego
│ │ └── watch-opa.sh
│ ├── openldap/
│ │ └── demo.ldif
│ ├── otel/
│ │ ├── otel-collector-config-tls.yaml
│ │ └── otel-collector-config.yaml
│ ├── prometheus/
│ │ └── prometheus.yml
│ ├── realms/
│ │ ├── acme-api.yaml
│ │ ├── acme-apps.yaml
│ │ ├── acme-auth0.yaml
│ │ ├── acme-client-examples.yaml
│ │ ├── acme-demo.yaml
│ │ ├── acme-internal.yaml
│ │ ├── acme-ldap.yaml
│ │ ├── acme-offline-test.yaml
│ │ ├── acme-ops.yaml
│ │ ├── acme-passwordless.yaml
│ │ ├── acme-saml.yaml
│ │ ├── acme-stepup.yaml
│ │ ├── company-apps.yaml
│ │ ├── company-users.yaml
│ │ ├── master.yaml
│ │ ├── other/
│ │ │ ├── acme-internal-custom.yaml
│ │ │ ├── acme-saml.yaml
│ │ │ ├── acme-user-profile.yaml
│ │ │ ├── acme-vci.yaml
│ │ │ ├── acme-workshop-clients.yaml
│ │ │ ├── acme-workshop-idp.yaml
│ │ │ └── acme-workshop.yaml
│ │ └── workshop.yaml
│ └── tls/
│ └── .gitkeep
├── deployments/
│ └── local/
│ ├── cluster/
│ │ ├── apache/
│ │ │ ├── docker-compose-apache.yml
│ │ │ └── id.acme.test.conf
│ │ ├── caddy/
│ │ │ ├── caddy.json
│ │ │ └── docker-compose-caddy.yml
│ │ ├── cli/
│ │ │ ├── 0001-onstart-init.cli
│ │ │ ├── 0010-add-jmx-user.sh
│ │ │ ├── 0100-onstart-setup-remote-caches.cli
│ │ │ ├── 0200-onstart-setup-jgroups-encryption.cli
│ │ │ └── 0300-onstart-setup-ispn-jdbc-store.cli
│ │ ├── docker-compose.yml
│ │ ├── haproxy/
│ │ │ ├── Dockerfile
│ │ │ ├── docker-compose-haproxy.yml
│ │ │ └── haproxy.cfg
│ │ ├── haproxy-database-ispn/
│ │ │ ├── cli/
│ │ │ │ ├── 0010-add-jmx-user.sh
│ │ │ │ └── 0300-onstart-setup-ispn-jdbc-store.cli
│ │ │ └── docker-compose-haproxy-jdbc-store.yml
│ │ ├── haproxy-encrypted-ispn/
│ │ │ ├── cli/
│ │ │ │ └── 0200-onstart-setup-jgroups-encryption.cli
│ │ │ ├── docker-compose-enc-haproxy.yml
│ │ │ ├── ispn/
│ │ │ │ └── jgroups.p12
│ │ │ └── jgroups-keystore.sh
│ │ ├── haproxy-external-ispn/
│ │ │ ├── cli/
│ │ │ │ ├── 0100-onstart-setup-hotrod-caches.cli
│ │ │ │ └── 0100-onstart-setup-remote-caches.cli
│ │ │ ├── docker-compose-haproxy-ispn-hotrod.yml
│ │ │ ├── docker-compose-haproxy-ispn-remote.yml
│ │ │ ├── haproxy-external-ispn.env
│ │ │ ├── ispn/
│ │ │ │ ├── Dockerfile
│ │ │ │ ├── cacerts
│ │ │ │ ├── conf/
│ │ │ │ │ ├── infinispan-keycloak.xml
│ │ │ │ │ └── users.properties
│ │ │ │ ├── ispn-server.jks
│ │ │ │ └── ispn-truststore.jks
│ │ │ └── readme.md
│ │ ├── nginx/
│ │ │ ├── docker-compose-nginx.yml
│ │ │ └── nginx.conf
│ │ └── readme.md
│ ├── clusterx/
│ │ ├── docker-compose.yml
│ │ ├── haproxy/
│ │ │ ├── Dockerfile
│ │ │ ├── acme.test+1.p12
│ │ │ ├── docker-compose-haproxy.yml
│ │ │ └── haproxy.cfg
│ │ ├── haproxy-database-ispn/
│ │ │ ├── Dockerfile
│ │ │ ├── acme.test+1.p12
│ │ │ ├── cache-ispn-database.xml
│ │ │ ├── docker-compose.yml
│ │ │ ├── haproxy.cfg
│ │ │ └── readme.md
│ │ ├── haproxy-external-ispn/
│ │ │ ├── cache-ispn-remote.xml
│ │ │ ├── docker-compose-haproxy-ispn-remote.yml
│ │ │ ├── haproxy-external-ispn.env
│ │ │ ├── haproxy.cfg
│ │ │ └── ispn/
│ │ │ ├── Dockerfile
│ │ │ ├── cacerts
│ │ │ ├── conf/
│ │ │ │ ├── infinispan-keycloak.xml
│ │ │ │ └── users.properties
│ │ │ ├── ispn-server.jks
│ │ │ └── ispn-truststore.jks
│ │ ├── haproxy-external-ispn-database/
│ │ │ ├── cache-ispn-remote.xml
│ │ │ ├── docker-compose-haproxy-ispn-remote-database.yml
│ │ │ ├── haproxy-external-ispn.env
│ │ │ ├── haproxy.cfg
│ │ │ └── ispn/
│ │ │ ├── Dockerfile
│ │ │ ├── cacerts
│ │ │ ├── conf/
│ │ │ │ ├── infinispan-keycloak-database.xml
│ │ │ │ └── users.properties
│ │ │ ├── ispn-server.jks
│ │ │ └── ispn-truststore.jks
│ │ ├── keycloakx/
│ │ │ ├── Dockerfile
│ │ │ ├── cache-custom-jgroups-tcp.xml
│ │ │ ├── cache-custom-jgroups.xml
│ │ │ ├── cache-custom.xml
│ │ │ ├── jgroups-jdbcping-enc.xml
│ │ │ ├── jgroups-multicast-diag.xml
│ │ │ ├── jgroups-multicast-enc.xml
│ │ │ └── jgroups.p12
│ │ ├── nginx/
│ │ │ ├── docker-compose-nginx.yml
│ │ │ └── nginx.conf
│ │ └── readme.md
│ ├── dev/
│ │ ├── docker-compose-ci-github.yml
│ │ ├── docker-compose-grafana.yml
│ │ ├── docker-compose-graylog.yml
│ │ ├── docker-compose-keycloak.yml
│ │ ├── docker-compose-keycloakx.yml
│ │ ├── docker-compose-mssql.yml
│ │ ├── docker-compose-mysql.yml
│ │ ├── docker-compose-nats.yml
│ │ ├── docker-compose-opa.yml
│ │ ├── docker-compose-openldap.yml
│ │ ├── docker-compose-oracle.yml
│ │ ├── docker-compose-postgres.yml
│ │ ├── docker-compose-prometheus.yml
│ │ ├── docker-compose-provisioning.yml
│ │ ├── docker-compose-simplesaml.yml
│ │ ├── docker-compose-tls.yml
│ │ ├── docker-compose-tracing-tls.yml
│ │ ├── docker-compose-tracing.yml
│ │ ├── docker-compose.yml
│ │ ├── graylog/
│ │ │ ├── Dockerfile
│ │ │ ├── cli/
│ │ │ │ └── 0020-onstart-setup-graylog-logging.cli
│ │ │ ├── contentpacks/
│ │ │ │ └── iam-keycloak-content-pack-v1.json
│ │ │ └── modules/
│ │ │ └── logstash-gelf-1.14.1/
│ │ │ └── biz/
│ │ │ └── paluch/
│ │ │ └── logging/
│ │ │ └── main/
│ │ │ └── module.xml
│ │ ├── keycloak/
│ │ │ └── Dockerfile
│ │ ├── keycloak-common.env
│ │ ├── keycloak-db.env
│ │ ├── keycloak-ext/
│ │ │ └── readme.md
│ │ ├── keycloak-http.env
│ │ ├── keycloak-openldap.env
│ │ ├── keycloak-provisioning.env
│ │ ├── keycloak-tls.env
│ │ ├── keycloak-tracing.env
│ │ ├── keycloakx/
│ │ │ ├── Dockerfile
│ │ │ ├── Dockerfile-ci
│ │ │ └── health_check.sh
│ │ ├── mysql/
│ │ │ └── Dockerfile
│ │ ├── nats/
│ │ │ ├── readme.md
│ │ │ └── server.conf
│ │ ├── oracle/
│ │ │ └── Dockerfile
│ │ ├── otel-collector/
│ │ │ └── Dockerfile
│ │ ├── postgresql/
│ │ │ └── Dockerfile
│ │ ├── simplesaml/
│ │ │ └── idp/
│ │ │ ├── Dockerfile
│ │ │ └── authsources.php
│ │ └── sqlserver/
│ │ ├── Dockerfile
│ │ ├── db-init.sh
│ │ ├── db-init.sql
│ │ ├── docker-entrypoint.sh
│ │ └── mssql.conf
│ └── standalone/
│ ├── docker-compose.yml
│ ├── keycloak/
│ │ ├── Dockerfile
│ │ └── conf/
│ │ ├── keycloak.conf
│ │ └── quarkus.properties
│ ├── proxy/
│ │ └── nginx.conf
│ ├── readme.md
│ └── up.sh
├── keycloak/
│ ├── cli/
│ │ ├── 0001-onstart-init.cli
│ │ ├── 0010-register-smallrye-extensions.cli
│ │ ├── 0020-onstart-setup-graylog-logging.cli
│ │ └── 0100-onstart-deploy-extensions.sh
│ ├── clisnippets/
│ │ ├── http-client-config.md
│ │ ├── json-logging.md
│ │ ├── map-keycloak-endpoint-to-custom-endpint.md
│ │ ├── offline-sessions-lazy-loading.md
│ │ ├── undertow-access.md
│ │ └── undertow-request-logging.md
│ ├── config/
│ │ ├── jmxremote.password
│ │ ├── openid-config.json
│ │ └── quarkus.properties
│ ├── docker/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ └── docker/
│ │ ├── keycloak/
│ │ │ ├── Dockerfile.alpine-slim
│ │ │ ├── Dockerfile.ci.plain
│ │ │ ├── Dockerfile.plain
│ │ │ └── custom-docker-entrypoint.sh
│ │ └── keycloakx/
│ │ ├── Dockerfile.ci.plain
│ │ └── Dockerfile.plain
│ ├── e2e-tests/
│ │ ├── .gitignore
│ │ ├── cypress/
│ │ │ ├── e2e/
│ │ │ │ └── login/
│ │ │ │ └── login.cy.ts
│ │ │ ├── fixtures/
│ │ │ │ ├── messages.json
│ │ │ │ └── users.json
│ │ │ ├── plugins/
│ │ │ │ └── index.ts
│ │ │ ├── support/
│ │ │ │ ├── commands.ts
│ │ │ │ └── e2e.ts
│ │ │ ├── tsconfig.json
│ │ │ └── utils/
│ │ │ └── keycloakUtils.ts
│ │ ├── cypress.config.ts
│ │ ├── package.json
│ │ └── readme.md
│ ├── extensions/
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/
│ │ │ ├── java/
│ │ │ │ └── com/
│ │ │ │ └── github/
│ │ │ │ └── thomasdarimont/
│ │ │ │ └── keycloak/
│ │ │ │ └── custom/
│ │ │ │ ├── account/
│ │ │ │ │ ├── AccountActivity.java
│ │ │ │ │ ├── AccountChange.java
│ │ │ │ │ ├── AccountDeletion.java
│ │ │ │ │ ├── AccountEmail.java
│ │ │ │ │ ├── AccountPostLoginAction.java
│ │ │ │ │ ├── MfaChange.java
│ │ │ │ │ ├── RequestAccountDeletionActionToken.java
│ │ │ │ │ ├── RequestAccountDeletionActionTokenHandler.java
│ │ │ │ │ └── console/
│ │ │ │ │ └── AcmeAccountConsoleFactory.java
│ │ │ │ ├── admin/
│ │ │ │ │ └── ui/
│ │ │ │ │ └── example/
│ │ │ │ │ └── ExampleUiPageProvider.java
│ │ │ │ ├── audit/
│ │ │ │ │ └── AcmeAuditListener.java
│ │ │ │ ├── auth/
│ │ │ │ │ ├── authzen/
│ │ │ │ │ │ ├── AuthZen.java
│ │ │ │ │ │ └── AuthzenClient.java
│ │ │ │ │ ├── checkaccess/
│ │ │ │ │ │ └── CheckAccessAuthenticator.java
│ │ │ │ │ ├── confirmcookie/
│ │ │ │ │ │ └── ConfirmCookieAuthenticator.java
│ │ │ │ │ ├── customcookie/
│ │ │ │ │ │ └── CustomCookieAuthenticator.java
│ │ │ │ │ ├── debug/
│ │ │ │ │ │ └── DebugAuthenticator.java
│ │ │ │ │ ├── demo/
│ │ │ │ │ │ └── SkippableRequiredAction.java
│ │ │ │ │ ├── dynamicidp/
│ │ │ │ │ │ └── DynamicIdpAuthenticator.java
│ │ │ │ │ ├── hello/
│ │ │ │ │ │ └── HelloAuthenticator.java
│ │ │ │ │ ├── idpselection/
│ │ │ │ │ │ └── AcmeDynamicIdpLookupUsernameForm.java
│ │ │ │ │ ├── magiclink/
│ │ │ │ │ │ └── MagicLinkAuthenticator.java
│ │ │ │ │ ├── mfa/
│ │ │ │ │ │ ├── MfaInfo.java
│ │ │ │ │ │ ├── emailcode/
│ │ │ │ │ │ │ ├── EmailCodeAuthenticatorForm.java
│ │ │ │ │ │ │ ├── EmailCodeCredentialModel.java
│ │ │ │ │ │ │ ├── EmailCodeCredentialProvider.java
│ │ │ │ │ │ │ └── RegisterEmailCodeRequiredAction.java
│ │ │ │ │ │ ├── otp/
│ │ │ │ │ │ │ └── AcmeOTPFormAuthenticator.java
│ │ │ │ │ │ ├── setup/
│ │ │ │ │ │ │ └── SelectMfaMethodAuthenticator.java
│ │ │ │ │ │ └── sms/
│ │ │ │ │ │ ├── PhoneNumberUtils.java
│ │ │ │ │ │ ├── SmsAuthenticator.java
│ │ │ │ │ │ ├── SmsCodeSender.java
│ │ │ │ │ │ ├── client/
│ │ │ │ │ │ │ ├── SmsClient.java
│ │ │ │ │ │ │ ├── SmsClientFactory.java
│ │ │ │ │ │ │ └── mock/
│ │ │ │ │ │ │ └── MockSmsClient.java
│ │ │ │ │ │ ├── credentials/
│ │ │ │ │ │ │ ├── SmsCredentialModel.java
│ │ │ │ │ │ │ └── SmsCredentialProvider.java
│ │ │ │ │ │ └── updatephone/
│ │ │ │ │ │ └── UpdatePhoneNumberRequiredAction.java
│ │ │ │ │ ├── net/
│ │ │ │ │ │ └── NetworkAuthenticator.java
│ │ │ │ │ ├── opa/
│ │ │ │ │ │ ├── OpaAccessResponse.java
│ │ │ │ │ │ ├── OpaAuthenticator.java
│ │ │ │ │ │ ├── OpaCheckAccessAction.java
│ │ │ │ │ │ └── OpaClient.java
│ │ │ │ │ ├── passwordform/
│ │ │ │ │ │ └── FederationAwarePasswordForm.java
│ │ │ │ │ ├── trusteddevice/
│ │ │ │ │ │ ├── TrustedDeviceCookie.java
│ │ │ │ │ │ ├── TrustedDeviceName.java
│ │ │ │ │ │ ├── TrustedDeviceToken.java
│ │ │ │ │ │ ├── action/
│ │ │ │ │ │ │ ├── ManageTrustedDeviceAction.java
│ │ │ │ │ │ │ └── TrustedDeviceInfo.java
│ │ │ │ │ │ ├── auth/
│ │ │ │ │ │ │ └── TrustedDeviceAuthenticator.java
│ │ │ │ │ │ ├── credentials/
│ │ │ │ │ │ │ ├── TrustedDeviceCredentialInput.java
│ │ │ │ │ │ │ ├── TrustedDeviceCredentialModel.java
│ │ │ │ │ │ │ └── TrustedDeviceCredentialProvider.java
│ │ │ │ │ │ └── support/
│ │ │ │ │ │ └── UserAgentParser.java
│ │ │ │ │ ├── userpasswordform/
│ │ │ │ │ │ └── AcmeCaptchaUsernamePasswordForm.java
│ │ │ │ │ └── verifyemailcode/
│ │ │ │ │ └── VerifyEmailCodeAction.java
│ │ │ │ ├── authz/
│ │ │ │ │ ├── filter/
│ │ │ │ │ │ └── AcmeAccessFilter.java
│ │ │ │ │ └── policies/
│ │ │ │ │ └── AcmeImpersonationPolicyProvider.java
│ │ │ │ ├── config/
│ │ │ │ │ ├── ClientConfig.java
│ │ │ │ │ ├── ConfigAccessor.java
│ │ │ │ │ ├── MapConfig.java
│ │ │ │ │ └── RealmConfig.java
│ │ │ │ ├── consent/
│ │ │ │ │ ├── ConsentSelectionAction.java
│ │ │ │ │ ├── ScopeBean.java
│ │ │ │ │ ├── ScopeField.java
│ │ │ │ │ └── ScopeFieldBean.java
│ │ │ │ ├── context/
│ │ │ │ │ └── ContextSelectionAction.java
│ │ │ │ ├── email/
│ │ │ │ │ └── AcmeEmailSenderProvider.java
│ │ │ │ ├── endpoints/
│ │ │ │ │ ├── CorsUtils.java
│ │ │ │ │ ├── CustomAdminResourceProvider.java
│ │ │ │ │ ├── CustomResource.java
│ │ │ │ │ ├── CustomResourceProvider.java
│ │ │ │ │ ├── account/
│ │ │ │ │ │ └── AcmeAccountResource.java
│ │ │ │ │ ├── admin/
│ │ │ │ │ │ ├── AdminSettingsResource.java
│ │ │ │ │ │ ├── CustomAdminResource.java
│ │ │ │ │ │ └── UserProvisioningResource.java
│ │ │ │ │ ├── applications/
│ │ │ │ │ │ └── ApplicationsInfoResource.java
│ │ │ │ │ ├── branding/
│ │ │ │ │ │ └── BrandingResource.java
│ │ │ │ │ ├── credentials/
│ │ │ │ │ │ └── UserCredentialsInfoResource.java
│ │ │ │ │ ├── demo/
│ │ │ │ │ │ └── DemosResource.java
│ │ │ │ │ ├── idp/
│ │ │ │ │ │ └── IdpApplications.java
│ │ │ │ │ ├── migration/
│ │ │ │ │ │ ├── TokenMigrationResource.java
│ │ │ │ │ │ └── UserImportMigrationResource.java
│ │ │ │ │ ├── offline/
│ │ │ │ │ │ ├── OfflineSessionPropagationResource.java
│ │ │ │ │ │ ├── SessionPropagationActionToken.java
│ │ │ │ │ │ └── SessionPropagationActionTokenHandler.java
│ │ │ │ │ ├── profile/
│ │ │ │ │ │ ├── ProfileData.java
│ │ │ │ │ │ └── UserProfileResource.java
│ │ │ │ │ └── settings/
│ │ │ │ │ └── UserSettingsResource.java
│ │ │ │ ├── eventpublishing/
│ │ │ │ │ ├── AcmeEventPublisherEventListener.java
│ │ │ │ │ ├── EventPublisher.java
│ │ │ │ │ ├── NatsEventPublisher.java
│ │ │ │ │ └── NoopPublisher.java
│ │ │ │ ├── health/
│ │ │ │ │ ├── CustomHealthChecks.java
│ │ │ │ │ └── CustomReadinessCheck.java
│ │ │ │ ├── idp/
│ │ │ │ │ ├── azure/
│ │ │ │ │ │ ├── CustomAzureADGroupMapper.java
│ │ │ │ │ │ └── CustomEntraIdProfileMapper.java
│ │ │ │ │ ├── brokering/
│ │ │ │ │ │ └── RestrictBrokeredUserMapper.java
│ │ │ │ │ ├── linking/
│ │ │ │ │ │ └── AcmeIdpLinkAction.java
│ │ │ │ │ ├── oidc/
│ │ │ │ │ │ └── AcmeOidcIdentityProvider.java
│ │ │ │ │ └── social/
│ │ │ │ │ └── linkedin/
│ │ │ │ │ └── LinkedInUserProfileImportIdpMapper.java
│ │ │ │ ├── infinispan/
│ │ │ │ │ └── CustomInfinispanUserSessionProviderFactory.java
│ │ │ │ ├── jpa/
│ │ │ │ │ └── CustomQuarkusJpaConnectionProviderFactory.java
│ │ │ │ ├── metrics/
│ │ │ │ │ ├── KeycloakMetric.java
│ │ │ │ │ ├── KeycloakMetricAccessor.java
│ │ │ │ │ ├── KeycloakMetricStore.java
│ │ │ │ │ ├── KeycloakMetrics.java
│ │ │ │ │ ├── RealmMetricUpdater.java
│ │ │ │ │ ├── RealmMetricsUpdater.java
│ │ │ │ │ └── events/
│ │ │ │ │ ├── MetricEventListenerProvider.java
│ │ │ │ │ └── MetricEventRecorder.java
│ │ │ │ ├── migration/
│ │ │ │ │ └── acmecred/
│ │ │ │ │ ├── AcmeCredentialModel.java
│ │ │ │ │ ├── AcmeCredentialProvider.java
│ │ │ │ │ └── AcmePasswordValidator.java
│ │ │ │ ├── oauth/
│ │ │ │ │ ├── client/
│ │ │ │ │ │ └── OauthClientCredentialsTokenManager.java
│ │ │ │ │ └── tokenexchange/
│ │ │ │ │ ├── ApiKeyTokenExchangeProvider.java
│ │ │ │ │ ├── CustomTokenExchangeProvider.java
│ │ │ │ │ └── CustomV2TokenExchangeProvider.java
│ │ │ │ ├── oidc/
│ │ │ │ │ ├── ageinfo/
│ │ │ │ │ │ └── AgeInfoMapper.java
│ │ │ │ │ ├── authzenclaims/
│ │ │ │ │ │ └── AuthzenClaimMapper.java
│ │ │ │ │ ├── opaclaims/
│ │ │ │ │ │ └── OpaClaimMapper.java
│ │ │ │ │ ├── remoteclaims/
│ │ │ │ │ │ └── RemoteOidcMapper.java
│ │ │ │ │ ├── scopes/
│ │ │ │ │ │ └── OnlyGrantedScopesMapper.java
│ │ │ │ │ ├── userdata/
│ │ │ │ │ │ └── AcmeUserInfoMapper.java
│ │ │ │ │ └── wellknown/
│ │ │ │ │ └── AcmeOidcWellKnownProvider.java
│ │ │ │ ├── profile/
│ │ │ │ │ ├── AcmeUserAttributes.java
│ │ │ │ │ ├── emailupdate/
│ │ │ │ │ │ └── UpdateEmailRequiredAction.java
│ │ │ │ │ └── phonenumber/
│ │ │ │ │ └── AcmePhoneValidator.java
│ │ │ │ ├── registration/
│ │ │ │ │ ├── actiontokens/
│ │ │ │ │ │ └── AcmeExecuteActionsActionTokenHandler.java
│ │ │ │ │ └── formaction/
│ │ │ │ │ ├── CustomRegistrationUserCreation.java
│ │ │ │ │ └── WelcomeEmailFormAction.java
│ │ │ │ ├── saml/
│ │ │ │ │ ├── AcmeSamlAuthenticationPreprocessor.java
│ │ │ │ │ ├── brokering/
│ │ │ │ │ │ └── AcmeSamlRoleImporter.java
│ │ │ │ │ └── rolelist/
│ │ │ │ │ └── AcmeSamlRoleListMapper.java
│ │ │ │ ├── scheduling/
│ │ │ │ │ ├── ScheduledTaskProvider.java
│ │ │ │ │ ├── ScheduledTaskProviderFactory.java
│ │ │ │ │ ├── ScheduledTaskSpi.java
│ │ │ │ │ └── tasks/
│ │ │ │ │ └── AcmeScheduledTaskProvider.java
│ │ │ │ ├── security/
│ │ │ │ │ ├── filter/
│ │ │ │ │ │ └── IpAccessFilter.java
│ │ │ │ │ └── friendlycaptcha/
│ │ │ │ │ ├── FriendlyCaptcha.java
│ │ │ │ │ ├── FriendlyCaptchaClient.java
│ │ │ │ │ ├── FriendlyCaptchaConfig.java
│ │ │ │ │ └── FriendlyCaptchaFormAction.java
│ │ │ │ ├── support/
│ │ │ │ │ ├── AuthUtils.java
│ │ │ │ │ ├── ConfigUtils.java
│ │ │ │ │ ├── CookieHelper.java
│ │ │ │ │ ├── CookieUtils.java
│ │ │ │ │ ├── CredentialUtils.java
│ │ │ │ │ ├── LocaleUtils.java
│ │ │ │ │ ├── RealmUtils.java
│ │ │ │ │ ├── RequiredActionUtils.java
│ │ │ │ │ ├── ScopeUtils.java
│ │ │ │ │ ├── TokenUtils.java
│ │ │ │ │ ├── UserSessionUtils.java
│ │ │ │ │ └── UserUtils.java
│ │ │ │ ├── terms/
│ │ │ │ │ └── AcmeTermsAndConditionsAction.java
│ │ │ │ ├── themes/
│ │ │ │ │ └── login/
│ │ │ │ │ ├── AcmeFreeMarkerLoginFormsProvider.java
│ │ │ │ │ ├── AcmeLoginBean.java
│ │ │ │ │ └── AcmeUrlBean.java
│ │ │ │ └── userstorage/
│ │ │ │ ├── adhoc/
│ │ │ │ │ └── AdhocUserStorageProvider.java
│ │ │ │ ├── ldap/
│ │ │ │ │ ├── AcmeLDAPStorageProvider.java
│ │ │ │ │ └── AcmeReadonlyLDAPUserModelDelegate.java
│ │ │ │ └── remote/
│ │ │ │ ├── AcmeUserAdapter.java
│ │ │ │ ├── AcmeUserStorageProvider.java
│ │ │ │ └── accountclient/
│ │ │ │ ├── AccountClientOptions.java
│ │ │ │ ├── AcmeAccountClient.java
│ │ │ │ ├── AcmeUser.java
│ │ │ │ ├── SimpleAcmeAccountClient.java
│ │ │ │ ├── UserSearchInput.java
│ │ │ │ ├── UserSearchOutput.java
│ │ │ │ ├── VerifyCredentialsInput.java
│ │ │ │ └── VerifyCredentialsOutput.java
│ │ │ └── resources/
│ │ │ ├── META-INF/
│ │ │ │ └── keycloak-scripts.json
│ │ │ ├── ignore_default-persistence.xml
│ │ │ ├── my-script-authenticator.js
│ │ │ └── my-script-mapper.js
│ │ └── test/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── github/
│ │ │ └── thomasdarimont/
│ │ │ └── keycloak/
│ │ │ └── custom/
│ │ │ ├── BoostrapTest.java
│ │ │ ├── KeycloakEnvironment.java
│ │ │ ├── KeycloakIntegrationTest.java
│ │ │ └── KeycloakTestSupport.java
│ │ └── resources/
│ │ ├── log4j.properties
│ │ └── testcontainers.properties
│ ├── http-tests/
│ │ ├── advanced_oauth_par.http
│ │ ├── advanced_oauth_resources.http
│ │ ├── custom-token-migration.http
│ │ ├── custom_token_exchange.http
│ │ ├── dynamic-client-registration.http
│ │ ├── example-requests.http
│ │ ├── grant_type_client_credentials-requests.http
│ │ ├── grant_type_password-requests.http
│ │ ├── grant_type_refreshtoken-requests.http
│ │ ├── http-client.env.json
│ │ ├── implicit-flow-request.http
│ │ ├── keycloak-lightweight-token-requests.http
│ │ ├── oidc-endpoint-requests.http
│ │ ├── token_exchange.http
│ │ ├── token_exchange_api_gateway.http
│ │ ├── token_exchange_fed-identity-chaining.http
│ │ └── token_exchange_v2.http
│ ├── misc/
│ │ ├── custom-keycloak-server/
│ │ │ ├── pom.xml
│ │ │ ├── readme.md
│ │ │ └── src/
│ │ │ └── main/
│ │ │ ├── copy-to-keycloak/
│ │ │ │ └── conf/
│ │ │ │ └── quarkus.properties
│ │ │ ├── java/
│ │ │ │ └── demo/
│ │ │ │ └── events/
│ │ │ │ └── MyEventListener.java
│ │ │ └── resources/
│ │ │ ├── META-INF/
│ │ │ │ ├── keycloak-themes.json
│ │ │ │ └── keycloak.conf
│ │ │ └── theme/
│ │ │ └── custom/
│ │ │ └── login/
│ │ │ ├── messages/
│ │ │ │ └── messages_en.properties
│ │ │ ├── resources/
│ │ │ │ ├── css/
│ │ │ │ │ └── custom-login.css
│ │ │ │ └── js/
│ │ │ │ └── custom-login.js
│ │ │ └── theme.properties
│ │ └── snippets/
│ │ ├── create-keycloak-config-cli-client.txt
│ │ ├── jgroups-debugging.txt
│ │ ├── jmx-config-keycloakx.md
│ │ ├── jmx-config-wildfly.md
│ │ ├── jvm-settings.txt
│ │ ├── keycloakx-cli.md
│ │ ├── metrics-examples.txt
│ │ └── overlay-keycloak-endpoint-undertow.txt
│ ├── patches/
│ │ ├── keycloak-model-infinispan-patch/
│ │ │ ├── pom.xml
│ │ │ ├── readme.md
│ │ │ └── src/
│ │ │ └── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── keycloak/
│ │ │ ├── models/
│ │ │ │ └── sessions/
│ │ │ │ └── infinispan/
│ │ │ │ └── CacheDecorators.java
│ │ │ └── patch/
│ │ │ └── infinispan/
│ │ │ └── keymappers/
│ │ │ └── CustomDefaultTwoWayKey2StringMapper.java
│ │ ├── wildfly-clustering-infinispan-extension-patch/
│ │ │ ├── pom.xml
│ │ │ ├── readme.md
│ │ │ └── src/
│ │ │ └── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── jboss/
│ │ │ └── as/
│ │ │ └── clustering/
│ │ │ └── infinispan/
│ │ │ └── subsystem/
│ │ │ ├── InfinispanSubsystemXMLReader.java
│ │ │ ├── LocalDescriptions.properties
│ │ │ ├── RemoteStoreResourceDefinition.java
│ │ │ ├── RemoteStoreServiceConfigurator.java
│ │ │ ├── XMLAttribute.java
│ │ │ └── remote/
│ │ │ └── RemoteCacheContainerResourceDefinition.java
│ │ ├── wildfly-clustering-infinispan-extension-patch-25.0.x/
│ │ │ ├── pom.xml
│ │ │ └── src/
│ │ │ └── main/
│ │ │ └── java/
│ │ │ └── org/
│ │ │ └── jboss/
│ │ │ └── as/
│ │ │ └── clustering/
│ │ │ └── infinispan/
│ │ │ └── subsystem/
│ │ │ ├── InfinispanSubsystemXMLReader.java
│ │ │ ├── LocalDescriptions.properties
│ │ │ ├── RemoteStoreResourceDefinition.java
│ │ │ ├── RemoteStoreServiceConfigurator.java
│ │ │ └── remote/
│ │ │ └── RemoteCacheContainerResourceDefinition.java
│ │ └── wildfly-clustering-infinispan-extension-patch-26.0.x/
│ │ ├── pom.xml
│ │ └── src/
│ │ └── main/
│ │ └── java/
│ │ └── org/
│ │ └── jboss/
│ │ └── as/
│ │ └── clustering/
│ │ └── infinispan/
│ │ └── subsystem/
│ │ ├── InfinispanSubsystemXMLReader.java
│ │ ├── LocalDescriptions.properties
│ │ ├── RemoteStoreResourceDefinition.java
│ │ └── RemoteStoreServiceConfigurator.java
│ └── themes/
│ ├── acme-account.v2/
│ │ └── account/
│ │ ├── messages/
│ │ │ ├── messages_de.properties
│ │ │ └── messages_en.properties
│ │ ├── resources/
│ │ │ ├── content.json
│ │ │ └── css/
│ │ │ └── styles.css
│ │ └── theme.properties
│ ├── admin-custom/
│ │ └── admin/
│ │ ├── admin-settings.ftl
│ │ ├── resources/
│ │ │ └── js/
│ │ │ └── admin-settings.js
│ │ └── theme.properties
│ ├── apps/
│ │ └── login/
│ │ ├── login.ftl
│ │ ├── messages/
│ │ │ ├── messages_de.properties
│ │ │ └── messages_en.properties
│ │ ├── register.ftl
│ │ ├── resources/
│ │ │ ├── css/
│ │ │ │ └── custom-login.css
│ │ │ └── js/
│ │ │ └── custom-login.js
│ │ ├── terms.ftl
│ │ └── theme.properties
│ ├── custom/
│ │ └── login/
│ │ ├── messages/
│ │ │ └── messages_en.properties
│ │ ├── register.ftl
│ │ ├── resources/
│ │ │ ├── css/
│ │ │ │ └── custom-login.css
│ │ │ └── js/
│ │ │ └── custom-login.js
│ │ └── theme.properties
│ ├── internal/
│ │ ├── account/
│ │ │ ├── account.ftl
│ │ │ ├── messages/
│ │ │ │ ├── messages_de.properties
│ │ │ │ └── messages_en.properties
│ │ │ └── theme.properties
│ │ ├── email/
│ │ │ ├── html/
│ │ │ │ ├── acme-account-blocked.ftl
│ │ │ │ ├── acme-account-deletion-requested.ftl
│ │ │ │ ├── acme-account-updated.ftl
│ │ │ │ ├── acme-email-verification-with-code.ftl
│ │ │ │ ├── acme-magic-link.ftl
│ │ │ │ ├── acme-mfa-added.ftl
│ │ │ │ ├── acme-mfa-removed.ftl
│ │ │ │ ├── acme-passkey-added.ftl
│ │ │ │ ├── acme-passkey-removed.ftl
│ │ │ │ ├── acme-trusted-device-added.ftl
│ │ │ │ ├── acme-trusted-device-removed.ftl
│ │ │ │ ├── acme-welcome.ftl
│ │ │ │ ├── code-email.ftl
│ │ │ │ └── template.ftl
│ │ │ ├── messages/
│ │ │ │ ├── messages_de.properties
│ │ │ │ └── messages_en.properties
│ │ │ ├── text/
│ │ │ │ ├── acme-account-blocked.ftl
│ │ │ │ ├── acme-account-deletion-requested.ftl
│ │ │ │ ├── acme-account-updated.ftl
│ │ │ │ ├── acme-email-verification-with-code.ftl
│ │ │ │ ├── acme-magic-link.ftl
│ │ │ │ ├── acme-mfa-added.ftl
│ │ │ │ ├── acme-mfa-removed.ftl
│ │ │ │ ├── acme-passkey-added.ftl
│ │ │ │ ├── acme-passkey-removed.ftl
│ │ │ │ ├── acme-trusted-device-added.ftl
│ │ │ │ ├── acme-trusted-device-removed.ftl
│ │ │ │ ├── acme-welcome.ftl
│ │ │ │ ├── code-email.ftl
│ │ │ │ └── template.ftl
│ │ │ └── theme.properties
│ │ └── login/
│ │ ├── email-code-form.ftl
│ │ ├── login-confirm-cookie-form.ftl
│ │ ├── login-magic-link.ftl
│ │ ├── login-otp.ftl
│ │ ├── login-password.ftl
│ │ ├── login-select-mfa-method.ftl
│ │ ├── login-skippable-action.ftl
│ │ ├── login-sms.ftl
│ │ ├── login-username.ftl
│ │ ├── manage-trusted-device-form.ftl
│ │ ├── messages/
│ │ │ ├── messages_de.properties
│ │ │ └── messages_en.properties
│ │ ├── register.ftl
│ │ ├── resources/
│ │ │ ├── css/
│ │ │ │ └── custom-login.css
│ │ │ └── js/
│ │ │ └── custom-login.js
│ │ ├── select-consent-form.ftl
│ │ ├── theme.properties
│ │ ├── update-email-form.ftl
│ │ ├── update-phone-number-form.ftl
│ │ ├── verify-email-form.ftl
│ │ └── verify-phone-number-form.ftl
│ ├── internal-modern/
│ │ ├── account/
│ │ │ └── theme.properties
│ │ ├── email/
│ │ │ ├── messages/
│ │ │ │ ├── messages_de.properties
│ │ │ │ └── messages_en.properties
│ │ │ └── theme.properties
│ │ └── login/
│ │ ├── context-selection.ftl
│ │ ├── login-applications.ftl
│ │ ├── login-idp-selection.ftl
│ │ ├── login-password.ftl
│ │ ├── login-username.ftl
│ │ ├── login-verify-email.ftl
│ │ ├── login.ftl
│ │ ├── messages/
│ │ │ ├── messages_de.properties
│ │ │ └── messages_en.properties
│ │ ├── register.ftl
│ │ ├── resources/
│ │ │ ├── css/
│ │ │ │ └── custom-modern-login.css
│ │ │ └── js/
│ │ │ └── custom-modern-login.js
│ │ ├── select-authenticator.ftl
│ │ ├── template.ftl
│ │ └── theme.properties
│ ├── minimal/
│ │ └── login/
│ │ ├── resources/
│ │ │ ├── css/
│ │ │ │ └── custom-login.css
│ │ │ └── js/
│ │ │ └── custom-login.js
│ │ └── theme.properties
│ └── minimal-branding/
│ └── login/
│ ├── customizations.ftl
│ ├── info.ftl
│ ├── login-update-password.ftl
│ ├── resources/
│ │ ├── css/
│ │ │ └── custom-login.css
│ │ └── js/
│ │ └── custom-login.js
│ ├── template.ftl
│ └── theme.properties
├── keycloak.env
├── maven-settings.xml
├── pom.xml
├── readme.md
├── start.java
├── stop.java
└── tools/
├── kcadm/
│ └── readme.md
├── postman/
│ ├── acme.postman_collection.json
│ ├── acme.postman_environment_http.json
│ ├── acme.postman_environment_https.json
│ ├── acme.postman_globals.json
│ └── readme.md
├── session-generator/
│ ├── .gitignore
│ ├── .mvn/
│ │ └── wrapper/
│ │ ├── MavenWrapperDownloader.java
│ │ └── maven-wrapper.properties
│ ├── mvnw
│ ├── mvnw.cmd
│ ├── pom.xml
│ └── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/
│ │ │ └── github/
│ │ │ └── thomasdarimont/
│ │ │ └── keycloak/
│ │ │ └── tools/
│ │ │ └── sessiongenerator/
│ │ │ └── SessionGeneratorApplication.java
│ │ └── resources/
│ │ └── application.properties
│ └── test/
│ └── java/
│ └── com/
│ └── github/
│ └── thomasdarimont/
│ └── keycloak/
│ └── tools/
│ └── sessiongenerator/
│ └── SessionGeneratorApplicationTests.java
└── tcpdump/
├── Dockerfile
└── readme.md
Showing preview only (224K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2509 symbols across 362 files)
FILE: apps/account-svc/.mvn/wrapper/MavenWrapperDownloader.java
class MavenWrapperDownloader (line 30) | public final class MavenWrapperDownloader {
method main (line 35) | public static void main(String[] args) {
method downloadFileFromURL (line 59) | private static void downloadFileFromURL(URL wrapperUrl, Path wrapperJa...
method log (line 78) | private static void log(String msg) {
FILE: apps/account-svc/src/main/java/com/thomasdarimont/keycloak/training/accounts/User.java
class User (line 9) | @Data
method User (line 24) | public User(String id, String username, String password, String email,...
method getPassword (line 37) | @JsonIgnore
FILE: apps/account-svc/src/main/java/com/thomasdarimont/keycloak/training/accounts/UserRepository.java
class UserRepository (line 14) | @Singleton
method UserRepository (line 20) | public UserRepository() {
method newUser (line 30) | private static User newUser(String idSeed, String username, String pas...
method findAll (line 34) | public List<User> findAll() {
method count (line 39) | public int count() {
method findById (line 44) | public User findById(String id) {
method findByUsernameOrEmail (line 49) | public User findByUsernameOrEmail(String username) {
method getByUsername (line 54) | public Optional<User> getByUsername(String username) {
method getByEmail (line 59) | public Optional<User> getByEmail(String email) {
method findUsers (line 64) | List<User> findUsers(String query) {
method validatePassword (line 69) | public boolean validatePassword(String id, String password) {
method updatePassword (line 74) | public boolean updatePassword(String id, String password) {
method createUser (line 80) | public void createUser(User user) {
method updateUser (line 87) | public void updateUser(User user) {
method removeUser (line 96) | public boolean removeUser(String id) {
method search (line 101) | public List<User> search(String search, Integer firstResult, Integer m...
method searchForCount (line 106) | public int searchForCount(String search, Integer firstResult, Integer ...
method searchInternal (line 111) | private static Stream<User> searchInternal(String search, Integer firs...
FILE: apps/account-svc/src/main/java/com/thomasdarimont/keycloak/training/accounts/UserResource.java
class UserResource (line 17) | @JBossLog
method userList (line 26) | @GET
method userById (line 31) | @GET
method lookupUserByUsername (line 38) | @POST
method lookupUserByEmail (line 44) | @POST
method verifyCredentials (line 50) | @POST
method searchUsers (line 58) | @POST
method verify (line 72) | private VerifyCredentialsOutput verify(String userId, VerifyCredential...
class UserLookupInput (line 76) | @Data
class UserSearchInput (line 83) | @Data
type UserSearchOption (line 92) | public enum UserSearchOption {
class UserSearchOutput (line 99) | @Data
class VerifyCredentialsInput (line 107) | @Data
class VerifyCredentialsOutput (line 112) | @Data
FILE: apps/acme-webapp-saml-node-express/src/config.js
constant IDP_ISSUER (line 3) | const IDP_ISSUER = process.env.IDP_ISSUER || "https://id.acme.test:8443/...
constant PORT (line 4) | const PORT = process.env.PORT || 4723;
constant HOSTNAME (line 5) | const HOSTNAME = process.env.HOSTNAME || "apps.acme.test" + (PORT === 44...
constant SP_ISSUER (line 6) | const SP_ISSUER = process.env.SP_ISSUER || "acme-webapp-saml-node-expre...
constant TLS_CERT_FILE (line 7) | const TLS_CERT_FILE = process.env.TLS_CERT_FILE || '../../config/stage/d...
constant TLS_KEY_FILE (line 8) | const TLS_KEY_FILE = process.env.TLS_KEY_FILE || '../../config/stage/dev...
constant LOG_LEVEL (line 9) | const LOG_LEVEL = process.env.LOG_LEVEL || 'info';
constant LOG_FORMAT (line 10) | const LOG_FORMAT = process.env.LOG_FORMAT || 'json';
constant READINESS_PROBE_DELAY (line 12) | const READINESS_PROBE_DELAY = process.env.READINESS_PROBE_DELAY || 1000;
constant SESSION_SECRET (line 14) | const SESSION_SECRET = process.env.SECRET || 'keyboard cat';
constant SAML_SP_KEY (line 16) | let SAML_SP_KEY = process.env.SAML_SP_KEY || fs.readFileSync("sp.key.pem...
constant SAML_IDP_CERT (line 18) | let SAML_IDP_CERT = process.env.SAML_IDP_CERT;
FILE: apps/acme-webapp-saml-node-express/src/express.js
function createExpressApp (line 7) | function createExpressApp(config, LOG) {
function configureSession (line 23) | function configureSession(app, config) {
function configureSaml (line 34) | function configureSaml(app, config, LOG) {
function configureTemplateEngine (line 109) | function configureTemplateEngine(app, config) {
function configureRoutes (line 115) | function configureRoutes(app, config) {
FILE: apps/acme-webapp-saml-node-express/src/index.js
constant LOG (line 9) | const LOG = initLogging(config);
FILE: apps/acme-webapp-saml-node-express/src/logging.js
function initLogging (line 3) | function initLogging(config) {
FILE: apps/acme-webapp-saml-node-express/src/server.js
function createServer (line 7) | function createServer(app, config, LOG) {
function configureGracefulShutdown (line 27) | function configureGracefulShutdown(httpsServer, config, LOG) {
FILE: apps/backend-api-dnc/api/Controllers/UsersController.cs
class UsersController (line 6) | [ApiController]
method UsersController (line 15) | public UsersController(ILogger<UsersController> logger, IHttpContextAc...
method Me (line 21) | [Authorize]
FILE: apps/backend-api-dnc/api/JwtBearerOptions.cs
class JwtBearerOptions (line 6) | public class JwtBearerOptions
FILE: apps/backend-api-micronaut/.mvn/wrapper/MavenWrapperDownloader.java
class MavenWrapperDownloader (line 28) | public class MavenWrapperDownloader {
method main (line 55) | public static void main(String args[]) {
method downloadFileFromURL (line 104) | private static void downloadFileFromURL(String urlString, File destina...
FILE: apps/backend-api-micronaut/src/main/java/com/acme/backend/micronaut/Application.java
class Application (line 5) | public class Application {
method main (line 7) | public static void main(String[] args) {
FILE: apps/backend-api-micronaut/src/main/java/com/acme/backend/micronaut/api/UsersResource.java
class UsersResource (line 17) | @Secured(IS_AUTHENTICATED)
method me (line 23) | @Get("/me")
FILE: apps/backend-api-node-express/src/api.js
function createApiEndpoints (line 6) | function createApiEndpoints(app, config, LOG) {
FILE: apps/backend-api-node-express/src/config.js
constant ISSUER (line 1) | const ISSUER = process.env.ISSUER || "https://id.acme.test:8443/auth/rea...
constant PORT (line 2) | const PORT = process.env.PORT || 4743;
constant CORS_ALLOWED_ORIGINS (line 3) | const CORS_ALLOWED_ORIGINS = process.env.CORS_ALLOWED_ORIGINS || 'https:...
constant CORS_ALLOWED_METHODS (line 4) | const CORS_ALLOWED_METHODS = process.env.CORS_ALLOWED_METHODS || 'GET';
constant TLS_CERT (line 5) | const TLS_CERT = process.env.TLS_CERT || '../../config/stage/dev/tls/acm...
constant TLS_KEY (line 6) | const TLS_KEY = process.env.TLS_KEY || '../../config/stage/dev/tls/acme....
constant LOG_LEVEL (line 7) | const LOG_LEVEL = process.env.LOG_LEVEL || 'info';
constant LOG_FORMAT (line 8) | const LOG_FORMAT = process.env.LOG_FORMAT || 'json';
constant READINESS_PROBE_DELAY (line 10) | const READINESS_PROBE_DELAY = process.env.READINESS_PROBE_DELAY || 1000;
FILE: apps/backend-api-node-express/src/express.js
function createExpressApp (line 6) | function createExpressApp(config, LOG) {
function configureCors (line 19) | function configureCors(app, config, LOG) {
function configureJwtAuthorization (line 32) | function configureJwtAuthorization(app, config, LOG) {
FILE: apps/backend-api-node-express/src/index.js
constant LOG (line 10) | const LOG = initLogging(config);
FILE: apps/backend-api-node-express/src/logging.js
function initLogging (line 3) | function initLogging(config) {
FILE: apps/backend-api-node-express/src/server.js
function createServer (line 7) | function createServer(app, config, LOG) {
function configureGracefulShutdown (line 26) | function configureGracefulShutdown(httpsServer, config, LOG) {
FILE: apps/backend-api-quarkus/src/main/java/com/acme/backend/quarkus/users/UsersResource.java
class UsersResource (line 22) | @Path("/api/users")
method me (line 42) | @GET
method claims (line 62) | @GET
FILE: apps/backend-api-rust-actix/src/api/me_info.rs
type MeInfo (line 8) | struct MeInfo {
type ErrorInfo (line 15) | struct ErrorInfo {
function handle_me_info (line 20) | pub async fn handle_me_info(user: AuthenticatedUser<FoundClaims>) -> Htt...
FILE: apps/backend-api-rust-actix/src/config.rs
type Config (line 2) | pub struct Config {
method from_environment_with_defaults (line 12) | pub fn from_environment_with_defaults() -> Self {
FILE: apps/backend-api-rust-actix/src/main.rs
function main (line 11) | async fn main() -> std::io::Result<()> {
FILE: apps/backend-api-rust-actix/src/middleware/cors.rs
function create_cors_config (line 4) | pub fn create_cors_config(allowed_origin: String) -> Cors {
FILE: apps/backend-api-rust-actix/src/middleware/jwt_auth.rs
type FoundClaims (line 8) | pub struct FoundClaims {
method has_scope (line 21) | pub fn has_scope(&self, scope: &str) -> bool {
function create_oidc_jwt_validator (line 26) | pub async fn create_oidc_jwt_validator(issuer: String) -> OIDCValidatorC...
FILE: apps/backend-api-rust-actix/src/middleware/ssl.rs
function create_ssl_acceptor_builder (line 3) | pub fn create_ssl_acceptor_builder(cert_location: &str, key_location: &s...
FILE: apps/backend-api-rust-rocket/src/domain/user.rs
type User (line 1) | pub struct User {
FILE: apps/backend-api-rust-rocket/src/main.rs
type MeInfo (line 24) | pub struct MeInfo {
function options_me_info (line 31) | fn options_me_info() {}
function get_me_info (line 34) | fn get_me_info(user: User) -> Json<MeInfo> {
function main (line 47) | async fn main() -> Result<(), Box<dyn Error>> {
FILE: apps/backend-api-rust-rocket/src/middleware/auth/jwt/auth.rs
type CleanupFn (line 8) | type CleanupFn = Box<dyn Fn() + Send>;
type JwtAuth (line 10) | pub struct JwtAuth {
method new (line 24) | pub fn new() -> JwtAuth {
method verify (line 43) | pub fn verify(&self, token: &str) -> Option<TokenData<Claims>> {
method start_key_update (line 48) | fn start_key_update(&mut self) {
method drop (line 16) | fn drop(&mut self) {
method default (line 67) | fn default() -> Self {
FILE: apps/backend-api-rust-rocket/src/middleware/auth/jwt/claims.rs
type Claims (line 4) | pub type Claims = HashMap<String, serde_json::Value>;
FILE: apps/backend-api-rust-rocket/src/middleware/auth/jwt/config.rs
type JwtConfig (line 4) | pub struct JwtConfig {
function get_config (line 11) | pub fn get_config() -> JwtConfig {
FILE: apps/backend-api-rust-rocket/src/middleware/auth/jwt/get_max_age.rs
type MaxAgeParseError (line 5) | pub enum MaxAgeParseError {
function get_max_age (line 13) | pub fn get_max_age(response: &Response) -> Result<Duration, MaxAgeParseE...
function parse_max_age_value (line 23) | fn parse_max_age_value(cache_control_value: &str) -> Result<Duration, Ma...
function parse_cache_control_header (line 46) | fn parse_cache_control_header(header_value: &HeaderValue) -> Result<Dura...
FILE: apps/backend-api-rust-rocket/src/middleware/auth/jwt/jwks.rs
type KeyResponse (line 9) | struct KeyResponse {
type JwkKey (line 14) | pub struct JwkKey {
type JwkKeys (line 23) | pub struct JwkKeys {
constant FALLBACK_TIMEOUT (line 29) | const FALLBACK_TIMEOUT: Duration = Duration::from_secs(300);
function fetch_keys_for_config (line 31) | pub fn fetch_keys_for_config(config: &JwtConfig) -> Result<JwkKeys, Box<...
function fetch_jwks_keys (line 43) | pub fn fetch_jwks_keys() -> Result<JwkKeys, Box<dyn Error + Send>> {
FILE: apps/backend-api-rust-rocket/src/middleware/auth/jwt/verifier.rs
type VerificationError (line 10) | enum VerificationError {
type JwtVerifier (line 16) | pub struct JwtVerifier {
method new (line 30) | pub fn new(keys: Vec<JwkKey>) -> JwtVerifier {
method verify (line 37) | pub fn verify(&self, token: &str) -> Option<TokenData<Claims>> {
method set_keys (line 54) | pub fn set_keys(&mut self, keys: Vec<JwkKey>) {
method get_key (line 58) | fn get_key(&self, key_id: String) -> Option<&JwkKey> {
method decode_token_with_key (line 62) | fn decode_token_with_key(
function keys_to_map (line 21) | fn keys_to_map(keys: Vec<JwkKey>) -> HashMap<String, JwkKey> {
FILE: apps/backend-api-rust-rocket/src/middleware/auth/jwt_auth_request_guard.rs
type AuthError (line 11) | pub enum AuthError {
function get_token_from_header (line 18) | fn get_token_from_header(header: &str) -> Option<String> {
function verify_token (line 27) | fn verify_token(token: &str, auth: &JwtAuth) -> request::Outcome<User, A...
function parse_and_verify_auth_header (line 63) | fn parse_and_verify_auth_header(header: &str, auth: &JwtAuth) -> request...
type Error (line 74) | type Error = AuthError;
method from_request (line 76) | async fn from_request(request: &'r Request<'_>) -> request::Outcome<Self...
function test_extract_token (line 94) | fn test_extract_token() {
function test_extract_token_too_short (line 100) | fn test_extract_token_too_short() {
FILE: apps/backend-api-rust-rocket/src/middleware/cors/cors.rs
type Cors (line 8) | pub struct Cors;
method info (line 12) | fn info(&self) -> Info {
method on_response (line 19) | async fn on_response<'r>(&self, _request: &'r Request<'_>, response: &mu...
FILE: apps/backend-api-rust-rocket/src/middleware/logging/logging.rs
function init_logging (line 7) | pub fn init_logging() {
FILE: apps/backend-api-rust-rocket/src/middleware/mod.rs
function expect_env_var (line 8) | pub fn expect_env_var(name: &str, default: &str) -> String {
function expect_env_var (line 13) | pub fn expect_env_var(name: &str, _default: &str) -> String {
FILE: apps/backend-api-rust-rocket/src/support/scheduling/use_repeating_job.rs
type Delay (line 5) | type Delay = Duration;
type Cancel (line 6) | type Cancel = Box<dyn Fn() + Send>;
function use_repeating_job (line 10) | pub fn use_repeating_job<F>(job: F) -> Cancel
FILE: apps/backend-api-rust-rocket/tests/fetch_keys.rs
function assert_is_valid_key (line 5) | fn assert_is_valid_key(key: &JwkKey) {
function test_fetch_keys (line 14) | fn test_fetch_keys() {
FILE: apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/BackendApiSpringbootReactiveApp.java
class BackendApiSpringbootReactiveApp (line 6) | @SpringBootApplication
method main (line 9) | public static void main(String[] args) {
FILE: apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/config/AcmeServiceProperties.java
class AcmeServiceProperties (line 10) | @Getter
class KeycloakJwtProperties (line 22) | @Getter
FILE: apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/config/JwtSecurityConfig.java
class JwtSecurityConfig (line 28) | @Configuration
method jwtDecoder (line 38) | @Bean
method defaultTokenValidator (line 60) | @Bean
method keycloakJwtAuthenticationConverter (line 70) | @Bean
method keycloakGrantedAuthoritiesConverter (line 75) | @Bean
FILE: apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/config/MethodSecurityConfig.java
class MethodSecurityConfig (line 15) | @Configuration
method keycloakAuthoritiesMapper (line 20) | @Bean
FILE: apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/config/WebFluxConfig.java
class WebFluxConfig (line 8) | @Configuration
method addCorsMappings (line 12) | @Override
FILE: apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/config/WebFluxRoutes.java
class WebFluxRoutes (line 14) | @Configuration
method route (line 17) | @Bean
FILE: apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/config/WebSecurityConfig.java
class WebSecurityConfig (line 19) | @EnableWebFluxSecurity
method springSecurityFilterChain (line 35) | @Bean
FILE: apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/support/keycloak/KeycloakAudienceValidator.java
class KeycloakAudienceValidator (line 13) | @Component
method validate (line 19) | @Override
FILE: apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/support/keycloak/KeycloakGrantedAuthoritiesConverter.java
class KeycloakGrantedAuthoritiesConverter (line 24) | public class KeycloakGrantedAuthoritiesConverter implements Converter<Jw...
method KeycloakGrantedAuthoritiesConverter (line 32) | public KeycloakGrantedAuthoritiesConverter(String clientId, GrantedAut...
method convert (line 37) | @Override
method mapKeycloakRolesToAuthorities (line 53) | protected Collection<GrantedAuthority> mapKeycloakRolesToAuthorities(S...
method getRealmRolesFrom (line 68) | protected Set<String> getRealmRolesFrom(Jwt jwt) {
method getClientRolesFrom (line 85) | protected Set<String> getClientRolesFrom(Jwt jwt, String clientId) {
method normalizeRole (line 107) | private String normalizeRole(String role) {
FILE: apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/support/keycloak/KeycloakJwtAuthenticationConverter.java
class KeycloakJwtAuthenticationConverter (line 18) | @RequiredArgsConstructor
method KeycloakJwtAuthenticationConverter (line 23) | public KeycloakJwtAuthenticationConverter(Converter<Jwt, Collection<Gr...
method convert (line 27) | @Override
method getUsernameFrom (line 36) | protected String getUsernameFrom(Jwt jwt) {
FILE: apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/users/UserHandlers.java
class UserHandlers (line 12) | @Slf4j
method me (line 16) | public Mono<ServerResponse> me(ServerRequest request) {
FILE: apps/backend-api-springboot-reactive/src/test/java/com/acme/backend/springreactive/BackendApiSpringbootReactiveAppTests.java
class BackendApiSpringbootReactiveAppTests (line 6) | @SpringBootTest
method contextLoads (line 9) | @Test
FILE: apps/backend-api-springboot/.mvn/wrapper/MavenWrapperDownloader.java
class MavenWrapperDownloader (line 21) | public class MavenWrapperDownloader {
method main (line 48) | public static void main(String args[]) {
method downloadFileFromURL (line 97) | private static void downloadFileFromURL(String urlString, File destina...
FILE: apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/BackendApiSpringbootApp.java
class BackendApiSpringbootApp (line 7) | @SpringBootApplication
method main (line 11) | public static void main(String[] args) {
FILE: apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/config/AcmeServiceProperties.java
class AcmeServiceProperties (line 10) | @Getter
class KeycloakJwtProperties (line 22) | @Getter
FILE: apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/config/JwtSecurityConfig.java
class JwtSecurityConfig (line 28) | @Configuration
method jwtDecoder (line 38) | @Bean
method defaultTokenValidator (line 60) | @Bean
method keycloakJwtAuthenticationConverter (line 70) | @Bean
method keycloakGrantedAuthoritiesConverter (line 75) | @Bean
FILE: apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/config/MethodSecurityConfig.java
class MethodSecurityConfig (line 20) | @Configuration
method createExpressionHandler (line 29) | @Override
method keycloakAuthoritiesMapper (line 39) | @Bean
FILE: apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/config/WebSecurityConfig.java
class WebSecurityConfig (line 22) | @Configuration
method filterChain (line 41) | @Bean
method accessController (line 62) | @Bean
method configureCors (line 72) | protected void configureCors(CorsConfigurer<HttpSecurity> cors) {
FILE: apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/support/access/AccessController.java
class AccessController (line 12) | @Slf4j
method checkAccess (line 15) | public boolean checkAccess() {
FILE: apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakAudienceValidator.java
class KeycloakAudienceValidator (line 13) | @Component
method validate (line 19) | @Override
FILE: apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakGrantedAuthoritiesConverter.java
class KeycloakGrantedAuthoritiesConverter (line 24) | public class KeycloakGrantedAuthoritiesConverter implements Converter<Jw...
method KeycloakGrantedAuthoritiesConverter (line 32) | public KeycloakGrantedAuthoritiesConverter(String clientId, GrantedAut...
method convert (line 37) | @Override
method mapKeycloakRolesToAuthorities (line 53) | protected Collection<GrantedAuthority> mapKeycloakRolesToAuthorities(S...
method getRealmRolesFrom (line 68) | protected Set<String> getRealmRolesFrom(Jwt jwt) {
method getClientRolesFrom (line 85) | protected Set<String> getClientRolesFrom(Jwt jwt, String clientId) {
method normalizeRole (line 107) | private String normalizeRole(String role) {
FILE: apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakJwtAuthenticationConverter.java
class KeycloakJwtAuthenticationConverter (line 17) | @RequiredArgsConstructor
method KeycloakJwtAuthenticationConverter (line 22) | public KeycloakJwtAuthenticationConverter(Converter<Jwt, Collection<Gr...
method convert (line 26) | @Override
method getUsernameFrom (line 35) | protected String getUsernameFrom(Jwt jwt) {
FILE: apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/support/permissions/DefaultPermissionEvaluator.java
class DefaultPermissionEvaluator (line 16) | @Slf4j
method hasPermission (line 21) | @Override
method hasPermission (line 29) | @Override
FILE: apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/support/permissions/DomainObjectReference.java
class DomainObjectReference (line 8) | @Data
FILE: apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/web/UsersController.java
class UsersController (line 15) | @Slf4j
method me (line 20) | @GetMapping("/me")
FILE: apps/backend-api-springboot/src/test/java/com/acme/backend/springboot/users/BackendApiSpringbootAppTests.java
class BackendApiSpringbootAppTests (line 6) | @SpringBootTest
method contextLoads (line 9) | @Test
FILE: apps/backend-api-springboot3/.mvn/wrapper/MavenWrapperDownloader.java
class MavenWrapperDownloader (line 21) | public class MavenWrapperDownloader {
method main (line 48) | public static void main(String args[]) {
method downloadFileFromURL (line 97) | private static void downloadFileFromURL(String urlString, File destina...
FILE: apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/BackendApiSpringboot3App.java
class BackendApiSpringboot3App (line 7) | @SpringBootApplication
method main (line 11) | public static void main(String[] args) {
FILE: apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/AcmeServiceProperties.java
class AcmeServiceProperties (line 10) | @Getter
class KeycloakJwtProperties (line 22) | @Getter
FILE: apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/JwtSecurityConfig.java
class JwtSecurityConfig (line 28) | @Configuration
method jwtDecoder (line 38) | @Bean
method defaultTokenValidator (line 60) | @Bean
method keycloakJwtAuthenticationConverter (line 70) | @Bean
method keycloakGrantedAuthoritiesConverter (line 75) | @Bean
FILE: apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/MethodSecurityConfig.java
class MethodSecurityConfig (line 19) | @Configuration
method customMethodSecurityExpressionHandler (line 28) | @Bean
method keycloakAuthoritiesMapper (line 37) | @Bean
FILE: apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/WebSecurityConfig.java
class WebSecurityConfig (line 22) | @Configuration
method filterChain (line 41) | @Bean
method accessController (line 64) | @Bean
method configureCors (line 74) | protected void configureCors(CorsConfigurer<HttpSecurity> cors) {
FILE: apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/access/AccessController.java
class AccessController (line 13) | @Slf4j
method checkAccess (line 19) | public static AuthorizationDecision checkAccess(Supplier<Authenticatio...
FILE: apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakAudienceValidator.java
class KeycloakAudienceValidator (line 13) | @Component
method validate (line 19) | @Override
FILE: apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakGrantedAuthoritiesConverter.java
class KeycloakGrantedAuthoritiesConverter (line 24) | public class KeycloakGrantedAuthoritiesConverter implements Converter<Jw...
method KeycloakGrantedAuthoritiesConverter (line 32) | public KeycloakGrantedAuthoritiesConverter(String clientId, GrantedAut...
method convert (line 37) | @Override
method mapKeycloakRolesToAuthorities (line 53) | protected Collection<GrantedAuthority> mapKeycloakRolesToAuthorities(S...
method getRealmRolesFrom (line 68) | protected Set<String> getRealmRolesFrom(Jwt jwt) {
method getClientRolesFrom (line 85) | protected Set<String> getClientRolesFrom(Jwt jwt, String clientId) {
method normalizeRole (line 107) | private String normalizeRole(String role) {
FILE: apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakJwtAuthenticationConverter.java
class KeycloakJwtAuthenticationConverter (line 17) | @RequiredArgsConstructor
method KeycloakJwtAuthenticationConverter (line 22) | public KeycloakJwtAuthenticationConverter(Converter<Jwt, Collection<Gr...
method convert (line 26) | @Override
method getUsernameFrom (line 35) | protected String getUsernameFrom(Jwt jwt) {
FILE: apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/permissions/DefaultPermissionEvaluator.java
class DefaultPermissionEvaluator (line 16) | @Slf4j
method hasPermission (line 21) | @Override
method hasPermission (line 29) | @Override
FILE: apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/permissions/DomainObjectReference.java
class DomainObjectReference (line 8) | @Data
FILE: apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/web/UsersController.java
class UsersController (line 14) | @Slf4j
method me (line 19) | @GetMapping("/me")
FILE: apps/backend-api-springboot3/src/test/java/com/acme/backend/springboot/users/BackendApiSpringboot3AppTests.java
class BackendApiSpringboot3AppTests (line 6) | @SpringBootTest
method contextLoads (line 9) | @Test
FILE: apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/BffApp.java
class BffApp (line 6) | @SpringBootApplication
method main (line 9) | public static void main(String[] args) {
FILE: apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/api/UsersResource.java
class UsersResource (line 16) | @RestController
method UsersResource (line 22) | public UsersResource(@Qualifier("oauth") RestTemplate oauthRestTemplat...
method userInfo (line 26) | @GetMapping("/me")
method getUserInfoFromAuthority (line 33) | private Map<String, Object> getUserInfoFromAuthority(Authentication au...
method getUserInfoFromRemote (line 43) | private UserInfo getUserInfoFromRemote() {
class UserInfo (line 47) | static class UserInfo extends LinkedHashMap<String, Object> {
FILE: apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/config/OAuth2RestTemplateConfig.java
class OAuth2RestTemplateConfig (line 11) | @Configuration
method oauthRestTemplate (line 20) | @Bean
FILE: apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/config/SessionConfig.java
class SessionConfig (line 9) | @Configuration
method connectionFactory (line 13) | @Bean
FILE: apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/config/WebSecurityConfig.java
class WebSecurityConfig (line 23) | @Configuration
method filterChain (line 29) | @Bean
method authorizationRequestRepository (line 65) | @Bean
method userAuthoritiesMapper (line 70) | private GrantedAuthoritiesMapper userAuthoritiesMapper() {
FILE: apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/config/keycloak/KeycloakLogoutHandler.java
class KeycloakLogoutHandler (line 13) | @Slf4j
method logout (line 17) | @Override
method generateAppUri (line 40) | private String generateAppUri(HttpServletRequest request) {
method createKeycloakLogoutUrl (line 50) | private String createKeycloakLogoutUrl(String issuerUri, String idToke...
FILE: apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/oauth/TokenAccessor.java
class TokenAccessor (line 22) | @Slf4j
method getAccessTokenForCurrentUser (line 37) | public OAuth2AccessToken getAccessTokenForCurrentUser() {
method getAccessToken (line 41) | public OAuth2AccessToken getAccessToken(Authentication auth) {
method getRefreshToken (line 61) | public OAuth2RefreshToken getRefreshToken(Authentication auth) {
method isAccessTokenStillValid (line 70) | private boolean isAccessTokenStillValid(OAuth2AccessToken accessToken) {
method getOAuth2AuthorizedClient (line 82) | private OAuth2AuthorizedClient getOAuth2AuthorizedClient(Authenticatio...
FILE: apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/oauth/TokenIntrospector.java
class TokenIntrospector (line 19) | @Component
method introspectToken (line 27) | public IntrospectionResult introspectToken(Authentication auth) {
class IntrospectionResult (line 65) | @Data
method setDataEntry (line 72) | @JsonAnySetter
FILE: apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/oauth/TokenRefresher.java
class TokenRefresher (line 29) | @Slf4j
method refreshTokens (line 36) | public OAuth2AccessToken refreshTokens(OAuth2AuthorizedClient client) {
class AccessTokenResponse (line 90) | @Data
method setMetadata (line 105) | @JsonAnySetter
FILE: apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/web/UiResource.java
class UiResource (line 8) | @Controller
method index (line 12) | @GetMapping("/")
FILE: apps/bff-springboot/src/main/resources/static/app/app.js
function qs (line 3) | function qs(selector) {
function qsa (line 7) | function qsa(selector) {
function callApi (line 11) | function callApi(url, requestOptions, onError) {
FILE: apps/bff-springboot3/src/main/java/com/github/thomasdarimont/apps/bff3/Bff3App.java
class Bff3App (line 6) | @SpringBootApplication
method main (line 9) | public static void main(String[] args) {
FILE: apps/bff-springboot3/src/main/java/com/github/thomasdarimont/apps/bff3/api/UsersResource.java
class UsersResource (line 17) | @RestController
method UsersResource (line 23) | public UsersResource(@Qualifier("oauth") RestTemplate oauthRestTemplat...
method userInfo (line 27) | @GetMapping("/me")
method getUserInfoFromAuthority (line 34) | private Map<String, Object> getUserInfoFromAuthority(Authentication au...
method getUserInfoFromRemote (line 44) | private UserInfo getUserInfoFromRemote(Authentication auth) {
class UserInfo (line 51) | static class UserInfo extends LinkedHashMap<String, Object> {
FILE: apps/bff-springboot3/src/main/java/com/github/thomasdarimont/apps/bff3/config/OAuth2RestTemplateConfig.java
class OAuth2RestTemplateConfig (line 11) | @Configuration
method oauthRestTemplate (line 20) | @Bean
FILE: apps/bff-springboot3/src/main/java/com/github/thomasdarimont/apps/bff3/config/SessionConfig.java
class SessionConfig (line 9) | @Configuration
method connectionFactory (line 13) | @Bean
FILE: apps/bff-springboot3/src/main/java/com/github/thomasdarimont/apps/bff3/config/WebSecurityConfig.java
class WebSecurityConfig (line 33) | @Configuration
method filterChain (line 39) | @Bean
method authorizationRequestRepository (line 94) | @Bean
method authorizedClientRepository (line 99) | @Bean
method oAuth2AuthorizedClientService (line 104) | @Bean
method userAuthoritiesMapper (line 112) | private GrantedAuthoritiesMapper userAuthoritiesMapper() {
FILE: apps/bff-springboot3/src/main/java/com/github/thomasdarimont/apps/bff3/config/keycloak/KeycloakLogoutHandler.java
class KeycloakLogoutHandler (line 14) | @Slf4j
method logout (line 18) | @Override
method generateAppUri (line 41) | private String generateAppUri(HttpServletRequest request) {
method createKeycloakLogoutUrl (line 51) | private String createKeycloakLogoutUrl(String issuerUri, String idToke...
FILE: apps/bff-springboot3/src/main/java/com/github/thomasdarimont/apps/bff3/oauth/TokenAccessor.java
class TokenAccessor (line 22) | @Slf4j
method TokenAccessor (line 32) | public TokenAccessor(OAuth2AuthorizedClientService authorizedClientSer...
method getAccessTokenForCurrentUser (line 41) | public OAuth2AccessToken getAccessTokenForCurrentUser() {
method getAccessToken (line 45) | public OAuth2AccessToken getAccessToken(Authentication auth) {
method getRefreshToken (line 65) | public OAuth2RefreshToken getRefreshToken(Authentication auth) {
method isAccessTokenStillValid (line 74) | private boolean isAccessTokenStillValid(OAuth2AccessToken accessToken) {
method getOAuth2AuthorizedClient (line 86) | private OAuth2AuthorizedClient getOAuth2AuthorizedClient(Authenticatio...
FILE: apps/bff-springboot3/src/main/java/com/github/thomasdarimont/apps/bff3/oauth/TokenIntrospector.java
class TokenIntrospector (line 21) | @Component
method introspectToken (line 29) | public IntrospectionResult introspectToken(Authentication auth, HttpSe...
class IntrospectionResult (line 68) | @Data
method setDataEntry (line 75) | @JsonAnySetter
FILE: apps/bff-springboot3/src/main/java/com/github/thomasdarimont/apps/bff3/oauth/TokenRefresher.java
class TokenRefresher (line 28) | @Slf4j
method TokenRefresher (line 34) | public TokenRefresher(OAuth2AuthorizedClientService authorizedClientSe...
method refreshTokens (line 38) | public OAuth2AccessToken refreshTokens(OAuth2AuthorizedClient client) {
class AccessTokenResponse (line 93) | @Data
method setMetadata (line 108) | @JsonAnySetter
FILE: apps/bff-springboot3/src/main/java/com/github/thomasdarimont/apps/bff3/support/HttpServletRequestUtils.java
class HttpServletRequestUtils (line 10) | public class HttpServletRequestUtils {
method getCurrentHttpServletRequest (line 12) | public static Optional<HttpServletRequest> getCurrentHttpServletReques...
method getCurrentHttpSession (line 17) | public static Optional<HttpSession> getCurrentHttpSession(boolean crea...
FILE: apps/bff-springboot3/src/main/java/com/github/thomasdarimont/apps/bff3/support/HttpSessionOAuth2AuthorizedClientService.java
class HttpSessionOAuth2AuthorizedClientService (line 8) | @RequiredArgsConstructor
method loadAuthorizedClient (line 11) | @Override
method saveAuthorizedClient (line 19) | @Override
method removeAuthorizedClient (line 26) | @Override
FILE: apps/bff-springboot3/src/main/java/com/github/thomasdarimont/apps/bff3/web/AuthResource.java
class AuthResource (line 19) | @RestController
method checkSession (line 27) | @GetMapping("/check-session")
class IntrospectionResponse (line 41) | @Data
method setDataEntry (line 48) | @JsonAnySetter
FILE: apps/bff-springboot3/src/main/java/com/github/thomasdarimont/apps/bff3/web/UiResource.java
class UiResource (line 8) | @Controller
method index (line 12) | @GetMapping("/")
FILE: apps/bff-springboot3/src/main/resources/static/app/app.js
function qs (line 3) | function qs(selector) {
function qsa (line 7) | function qsa(selector) {
function callApi (line 11) | function callApi(url, requestOptions, onError) {
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/WebAppSpringBoot.java
class WebAppSpringBoot (line 6) | @SpringBootApplication
method main (line 9) | public static void main(String[] args) {
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/config/KeycloakWebClientConfig.java
class KeycloakWebClientConfig (line 16) | @Configuration
method keycloakWebClient (line 19) | @Bean
method errorHandler (line 40) | public static ExchangeFilterFunction errorHandler() {
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/config/OidcUserServiceConfig.java
class OidcUserServiceConfig (line 7) | @Configuration
method keycloakUserService (line 10) | @Bean
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/config/WebSecurityConfig.java
class WebSecurityConfig (line 24) | @Configuration
method filterChain (line 30) | @Bean
method authorizationRequestRepository (line 70) | @Bean
method userAuthoritiesMapper (line 75) | private GrantedAuthoritiesMapper userAuthoritiesMapper() {
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/domain/ApplicationEntry.java
class ApplicationEntry (line 5) | @Data
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/domain/CredentialEntry.java
class CredentialEntry (line 5) | @Data
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/domain/SettingEntry.java
class SettingEntry (line 5) | @Data
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/domain/UserProfile.java
class UserProfile (line 5) | @Data
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/OAuth2AuthorizedClientAccessor.java
class OAuth2AuthorizedClientAccessor (line 12) | @Component
method getOAuth2AuthorizedClient (line 21) | public OAuth2AuthorizedClient getOAuth2AuthorizedClient(Authentication...
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/TokenAccessor.java
class TokenAccessor (line 12) | @Component
method getAccessTokenForCurrentUser (line 18) | public OAuth2AccessToken getAccessTokenForCurrentUser() {
method getAccessToken (line 22) | public OAuth2AccessToken getAccessToken(Authentication auth) {
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/TokenIntrospector.java
class TokenIntrospector (line 20) | @Component
method introspectToken (line 28) | public IntrospectionResult introspectToken(Authentication auth) {
class IntrospectionResult (line 66) | @Data
method setDataEntry (line 73) | @JsonAnySetter
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/keycloakclient/DefaultKeycloakClient.java
class DefaultKeycloakClient (line 22) | @Service
method DefaultKeycloakClient (line 41) | public DefaultKeycloakClient(@Qualifier("keycloakWebClient") WebClient...
method introspect (line 58) | @Override
method userInfo (line 75) | @Override
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/keycloakclient/KeycloakClient.java
type KeycloakClient (line 6) | public interface KeycloakClient {
method introspect (line 8) | KeycloakIntrospectResponse introspect(String token);
method userInfo (line 10) | KeycloakUserInfo userInfo(OAuth2AuthorizedClient authorizedClient, Oid...
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/keycloakclient/KeycloakIntrospectResponse.java
class KeycloakIntrospectResponse (line 8) | @Data
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/keycloakclient/KeycloakServiceException.java
class KeycloakServiceException (line 5) | @Data
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/keycloakclient/KeycloakUserInfo.java
class KeycloakUserInfo (line 7) | @Data
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/security/KeycloakLogoutHandler.java
class KeycloakLogoutHandler (line 13) | @Slf4j
method logout (line 17) | @Override
method generateAppUri (line 40) | private String generateAppUri(HttpServletRequest request) {
method createKeycloakLogoutUrl (line 50) | private String createKeycloakLogoutUrl(String issuerUri, String idToke...
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/web/AuthController.java
class AuthController (line 25) | @RestController
method register (line 42) | @GetMapping("/auth/register")
method checkSession (line 61) | @GetMapping("/auth/check-session")
class IntrospectionResponse (line 74) | @Data
method setDataEntry (line 81) | @JsonAnySetter
FILE: apps/frontend-webapp-springboot/src/main/java/com/github/thomasdarimont/keycloak/webapp/web/UiController.java
class UiController (line 21) | @Controller
method showIndex (line 29) | @GetMapping("/")
method showProfile (line 34) | @GetMapping("/profile")
method buildUserProfile (line 50) | private UserProfile buildUserProfile(OAuth2AuthorizedClient oAuth2Auth...
method showSettings (line 61) | @GetMapping("/settings")
method showSecurity (line 87) | @GetMapping("/security")
method showApplications (line 113) | @GetMapping("/applications")
FILE: apps/frontend-webapp-springboot/src/test/java/com/github/thomasdarimont/keycloak/cac/WebApplicationTestsSpringBoot.java
class WebApplicationTestsSpringBoot (line 6) | @SpringBootTest
method contextLoads (line 9) | @Test
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/WebAppSpringBoot3.java
class WebAppSpringBoot3 (line 6) | @SpringBootApplication
method main (line 9) | public static void main(String[] args) {
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/config/KeycloakWebClientConfig.java
class KeycloakWebClientConfig (line 25) | @Configuration
method keycloakWebClient (line 28) | @Bean
class OAuth2ClientInterceptor (line 46) | public static class OAuth2ClientInterceptor implements ClientHttpReque...
method OAuth2ClientInterceptor (line 51) | public OAuth2ClientInterceptor(OAuth2AuthorizedClientManager manager...
method intercept (line 56) | @Override
method initialize (line 62) | @Override
method getBearerToken (line 67) | private String getBearerToken() {
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/config/OidcUserServiceConfig.java
class OidcUserServiceConfig (line 7) | @Configuration
method keycloakUserService (line 10) | @Bean
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/config/WebSecurityConfig.java
class WebSecurityConfig (line 37) | @Slf4j
method filterChain (line 44) | @Bean
method customizeTokenEndpointRequest (line 81) | private static void customizeTokenEndpointRequest(OAuth2LoginConfigure...
method createCustomAccessTokenResponseClientNew (line 92) | private static OAuth2AccessTokenResponseClient<OAuth2AuthorizationCode...
method createCustomAccessTokenResponseClientOld (line 101) | private static OAuth2AccessTokenResponseClient<OAuth2AuthorizationCode...
method authorizationRequestRepository (line 124) | @Bean
method authorizedClientRepository (line 129) | @Bean
method oAuth2AuthorizedClientService (line 134) | @Bean
method userAuthoritiesMapper (line 140) | private GrantedAuthoritiesMapper userAuthoritiesMapper() {
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/domain/ApplicationEntry.java
class ApplicationEntry (line 5) | @Data
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/domain/CredentialEntry.java
class CredentialEntry (line 5) | @Data
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/domain/SettingEntry.java
class SettingEntry (line 5) | @Data
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/domain/UserProfile.java
class UserProfile (line 5) | @Data
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/HttpServletRequestUtils.java
class HttpServletRequestUtils (line 11) | public class HttpServletRequestUtils {
method getCurrentHttpServletRequest (line 13) | public static Optional<HttpServletRequest> getCurrentHttpServletReques...
method getCurrentHttpServletResponse (line 18) | public static Optional<HttpServletResponse> getCurrentHttpServletRespo...
method getCurrentHttpSession (line 23) | public static Optional<HttpSession> getCurrentHttpSession(boolean crea...
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/HttpSessionOAuth2AuthorizedClientService.java
class HttpSessionOAuth2AuthorizedClientService (line 13) | @RequiredArgsConstructor
method loadAuthorizedClient (line 18) | @Override
method saveAuthorizedClient (line 24) | @Override
method removeAuthorizedClient (line 31) | @Override
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/TokenAccessor.java
class TokenAccessor (line 12) | @Component
method getAccessTokenForCurrentUser (line 18) | public OAuth2AccessToken getAccessTokenForCurrentUser() {
method getAccessToken (line 22) | public OAuth2AccessToken getAccessToken(Authentication auth) {
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/TokenIntrospector.java
class TokenIntrospector (line 20) | @Component
method introspectToken (line 28) | public IntrospectionResult introspectToken(Authentication auth) {
class IntrospectionResult (line 66) | @Data
method setDataEntry (line 73) | @JsonAnySetter
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/keycloakclient/DefaultKeycloakClient.java
class DefaultKeycloakClient (line 21) | @Service
method DefaultKeycloakClient (line 40) | public DefaultKeycloakClient(@Qualifier("keycloakRestClient") RestClie...
method introspect (line 57) | @Override
method userInfo (line 73) | @Override
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/keycloakclient/KeycloakClient.java
type KeycloakClient (line 6) | public interface KeycloakClient {
method introspect (line 8) | KeycloakIntrospectResponse introspect(String token);
method userInfo (line 10) | KeycloakUserInfo userInfo(OAuth2AuthorizedClient authorizedClient, Oid...
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/keycloakclient/KeycloakIntrospectResponse.java
class KeycloakIntrospectResponse (line 8) | @Data
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/keycloakclient/KeycloakServiceException.java
class KeycloakServiceException (line 5) | @Data
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/keycloakclient/KeycloakUserInfo.java
class KeycloakUserInfo (line 7) | @Data
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/support/security/KeycloakLogoutHandler.java
class KeycloakLogoutHandler (line 14) | @Slf4j
method logout (line 18) | @Override
method generateAppUri (line 41) | private String generateAppUri(HttpServletRequest request) {
method createKeycloakLogoutUrl (line 51) | private String createKeycloakLogoutUrl(String issuerUri, String idToke...
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/web/AuthController.java
class AuthController (line 25) | @RestController
method register (line 42) | @GetMapping("/auth/register")
method checkSession (line 61) | @GetMapping("/auth/check-session")
class IntrospectionResponse (line 74) | @Data
method setDataEntry (line 81) | @JsonAnySetter
FILE: apps/frontend-webapp-springboot3/src/main/java/com/github/thomasdarimont/keycloak/webapp/web/UiController.java
class UiController (line 21) | @Controller
method showIndex (line 27) | @GetMapping("/")
method showProfile (line 33) | @GetMapping("/profile")
method showSettings (line 51) | @GetMapping("/settings")
method showSecurity (line 71) | @GetMapping("/security")
method showApplications (line 91) | @GetMapping("/applications")
FILE: apps/frontend-webapp-springboot3/src/test/java/com/github/thomasdarimont/keycloak/cac/WebApplicationTestsSpringBoot.java
class WebApplicationTestsSpringBoot (line 6) | @SpringBootTest
method contextLoads (line 9) | @Test
FILE: apps/java-opa-embedded/src/main/java/demo/OpaEmbeddedDemo.java
class OpaEmbeddedDemo (line 16) | public class OpaEmbeddedDemo {
method main (line 18) | public static void main(String[] args) throws Exception {
FILE: apps/jwt-client-authentication/src/main/java/demo/jwtclientauth/JwtClientAuthApp.java
class JwtClientAuthApp (line 48) | @Slf4j
method main (line 52) | public static void main(String[] args) {
method cli (line 56) | @Bean
method requestToken (line 110) | private Map<String, Object> requestToken(String issuer, String clientA...
method requestPAR (line 128) | private String requestPAR(String issuer, String clientId, String nonce...
method generateClientAssertionSignedWithPrivateKey (line 150) | private String generateClientAssertionSignedWithPrivateKey(Map<String,...
method generateClientAssertionSignedWithClientSecret (line 178) | private String generateClientAssertionSignedWithClientSecret(Map<Strin...
method generateClientSignedJwtToken (line 201) | private String generateClientSignedJwtToken(String clientId, String is...
method parseCertificate (line 215) | private X509Certificate parseCertificate(String path) {
method createKeyThumbprint (line 224) | private static Base64URL createKeyThumbprint(X509Certificate cert, Str...
method readPrivateKeyFile (line 233) | static RSAPrivateKey readPrivateKeyFile(String path) {
FILE: apps/oauth2-proxy/app/main.go
function greet (line 10) | func greet(w http.ResponseWriter, r *http.Request) {
function main (line 63) | func main() {
FILE: apps/offline-session-client/src/main/java/demo/OfflineSessionClient.java
class OfflineSessionClient (line 49) | @Slf4j
method main (line 53) | public static void main(String[] args) {
method clr (line 57) | @Bean
class OAuthInfo (line 95) | @Builder
method getUserInfoUrl (line 111) | public String getUserInfoUrl() {
method getTokenUrl (line 115) | public String getTokenUrl() {
method getLogoutUrl (line 119) | public String getLogoutUrl() {
class OAuthClient (line 124) | @Slf4j
method loadOfflineToken (line 138) | public boolean loadOfflineToken(boolean obtainIfMissing, String offl...
method fetchUserInfo (line 200) | public UserInfoResponse fetchUserInfo() {
method doRefreshToken (line 212) | private boolean doRefreshToken(String refreshToken) {
method sendOfflineTokenRequest (line 238) | private boolean sendOfflineTokenRequest() {
method ensureTokenValidSeconds (line 264) | public void ensureTokenValidSeconds(int minSecondsValid) {
method getAccessToken (line 275) | public String getAccessToken() {
method logout (line 280) | public boolean logout() {
class TlsRestTemplateCustomizer (line 313) | @Slf4j
method customize (line 318) | @Override
method createSslContext (line 333) | private SSLContext createSslContext() {
class AccessTokenResponse (line 346) | @Data
method setMetadata (line 361) | @JsonAnySetter
class UserInfoResponse (line 367) | @Data
method setMetadata (line 372) | @JsonAnySetter
FILE: apps/site/lib/keycloak-js/keycloak-authz.js
method get (line 29) | get() {
function initializeConfigIfNeeded (line 46) | async function initializeConfigIfNeeded() {
function loadConfig (line 249) | async function loadConfig(serverUrl, realm) {
function fetchJSON (line 264) | async function fetchJSON(url) {
function handleError (line 288) | function handleError(error, handler) {
FILE: apps/site/lib/keycloak-js/keycloak.js
function Keycloak (line 17) | function Keycloak (config) {
function bytesToBase64 (line 1779) | function bytesToBase64(bytes) {
function sha256Digest (line 1788) | async function sha256Digest(message) {
function decodeToken (line 1802) | function decodeToken(token) {
function base64UrlDecode (line 1827) | function base64UrlDecode(input) {
function b64DecodeUnicode (line 1855) | function b64DecodeUnicode(input) {
function isObject (line 1871) | function isObject(input) {
FILE: apps/spring-boot-device-flow-client/src/main/java/demo/SpringBootDeviceFlowApplication.java
class SpringBootDeviceFlowApplication (line 24) | @Slf4j
method main (line 28) | public static void main(String[] args) {
method clr (line 32) | @Bean
method requestDeviceCode (line 83) | private ResponseEntity<DeviceCodeResponse> requestDeviceCode(String cl...
method checkForDeviceFlowCompletion (line 97) | private ResponseEntity<AccessTokenResponse> checkForDeviceFlowCompleti...
class DeviceCodeResponse (line 111) | @Data
method setValue (line 128) | @JsonAnySetter
class AccessTokenResponse (line 134) | @Data
method setValue (line 143) | @JsonAnySetter
FILE: bin/applyRealmConfig.java
class applyKeycloakConfigCli (line 9) | class applyKeycloakConfigCli {
method main (line 11) | public static void main(String[] args) throws IOException, Interrupted...
FILE: bin/createTlsCerts.java
class createTlsCerts (line 26) | class createTlsCerts {
method main (line 50) | public static void main(String[] args) throws IOException, Interrupted...
FILE: bin/envcheck.java
class envcheck (line 8) | class envcheck {
method main (line 10) | public static void main(String[] args) throws IOException, Interrupted...
FILE: bin/importCertificateIntoTruststore.java
class importCertificateIntoTruststore (line 6) | public class importCertificateIntoTruststore {
method main (line 17) | public static void main(String[] args) throws IOException, Interrupted...
FILE: bin/installOtel.java
class installOtel (line 7) | class installOtel {
method main (line 9) | public static void main(String[] args) throws Exception {
method downloadFile (line 25) | public static void downloadFile(String url, Path filePath) {
FILE: bin/keycloakConfigCli.java
class keycloakConfigCli (line 7) | class keycloakConfigCli {
method main (line 22) | public static void main(String[] args) throws Exception {
FILE: bin/realmImex.java
class realmImex (line 13) | class realmImex {
method main (line 31) | public static void main(String[] args) throws IOException, Interrupted...
FILE: keycloak/e2e-tests/cypress.config.ts
method setupNodeEvents (line 13) | setupNodeEvents(on, config) {
FILE: keycloak/e2e-tests/cypress/utils/keycloakUtils.ts
function visitClient (line 3) | function visitClient(clientId: string) {
function loginUser (line 7) | function loginUser(user: any) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/account/AccountActivity.java
class AccountActivity (line 21) | @JBossLog
method onUserMfaChanged (line 24) | public static void onUserMfaChanged(KeycloakSession session, RealmMode...
method onAccountDeletionRequested (line 50) | public static void onAccountDeletionRequested(KeycloakSession session,...
method onTrustedDeviceChange (line 63) | public static void onTrustedDeviceChange(KeycloakSession session, Real...
method onAccountLockedOut (line 87) | public static void onAccountLockedOut(KeycloakSession session, RealmMo...
method onAccountUpdate (line 98) | public static void onAccountUpdate(KeycloakSession session, RealmModel...
method getCredentialLabel (line 109) | private static String getCredentialLabel(CredentialModel credential) {
method onCredentialChange (line 124) | public static void onCredentialChange(KeycloakSession session, RealmMo...
method onUserPasskeyChanged (line 135) | public static void onUserPasskeyChanged(KeycloakSession session, Realm...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/account/AccountChange.java
class AccountChange (line 5) | @Data
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/account/AccountDeletion.java
class AccountDeletion (line 15) | public class AccountDeletion {
method createActionToken (line 17) | public static URI createActionToken(KeycloakSession session, RealmMode...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/account/AccountEmail.java
class AccountEmail (line 13) | public class AccountEmail {
method send (line 15) | public static void send(KeycloakSession session, EmailTemplateProvider...
type SendEmailTask (line 30) | @FunctionalInterface
method sendEmail (line 33) | void sendEmail(EmailTemplateProvider emailTemplateProvider, Map<Stri...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/account/AccountPostLoginAction.java
class AccountPostLoginAction (line 14) | @JBossLog
method evaluateTriggers (line 19) | @Override
method updateLastActivityTimestamp (line 33) | private void updateLastActivityTimestamp(UserModel user) {
method requiredActionChallenge (line 37) | @Override
method processAction (line 42) | @Override
method close (line 47) | @Override
class Factory (line 52) | @AutoService(RequiredActionFactory.class)
method getId (line 57) | @Override
method getDisplayText (line 62) | @Override
method create (line 67) | @Override
method init (line 72) | @Override
method postInit (line 77) | @Override
method close (line 82) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/account/MfaChange.java
type MfaChange (line 3) | public enum MfaChange {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/account/RequestAccountDeletionActionToken.java
class RequestAccountDeletionActionToken (line 6) | public class RequestAccountDeletionActionToken extends DefaultActionToken {
method RequestAccountDeletionActionToken (line 12) | public RequestAccountDeletionActionToken(String userId, int absoluteEx...
method RequestAccountDeletionActionToken (line 21) | @SuppressWarnings("unused")
method getRedirectUri (line 25) | @JsonProperty(REDIRECT_URI)
method setRedirectUri (line 30) | @JsonProperty(REDIRECT_URI)
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/account/RequestAccountDeletionActionTokenHandler.java
class RequestAccountDeletionActionTokenHandler (line 20) | @JBossLog
method RequestAccountDeletionActionTokenHandler (line 26) | public RequestAccountDeletionActionTokenHandler() {
method handleToken (line 30) | @Override
method getVerifiers (line 44) | @Override
method canUseTokenRepeatedly (line 50) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/account/console/AcmeAccountConsoleFactory.java
class AcmeAccountConsoleFactory (line 16) | @JBossLog
method init (line 20) | @Override
method create (line 26) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/admin/ui/example/ExampleUiPageProvider.java
class ExampleUiPageProvider (line 19) | @JBossLog
method getId (line 23) | @Override
method getHelpText (line 29) | @Override
method onCreate (line 34) | @Override
method onUpdate (line 47) | @Override
method preRemove (line 52) | @Override
method getConfigProperties (line 57) | @Override
method init (line 84) | @Override
method postInit (line 89) | @Override
method close (line 94) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/audit/AcmeAuditListener.java
class AcmeAuditListener (line 19) | @JBossLog
method AcmeAuditListener (line 28) | public AcmeAuditListener(KeycloakSession session) {
method onEvent (line 34) | @Override
method onEvent (line 39) | @Override
method processUserEventAfterTransaction (line 44) | private void processUserEventAfterTransaction(Event event) {
method processAdminEventAfterTransaction (line 90) | private void processAdminEventAfterTransaction(AdminEvent event, boole...
method close (line 95) | @Override
class Factory (line 100) | @AutoService(EventListenerProviderFactory.class)
method getId (line 103) | @Override
method create (line 108) | @Override // return singleton instance, create new AcmeAuditListener...
method init (line 113) | @Override
method postInit (line 118) | @Override // we could init our provider with information from other ...
method close (line 121) | @Override // close resources if necessary
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/authzen/AuthZen.java
class AuthZen (line 6) | public class AuthZen {
method AccessRequest (line 10) | public AccessRequest(Subject subject, Action action, Resource resource...
method AccessEvaluation (line 16) | public AccessEvaluation(Resource resource) {
method AccessEvaluation (line 20) | public AccessEvaluation(Action action, Resource resource) {
type EvaluationOption (line 28) | public enum EvaluationOption {
method Action (line 39) | public Action(String name) {
method Resource (line 45) | public Resource(String type) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/authzen/AuthzenClient.java
class AuthzenClient (line 29) | @JBossLog
method checkAccess (line 70) | public AuthZen.AccessResponse checkAccess(KeycloakSession session, Con...
method checkAccess (line 75) | public AuthZen.AccessResponse checkAccess(KeycloakSession session, Con...
method search (line 105) | public AuthZen.SearchResponse search(KeycloakSession session, MapConfi...
method createSubject (line 134) | protected AuthZen.Subject createSubject(ConfigAccessor config, UserMod...
method createResource (line 165) | protected AuthZen.Resource createResource(ConfigAccessor config, Realm...
method createAccessContext (line 175) | protected Map<String, Object> createAccessContext(KeycloakSession sess...
method extractRequestHeaders (line 194) | protected Map<String, Object> extractRequestHeaders(KeycloakSession se...
method extractContextAttributes (line 215) | protected Map<String, Object> extractContextAttributes(KeycloakSession...
method extractAttributes (line 227) | protected <T> Map<String, Object> extractAttributes(T source, ConfigAc...
method extractUserAttributes (line 247) | protected Map<String, Object> extractUserAttributes(UserModel user, Co...
method extractClientAttributes (line 266) | protected Map<String, Object> extractClientAttributes(ClientModel clie...
method extractRealmAttributes (line 271) | protected Map<String, Object> extractRealmAttributes(RealmModel realm,...
method fetchGroupNames (line 276) | protected List<String> fetchGroupNames(UserModel user) {
method fetchClientRoles (line 280) | protected List<String> fetchClientRoles(UserModel user, ClientModel cl...
method fetchRealmRoles (line 289) | protected List<String> fetchRealmRoles(UserModel user) {
method normalizeRoleName (line 296) | protected String normalizeRoleName(RoleModel role) {
method getBoolean (line 303) | protected boolean getBoolean(Map<String, String> config, String key, b...
method extractDefaultUserAttributes (line 312) | protected Map<String, Object> extractDefaultUserAttributes(UserModel u...
method fetchResponse (line 316) | protected <T> T fetchResponse(SimpleHttp request, Class<T> responseTyp...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/checkaccess/CheckAccessAuthenticator.java
class CheckAccessAuthenticator (line 51) | @JBossLog
method authenticate (line 56) | @Override
method checkGroups (line 85) | private CheckResult checkGroups(KeycloakSession session, RealmModel re...
method checkRoles (line 91) | private CheckResult checkRoles(KeycloakSession session, RealmModel rea...
method checkAttributes (line 97) | private CheckResult checkAttributes(KeycloakSession session, RealmMode...
method evaluateCheck (line 104) | private CheckResult evaluateCheck(String check, Boolean allowResult, B...
method checkGroupsInternal (line 123) | private Boolean checkGroupsInternal(KeycloakSession session, RealmMode...
method checkRolesInternal (line 153) | private Boolean checkRolesInternal(KeycloakSession session, RealmModel...
method resolveRole (line 183) | private static RoleModel resolveRole(KeycloakSession session, RealmMod...
method checkAttributeInternal (line 203) | private static Boolean checkAttributeInternal(UserModel user, ClientMo...
method action (line 234) | @Override
method requiresUser (line 239) | @Override
method configuredFor (line 244) | @Override
method setRequiredActions (line 249) | @Override
method close (line 254) | @Override
class Factory (line 260) | @AutoService(AuthenticatorFactory.class)
method create (line 265) | @Override
method getId (line 270) | @Override
method getDisplayType (line 275) | @Override
method getHelpText (line 280) | @Override
method getConfigProperties (line 285) | @Override
method getReferenceCategory (line 290) | @Override
method isUserSetupAllowed (line 295) | @Override
type AccessCheck (line 302) | interface AccessCheck {
method apply (line 303) | CheckResult apply(KeycloakSession session, RealmModel realm, UserMod...
class CheckResult (line 306) | @Data
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/confirmcookie/ConfirmCookieAuthenticator.java
class ConfirmCookieAuthenticator (line 24) | @JBossLog
method authenticate (line 29) | @Override
method action (line 43) | @Override
method requiresUser (line 48) | @Override
method configuredFor (line 53) | @Override
method setRequiredActions (line 58) | @Override
method close (line 63) | @Override
class Factory (line 68) | @AutoService(AuthenticatorFactory.class)
method getId (line 71) | @Override
method create (line 76) | @Override
method getDisplayType (line 81) | @Override
method getHelpText (line 86) | @Override
method getReferenceCategory (line 91) | @Override
method isConfigurable (line 96) | @Override
method getConfigProperties (line 101) | @Override
method getRequirementChoices (line 113) | @Override
method isUserSetupAllowed (line 118) | @Override
method postInit (line 123) | @Override
method init (line 128) | @Override
method close (line 133) | @Override
method getOperationalInfo (line 138) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/customcookie/CustomCookieAuthenticator.java
class CustomCookieAuthenticator (line 11) | public class CustomCookieAuthenticator extends CookieAuthenticator {
method CustomCookieAuthenticator (line 15) | public CustomCookieAuthenticator(KeycloakSession session) {
method authenticate (line 19) | @Override
class Factory (line 25) | public static class Factory extends CookieAuthenticatorFactory {
method create (line 26) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/debug/DebugAuthenticator.java
class DebugAuthenticator (line 23) | @JBossLog
method DebugAuthenticator (line 29) | public DebugAuthenticator() {
method authenticate (line 32) | @Override
method action (line 78) | @Override
method requiresUser (line 83) | @Override
method configuredFor (line 88) | @Override
method setRequiredActions (line 93) | @Override
method close (line 98) | @Override
class Factory (line 103) | @AutoService(AuthenticatorFactory.class)
method getId (line 123) | @Override
method create (line 128) | @Override
method getDisplayType (line 134) | @Override
method getHelpText (line 139) | @Override
method getReferenceCategory (line 144) | @Override
method isConfigurable (line 149) | @Override
method getRequirementChoices (line 154) | @Override
method isUserSetupAllowed (line 159) | @Override
method getConfigProperties (line 164) | @Override
method init (line 169) | @Override
method postInit (line 174) | @Override
method close (line 179) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/demo/SkippableRequiredAction.java
class SkippableRequiredAction (line 22) | public class SkippableRequiredAction implements RequiredActionProvider {
method evaluateTriggers (line 34) | @Override
method didUserSkipRequiredAction (line 56) | protected boolean didUserSkipRequiredAction(RequiredActionContext cont...
method isUserActionRequired (line 62) | protected boolean isUserActionRequired(UserModel user) {
method requiredActionChallenge (line 66) | @Override
method createChallengeForm (line 73) | protected Response createChallengeForm(RequiredActionContext context) {
method isSkipActionPossible (line 82) | protected boolean isSkipActionPossible(RequiredActionContext context) {
method processAction (line 97) | @Override
method markActionDone (line 122) | protected void markActionDone(UserModel user) {
method recordActionSkipped (line 127) | protected void recordActionSkipped(UserModel user, AuthenticationSessi...
method close (line 135) | @Override
class Factory (line 140) | @AutoService(RequiredActionFactory.class)
method getId (line 145) | @Override
method getDisplayText (line 150) | @Override
method create (line 155) | @Override
method getConfigMetadata (line 160) | @Override
method init (line 176) | @Override
method postInit (line 181) | @Override
method close (line 186) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/dynamicidp/DynamicIdpAuthenticator.java
class DynamicIdpAuthenticator (line 33) | public class DynamicIdpAuthenticator implements Authenticator {
method authenticate (line 35) | @Override
method action (line 76) | @Override
method requiresUser (line 81) | @Override
method configuredFor (line 86) | @Override
method setRequiredActions (line 91) | @Override
method close (line 96) | @Override
class Factory (line 101) | @AutoService(AuthenticatorFactory.class)
method getId (line 104) | @Override
method getDisplayType (line 109) | @Override
method getHelpText (line 114) | @Override
method getReferenceCategory (line 119) | @Override
method create (line 124) | @Override
method isConfigurable (line 129) | @Override
method getRequirementChoices (line 134) | @Override
method isUserSetupAllowed (line 139) | @Override
method getConfigProperties (line 144) | @Override
method init (line 150) | @Override
method postInit (line 154) | @Override
method close (line 158) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/hello/HelloAuthenticator.java
class HelloAuthenticator (line 22) | @JBossLog
method authenticate (line 27) | @Override
method action (line 42) | @Override
method requiresUser (line 50) | @Override
method configuredFor (line 55) | @Override
method setRequiredActions (line 60) | @Override
method close (line 65) | @Override
class Factory (line 70) | @AutoService(AuthenticatorFactory.class)
method getId (line 73) | @Override
method create (line 78) | @Override
method getDisplayType (line 83) | @Override
method getHelpText (line 88) | @Override
method getReferenceCategory (line 93) | @Override
method isConfigurable (line 98) | @Override
method getConfigProperties (line 103) | @Override
method getRequirementChoices (line 115) | @Override
method isUserSetupAllowed (line 120) | @Override
method postInit (line 125) | @Override
method init (line 130) | @Override
method close (line 139) | @Override
method getOperationalInfo (line 144) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/idpselection/AcmeDynamicIdpLookupUsernameForm.java
class AcmeDynamicIdpLookupUsernameForm (line 43) | @JBossLog
method authenticate (line 52) | @Override
method action (line 66) | @Override
method resolveTargetIdpByEmailDomain (line 154) | private String resolveTargetIdpByEmailDomain(RealmModel realm, String ...
method validateForm (line 181) | @Override
method redirect (line 193) | private void redirect(AuthenticationFlowContext context, String provid...
method challenge (line 217) | @Override
method createLoginForm (line 228) | @Override
method getDefaultChallengeMessage (line 233) | @Override
method findUserInLookupRealm (line 241) | protected UserModel findUserInLookupRealm(KeycloakSession session, Str...
class Factory (line 247) | @AutoService(AuthenticatorFactory.class)
method getId (line 250) | @Override
method getDisplayType (line 255) | @Override
method getReferenceCategory (line 260) | @Override
method getHelpText (line 265) | @Override
method getRequirementChoices (line 270) | @Override
method isUserSetupAllowed (line 275) | @Override
method isConfigurable (line 280) | @Override
method getConfigProperties (line 285) | @Override
method create (line 310) | @Override
method init (line 315) | @Override
method postInit (line 321) | @Override
method close (line 326) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/magiclink/MagicLinkAuthenticator.java
class MagicLinkAuthenticator (line 27) | @Slf4j
method authenticate (line 35) | @Override
method action (line 67) | @Override
method sendMagicLink (line 72) | private void sendMagicLink(AuthenticationFlowContext context) {
method generateMagicLink (line 98) | private String generateMagicLink(AuthenticationFlowContext context, St...
method displayMagicLinkPage (line 103) | private void displayMagicLinkPage(AuthenticationFlowContext context) {
method requiresUser (line 109) | @Override
method configuredFor (line 114) | @Override
method setRequiredActions (line 119) | @Override
method close (line 124) | @Override
class Factory (line 129) | @AutoService(AuthenticatorFactory.class)
method getId (line 134) | @Override
method create (line 139) | @Override
method getDisplayType (line 144) | @Override
method getHelpText (line 149) | @Override
method getReferenceCategory (line 154) | @Override
method isConfigurable (line 159) | @Override
method getRequirementChoices (line 164) | @Override
method isUserSetupAllowed (line 169) | @Override
method getConfigProperties (line 175) | @Override
method init (line 180) | @Override
method postInit (line 184) | @Override
method close (line 188) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/MfaInfo.java
class MfaInfo (line 6) | @Getter
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/emailcode/EmailCodeAuthenticatorForm.java
class EmailCodeAuthenticatorForm (line 33) | @JBossLog
method EmailCodeAuthenticatorForm (line 43) | public EmailCodeAuthenticatorForm(KeycloakSession session) {
method authenticate (line 47) | @Override
method challenge (line 52) | private void challenge(AuthenticationFlowContext context, FormMessage ...
method generateAndSendEmailCode (line 70) | private void generateAndSendEmailCode(AuthenticationFlowContext contex...
method toDisplayCode (line 83) | private String toDisplayCode(String emailCode) {
method fromDisplayCode (line 87) | private String fromDisplayCode(String code) {
method action (line 91) | @Override
method resetEmailCode (line 125) | private void resetEmailCode(AuthenticationFlowContext context) {
method validateCode (line 129) | private boolean validateCode(AuthenticationFlowContext context, String...
method requiresUser (line 134) | @Override
method configuredFor (line 139) | @Override
method setRequiredActions (line 144) | @Override
method close (line 149) | @Override
method sendEmailWithCode (line 154) | private void sendEmailWithCode(RealmModel realm, UserModel user, Strin...
method getCredentialProvider (line 180) | @Override
class Factory (line 186) | @AutoService(AuthenticatorFactory.class)
method getDisplayType (line 189) | @Override
method getReferenceCategory (line 194) | @Override
method isConfigurable (line 199) | @Override
method getRequirementChoices (line 204) | @Override
method isUserSetupAllowed (line 209) | @Override
method getHelpText (line 214) | @Override
method getConfigProperties (line 219) | @Override
method close (line 224) | @Override
method create (line 229) | @Override
method init (line 234) | @Override
method postInit (line 239) | @Override
method getId (line 244) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/emailcode/EmailCodeCredentialModel.java
class EmailCodeCredentialModel (line 5) | public class EmailCodeCredentialModel extends CredentialModel {
method EmailCodeCredentialModel (line 9) | public EmailCodeCredentialModel() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/emailcode/EmailCodeCredentialProvider.java
class EmailCodeCredentialProvider (line 18) | @JBossLog
method EmailCodeCredentialProvider (line 25) | public EmailCodeCredentialProvider(KeycloakSession session) {
method supportsCredentialType (line 29) | @Override
method isConfiguredFor (line 34) | @Override
method isValid (line 39) | @Override
method getType (line 44) | @Override
method createCredential (line 49) | @Override
method deleteCredential (line 61) | @Override
method getCredentialFromModel (line 71) | @Override
method getCredentialTypeMetadata (line 81) | @Override
class Factory (line 96) | @SuppressWarnings("rawtypes")
method create (line 100) | @Override
method getId (line 105) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/emailcode/RegisterEmailCodeRequiredAction.java
class RegisterEmailCodeRequiredAction (line 16) | @JBossLog
method evaluateTriggers (line 21) | @Override
method initiatedActionSupport (line 26) | @Override
method requiredActionChallenge (line 32) | @Override
method processAction (line 52) | @Override
method close (line 57) | @Override
class Factory (line 62) | @AutoService(RequiredActionFactory.class)
method create (line 67) | @Override
method init (line 72) | @Override
method postInit (line 77) | @Override
method close (line 82) | @Override
method getId (line 87) | @Override
method getDisplayText (line 92) | @Override
method isOneTimeAction (line 97) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/otp/AcmeOTPFormAuthenticator.java
class AcmeOTPFormAuthenticator (line 35) | public class AcmeOTPFormAuthenticator extends OTPFormAuthenticator {
method validateOTP (line 39) | @Override
class Factory (line 51) | @AutoService(AuthenticatorFactory.class)
method create (line 56) | @Override
method getId (line 61) | @Override
method getDisplayType (line 66) | @Override
method getHelpText (line 71) | @Override
method getConfigProperties (line 76) | @Override
method getReferenceCategory (line 81) | @Override
method isUserSetupAllowed (line 86) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/setup/SelectMfaMethodAuthenticator.java
class SelectMfaMethodAuthenticator (line 36) | @JBossLog
method authenticate (line 47) | @Override
method action (line 68) | @Override
method requiresUser (line 85) | @Override
method configuredFor (line 90) | @Override
method isMfaCredentialConfiguredForCurrentUser (line 95) | boolean isMfaCredentialConfiguredForCurrentUser(UserModel user, Set<St...
method getConfiguredMfaCredentialTypes (line 101) | private static Set<String> getConfiguredMfaCredentialTypes(Authenticat...
method getConfiguredMfaCredentialTypesRequiredActionsMapping (line 114) | private static Map<String, String> getConfiguredMfaCredentialTypesRequ...
method setRequiredActions (line 127) | @Override
method close (line 132) | @Override
method mapToString (line 137) | private static String mapToString(Map<String, String> map) {
method stringToMap (line 145) | private static Map<String, String> stringToMap(String string) {
class Factory (line 155) | @AutoService(AuthenticatorFactory.class)
method getId (line 158) | @Override
method create (line 163) | @Override
method getDisplayType (line 168) | @Override
method getHelpText (line 173) | @Override
method getReferenceCategory (line 178) | @Override
method isConfigurable (line 183) | @Override
method getConfigProperties (line 188) | @Override
method getRequirementChoices (line 213) | @Override
method isUserSetupAllowed (line 218) | @Override
method postInit (line 223) | @Override
method init (line 228) | @Override
method close (line 237) | @Override
method getOperationalInfo (line 242) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/sms/PhoneNumberUtils.java
class PhoneNumberUtils (line 5) | public class PhoneNumberUtils {
method abbreviatePhoneNumber (line 7) | public static String abbreviatePhoneNumber(String phoneNumber) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/sms/SmsAuthenticator.java
class SmsAuthenticator (line 35) | @JBossLog
method authenticate (line 61) | @Override
method extractPhoneNumber (line 86) | protected String extractPhoneNumber(KeycloakSession session, RealmMode...
method sendCodeAndChallenge (line 107) | protected void sendCodeAndChallenge(AuthenticationFlowContext context,...
method generateLoginForm (line 126) | protected LoginFormsProvider generateLoginForm(AuthenticationFlowConte...
method sendSmsWithCode (line 130) | protected boolean sendSmsWithCode(AuthenticationFlowContext context, U...
method createSmsCodeSender (line 145) | protected SmsCodeSender createSmsCodeSender(AuthenticationFlowContext ...
method validatePhoneNumberFormat (line 149) | protected boolean validatePhoneNumberFormat(String phoneNumber, Authen...
method action (line 160) | @Override
method handleFailure (line 222) | protected void handleFailure(AuthenticationFlowContext context, Authen...
method isCodeExpired (line 233) | protected boolean isCodeExpired(String codeExpireAt) {
method generateErrorForm (line 237) | protected LoginFormsProvider generateErrorForm(AuthenticationFlowConte...
method requiresUser (line 249) | @Override
method configuredFor (line 254) | @Override
method setRequiredActions (line 263) | @Override
method close (line 268) | @Override
class Factory (line 273) | @AutoService(AuthenticatorFactory.class)
method getId (line 339) | @Override
method getDisplayType (line 344) | @Override
method getHelpText (line 349) | @Override
method getReferenceCategory (line 354) | @Override
method isConfigurable (line 359) | @Override
method isUserSetupAllowed (line 364) | @Override
method getRequirementChoices (line 369) | @Override
method getConfigProperties (line 374) | @Override
method create (line 379) | @Override
method init (line 384) | @Override
method postInit (line 389) | @Override
method close (line 394) | @Override
method getOperationalInfo (line 399) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/sms/SmsCodeSender.java
class SmsCodeSender (line 19) | @JBossLog
method sendVerificationCode (line 22) | public boolean sendVerificationCode(KeycloakSession session, RealmMode...
method generateCode (line 49) | protected String generateCode(int length) {
method resolveDomain (line 53) | protected String resolveDomain(KeycloakContext context) {
method createSmsClient (line 58) | protected SmsClient createSmsClient(Map<String, String> config) {
method generateSmsText (line 63) | protected String generateSmsText(int ttlSeconds, String code, String s...
method appendWebOtpFragment (line 72) | protected String appendWebOtpFragment(String code, String domain, Stri...
method computeExpireAt (line 77) | protected String computeExpireAt(int ttlSeconds) {
method resolveSender (line 81) | protected String resolveSender(RealmModel realm, Map<String, String> c...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/sms/client/SmsClient.java
type SmsClient (line 3) | public interface SmsClient {
method send (line 5) | void send(String sender, String receiver, String message);
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/sms/client/SmsClientFactory.java
class SmsClientFactory (line 11) | public class SmsClientFactory {
method createClient (line 15) | public static SmsClient createClient(String name, Map<String, String> ...
method getAvailableClientNames (line 26) | public static Set<String> getAvailableClientNames() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/sms/client/mock/MockSmsClient.java
class MockSmsClient (line 8) | @JBossLog
method MockSmsClient (line 13) | public MockSmsClient(Map<String, String> config) {
method send (line 17) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/sms/credentials/SmsCredentialModel.java
class SmsCredentialModel (line 12) | @JBossLog
method SmsCredentialModel (line 19) | public SmsCredentialModel() {
method SmsCredentialModel (line 23) | public SmsCredentialModel(CredentialModel credentialModel) {
method getPhoneNumber (line 33) | public String getPhoneNumber() {
method setPhoneNumber (line 37) | public void setPhoneNumber(String phoneNumber) {
method writeCredentialData (line 41) | public void writeCredentialData() {
method readCredentialData (line 52) | public void readCredentialData() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/sms/credentials/SmsCredentialProvider.java
class SmsCredentialProvider (line 20) | @JBossLog
method SmsCredentialProvider (line 27) | public SmsCredentialProvider(KeycloakSession session) {
method supportsCredentialType (line 31) | @Override
method isConfiguredFor (line 36) | @Override
method isValid (line 41) | @Override
method getType (line 46) | @Override
method createCredential (line 51) | @Override
method extractPhoneNumber (line 72) | private String extractPhoneNumber(SmsCredentialModel model, UserModel ...
method deleteCredential (line 80) | @Override
method getCredentialFromModel (line 85) | @Override
method getCredentialTypeMetadata (line 95) | @Override
class Factory (line 111) | @SuppressWarnings("rawtypes")
method create (line 115) | @Override
method getId (line 120) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/mfa/sms/updatephone/UpdatePhoneNumberRequiredAction.java
class UpdatePhoneNumberRequiredAction (line 36) | @JBossLog
method initiatedActionSupport (line 50) | @Override
method evaluateTriggers (line 56) | @Override
method requiredActionChallenge (line 73) | @Override
method createForm (line 80) | protected Response createForm(RequiredActionContext context, Consumer<...
method processAction (line 103) | @Override
method afterPhoneNumberVerified (line 175) | protected void afterPhoneNumberVerified(RealmModel realm, UserModel us...
method updateSmsMfaCredential (line 180) | protected void updateSmsMfaCredential(RealmModel realm, UserModel user...
method isValidPhoneNumber (line 198) | private static boolean isValidPhoneNumber(String phoneNumber) {
method createSmsSender (line 209) | protected SmsCodeSender createSmsSender(RequiredActionContext context) {
method close (line 213) | @Override
class Factory (line 218) | @AutoService(RequiredActionFactory.class)
method create (line 223) | @Override
method init (line 228) | @Override
method postInit (line 233) | @Override
method close (line 238) | @Override
method getId (line 243) | @Override
method getDisplayText (line 248) | @Override
method isOneTimeAction (line 253) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/net/NetworkAuthenticator.java
class NetworkAuthenticator (line 45) | @JBossLog
method authenticate (line 65) | @Override
method isAccessAllowed (line 109) | @VisibleForTesting
method resolveAllowedNetworks (line 134) | @VisibleForTesting
method errorResponse (line 150) | public Response errorResponse(AuthenticationFlowContext flowContext, i...
method isAllowedNetworkConfigured (line 164) | private boolean isAllowedNetworkConfigured(String allowedNetworks) {
method getAllowedNetworksForAuthenticator (line 168) | @VisibleForTesting
method getAllowedNetworksForClient (line 183) | @VisibleForTesting
method isRemoteIpAllowed (line 188) | @VisibleForTesting
method resolveRemoteIp (line 215) | @VisibleForTesting
method getRemoteIpHeaderName (line 241) | @VisibleForTesting
method action (line 261) | @Override
method requiresUser (line 266) | @Override
method configuredFor (line 272) | @Override
method setRequiredActions (line 277) | @Override
method close (line 282) | @Override
class Factory (line 287) | @AutoService(AuthenticatorFactory.class)
method getId (line 314) | @Override
method getDisplayType (line 319) | @Override
method getReferenceCategory (line 324) | @Override
method getHelpText (line 329) | @Override
method create (line 334) | @Override
method init (line 339) | @Override
method postInit (line 344) | @Override
method isConfigurable (line 349) | @Override
method getRequirementChoices (line 354) | @Override
method isUserSetupAllowed (line 359) | @Override
method getConfigProperties (line 364) | @Override
method close (line 369) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/opa/OpaAccessResponse.java
class OpaAccessResponse (line 12) | @Data
method OpaAccessResponse (line 20) | public OpaAccessResponse(AuthZen.AccessResponse result) {
method isAllowed (line 24) | @JsonIgnore
method getHint (line 29) | public String getHint() {
method handleUnknownProperty (line 43) | @JsonAnySetter
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/opa/OpaAuthenticator.java
class OpaAuthenticator (line 25) | @JBossLog
method OpaAuthenticator (line 32) | public OpaAuthenticator(KeycloakSession session, OpaClient opaClient) {
method authenticate (line 37) | @Override
method action (line 62) | @Override
method requiresUser (line 67) | @Override
method configuredFor (line 72) | @Override
method setRequiredActions (line 77) | @Override
method close (line 82) | @Override
class OpaAuthenticatorFactory (line 87) | @AutoService(AuthenticatorFactory.class)
method getId (line 165) | public String getId() {
method getDisplayType (line 169) | @Override
method getReferenceCategory (line 174) | @Override
method getHelpText (line 179) | @Override
method isConfigurable (line 184) | @Override
method getRequirementChoices (line 189) | @Override
method isUserSetupAllowed (line 194) | @Override
method getConfigProperties (line 199) | @Override
method create (line 204) | @Override
method init (line 209) | @Override
method postInit (line 214) | @Override
method close (line 219) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/opa/OpaCheckAccessAction.java
class OpaCheckAccessAction (line 23) | public class OpaCheckAccessAction implements RequiredActionProvider {
method OpaCheckAccessAction (line 106) | public OpaCheckAccessAction(OpaClient opaClient) {
method evaluateTriggers (line 110) | @Override
method requiredActionChallenge (line 122) | @Override
method processAction (line 151) | @Override
method close (line 156) | @Override
class Factory (line 162) | @AutoService(RequiredActionFactory.class)
method create (line 167) | @Override
method init (line 172) | @Override
method postInit (line 178) | @Override
method getConfigMetadata (line 183) | @Override
method close (line 188) | @Override
method getId (line 193) | @Override
method getDisplayText (line 198) | @Override
method isOneTimeAction (line 203) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/opa/OpaClient.java
class OpaClient (line 30) | @JBossLog
method checkAccess (line 67) | public OpaAccessResponse checkAccess(KeycloakSession session, ConfigAc...
method checkAccess (line 72) | public OpaAccessResponse checkAccess(KeycloakSession session, ConfigAc...
method createSubject (line 101) | protected AuthZen.Subject createSubject(ConfigAccessor config, UserMod...
method createResource (line 124) | protected AuthZen.Resource createResource(ConfigAccessor config, Realm...
method createAccessContext (line 134) | protected Map<String, Object> createAccessContext(KeycloakSession sess...
method extractRequestHeaders (line 143) | protected Map<String, Object> extractRequestHeaders(KeycloakSession se...
method extractContextAttributes (line 164) | protected Map<String, Object> extractContextAttributes(KeycloakSession...
method extractAttributes (line 176) | protected <T> Map<String, Object> extractAttributes(T source, ConfigAc...
method extractUserAttributes (line 196) | protected Map<String, Object> extractUserAttributes(UserModel user, Co...
method extractClientAttributes (line 215) | protected Map<String, Object> extractClientAttributes(ClientModel clie...
method extractRealmAttributes (line 220) | protected Map<String, Object> extractRealmAttributes(RealmModel realm,...
method fetchGroupNames (line 225) | protected List<String> fetchGroupNames(UserModel user) {
method fetchClientRoles (line 229) | protected List<String> fetchClientRoles(UserModel user, ClientModel cl...
method fetchRealmRoles (line 238) | protected List<String> fetchRealmRoles(UserModel user) {
method normalizeRoleName (line 245) | protected String normalizeRoleName(RoleModel role) {
method getBoolean (line 252) | protected boolean getBoolean(Map<String, String> config, String key, b...
method extractDefaultUserAttributes (line 261) | protected Map<String, Object> extractDefaultUserAttributes(UserModel u...
method fetchResponse (line 265) | protected OpaAccessResponse fetchResponse(SimpleHttp request) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/passwordform/FederationAwarePasswordForm.java
class FederationAwarePasswordForm (line 17) | public class FederationAwarePasswordForm extends PasswordForm {
method FederationAwarePasswordForm (line 19) | public FederationAwarePasswordForm(KeycloakSession session) {
method configuredFor (line 23) | @Override
class Factory (line 35) | @JBossLog
method create (line 39) | @Override
method postInit (line 44) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/trusteddevice/TrustedDeviceCookie.java
class TrustedDeviceCookie (line 10) | public class TrustedDeviceCookie {
method removeDeviceCookie (line 14) | public static void removeDeviceCookie(KeycloakSession session, RealmMo...
method addDeviceCookie (line 19) | public static void addDeviceCookie(String deviceTokenString, int maxAg...
method parseDeviceTokenFromCookie (line 23) | public static TrustedDeviceToken parseDeviceTokenFromCookie(HttpReques...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/trusteddevice/TrustedDeviceName.java
class TrustedDeviceName (line 12) | public class TrustedDeviceName {
method generateDeviceName (line 16) | public static String generateDeviceName(HttpRequest request) {
method guessOsFromUserAgentString (line 35) | private static String guessOsFromUserAgentString(String userAgentStrin...
method guessDeviceTypeFromUserAgentString (line 44) | private static String guessDeviceTypeFromUserAgentString(String userAg...
method sanitizeDeviceName (line 64) | public static String sanitizeDeviceName(String deviceNameInput) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/trusteddevice/TrustedDeviceToken.java
class TrustedDeviceToken (line 7) | public class TrustedDeviceToken extends JsonWebToken {
method getCategory (line 12) | @Override
method getDeviceId (line 17) | public String getDeviceId() {
method setDeviceId (line 21) | public void setDeviceId(String deviceId) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/trusteddevice/action/ManageTrustedDeviceAction.java
class ManageTrustedDeviceAction (line 35) | @JBossLog
method initiatedActionSupport (line 45) | @Override
method evaluateTriggers (line 50) | @Override
method requiredActionChallenge (line 55) | @Override
method processAction (line 83) | @Override
method afterTrustedDeviceRegistration (line 133) | private void afterTrustedDeviceRegistration(RequiredActionContext cont...
method registerNewTrustedDevice (line 147) | private void registerNewTrustedDevice(KeycloakSession session, RealmMo...
method removeTrustedDevices (line 177) | private void removeTrustedDevices(RequiredActionContext context) {
method createDeviceToken (line 185) | protected TrustedDeviceToken createDeviceToken(String deviceId, int nu...
method close (line 204) | @Override
class Factory (line 209) | @AutoService(RequiredActionFactory.class)
method create (line 214) | @Override
method init (line 219) | @Override
method postInit (line 224) | @Override
method close (line 229) | @Override
method getId (line 234) | @Override
method getDisplayText (line 239) | @Override
method isOneTimeAction (line 244) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/trusteddevice/action/TrustedDeviceInfo.java
class TrustedDeviceInfo (line 3) | public class TrustedDeviceInfo {
method TrustedDeviceInfo (line 7) | public TrustedDeviceInfo(String deviceName) {
method getDeviceName (line 11) | public String getDeviceName() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/trusteddevice/auth/TrustedDeviceAuthenticator.java
class TrustedDeviceAuthenticator (line 26) | @JBossLog
method lookupTrustedDeviceCredentialModelFromCookie (line 31) | public static TrustedDeviceCredentialModel lookupTrustedDeviceCredenti...
method authenticate (line 56) | @Override
method action (line 78) | @Override
method requiresUser (line 83) | @Override
method configuredFor (line 88) | @Override
method setRequiredActions (line 93) | @Override
method close (line 98) | @Override
method getCredentialProvider (line 103) | @Override
class Factory (line 108) | @AutoService(AuthenticatorFactory.class)
method getId (line 113) | @Override
method getDisplayType (line 118) | @Override
method getHelpText (line 123) | @Override
method isConfigurable (line 128) | @Override
method getRequirementChoices (line 133) | @Override
method isUserSetupAllowed (line 138) | @Override
method getReferenceCategory (line 143) | @Override
method getConfigProperties (line 148) | @Override
method create (line 153) | @Override
method init (line 158) | @Override
method postInit (line 163) | @Override
method close (line 168) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/trusteddevice/credentials/TrustedDeviceCredentialInput.java
class TrustedDeviceCredentialInput (line 5) | public class TrustedDeviceCredentialInput implements CredentialInput {
method TrustedDeviceCredentialInput (line 13) | public TrustedDeviceCredentialInput(String credentialId, String type, ...
method getCredentialId (line 19) | @Override
method getType (line 24) | @Override
method getChallengeResponse (line 29) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/trusteddevice/credentials/TrustedDeviceCredentialModel.java
class TrustedDeviceCredentialModel (line 7) | public class TrustedDeviceCredentialModel extends CredentialModel {
method TrustedDeviceCredentialModel (line 15) | public TrustedDeviceCredentialModel(String deviceName, TrustedDeviceTo...
method TrustedDeviceCredentialModel (line 20) | public TrustedDeviceCredentialModel(String id, String deviceName, Stri...
method getType (line 26) | @Override
method getDeviceToken (line 31) | public TrustedDeviceToken getDeviceToken() {
method getDeviceId (line 35) | public String getDeviceId() {
method lookupTrustedDevice (line 39) | public static TrustedDeviceCredentialModel lookupTrustedDevice(UserMod...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/trusteddevice/credentials/TrustedDeviceCredentialProvider.java
class TrustedDeviceCredentialProvider (line 22) | @JBossLog
method TrustedDeviceCredentialProvider (line 29) | public TrustedDeviceCredentialProvider(KeycloakSession session) {
method getType (line 33) | @Override
method createCredential (line 38) | @Override
method createTrustedDeviceCredentialModel (line 57) | protected CredentialModel createTrustedDeviceCredentialModel(TrustedDe...
method deleteCredential (line 70) | @Override
method deleteMatchingDeviceCookieIfPresent (line 90) | private boolean deleteMatchingDeviceCookieIfPresent(RealmModel realm, ...
method getCredentialFromModel (line 108) | @Override
method getCredentialTypeMetadata (line 118) | @Override
method supportsCredentialType (line 139) | @Override
method isConfiguredFor (line 144) | @Override
method isValid (line 149) | @Override
class Factory (line 166) | @SuppressWarnings("rawtypes")
method create (line 170) | @Override
method getId (line 175) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/trusteddevice/support/UserAgentParser.java
class UserAgentParser (line 8) | @JBossLog
method parseUserAgent (line 23) | public static UserAgent parseUserAgent(String userAgentString) {
method parseOperationSystem (line 32) | public static OS parseOperationSystem(String userAgentString) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/userpasswordform/AcmeCaptchaUsernamePasswordForm.java
class AcmeCaptchaUsernamePasswordForm (line 24) | public class AcmeCaptchaUsernamePasswordForm extends UsernamePasswordForm {
method challenge (line 32) | @Override
method challenge (line 38) | @Override
method challenge (line 44) | @Override
method addCaptcha (line 50) | private void addCaptcha(AuthenticationFlowContext context) {
method validateForm (line 90) | @Override
method checkCaptcha (line 100) | private boolean checkCaptcha(AuthenticationFlowContext context, Multiv...
class Factory (line 130) | @AutoService(AuthenticatorFactory.class)
method getId (line 135) | @Override
method create (line 140) | @Override
method getDisplayType (line 145) | @Override
method getHelpText (line 150) | @Override
method getReferenceCategory (line 155) | @Override
method isConfigurable (line 160) | @Override
method getRequirementChoices (line 165) | @Override
method isUserSetupAllowed (line 170) | @Override
method getConfigProperties (line 176) | @Override
method init (line 181) | @Override
method postInit (line 185) | @Override
method close (line 189) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/auth/verifyemailcode/VerifyEmailCodeAction.java
class VerifyEmailCodeAction (line 40) | @JBossLog
method evaluateTriggers (line 48) | @Override
method requiredActionChallenge (line 56) | @Override
method requiredActionChallenge (line 61) | public void requiredActionChallenge(RequiredActionContext context, For...
method processAction (line 101) | @Override
method generateAndSendEmailCode (line 140) | protected void generateAndSendEmailCode(RequiredActionContext context,...
method toDisplayCode (line 153) | protected String toDisplayCode(String emailCode, VerifyEmailCodeAction...
method fromDisplayCode (line 157) | protected String fromDisplayCode(String code) {
method resetEmailCode (line 161) | protected void resetEmailCode(RequiredActionContext context) {
method validateCode (line 165) | protected boolean validateCode(RequiredActionContext context, String g...
method sendEmailWithCode (line 170) | protected void sendEmailWithCode(RequiredActionContext context, String...
method close (line 200) | @Override
method getId (line 204) | @Override
method getDisplayText (line 209) | @Override
method create (line 214) | @Override
method init (line 219) | @Override
method postInit (line 224) | @Override
method getConfigMetadata (line 229) | @Override
class VerifyEmailCodeActionConfig (line 261) | @Data
method VerifyEmailCodeActionConfig (line 270) | public VerifyEmailCodeActionConfig(RequiredActionConfigModel config) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/authz/filter/AcmeAccessFilter.java
class AcmeAccessFilter (line 24) | @JBossLog
method filter (line 29) | @Override
method authenticateRealmAdminRequest (line 47) | private AdminAuth authenticateRealmAdminRequest(KeycloakSession sessio...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/authz/policies/AcmeImpersonationPolicyProvider.java
class AcmeImpersonationPolicyProvider (line 26) | @JBossLog
method AcmeImpersonationPolicyProvider (line 32) | public AcmeImpersonationPolicyProvider(KeycloakSession session, Author...
method evaluate (line 37) | @Override
method isImpersonationAllowed (line 68) | protected boolean isImpersonationAllowed(RealmModel realm, UserModel s...
method close (line 77) | @Override
class AcmeImpersonationPolicyRepresentation (line 82) | public static class AcmeImpersonationPolicyRepresentation extends JSPo...
class Factory (line 86) | @AutoService(PolicyProviderFactory.class)
method getId (line 89) | @Override
method getName (line 94) | @Override
method getGroup (line 99) | @Override
method create (line 104) | @Override
method create (line 109) | @Override
method create (line 114) | public PolicyProvider create(KeycloakSession session, AuthorizationP...
method init (line 118) | @Override
method postInit (line 123) | @Override
method toRepresentation (line 128) | @Override
method onUpdate (line 140) | @Override
method getRepresentationType (line 147) | @Override
method close (line 152) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/config/ClientConfig.java
class ClientConfig (line 6) | @RequiredArgsConstructor
method getType (line 11) | @Override
method getSource (line 16) | @Override
method getValue (line 21) | public String getValue(String key) {
method containsKey (line 25) | public boolean containsKey(String key) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/config/ConfigAccessor.java
type ConfigAccessor (line 9) | public interface ConfigAccessor {
method getType (line 11) | String getType();
method getSource (line 13) | String getSource();
method containsKey (line 15) | boolean containsKey(String key);
method getValue (line 17) | String getValue(String key);
method getValueOrDefault (line 19) | default <T> T getValueOrDefault(String key, T defaultValue, Function<S...
method getValue (line 29) | default <T> T getValue(String key, Function<String, T> converter) {
method getString (line 39) | default String getString(String key, String defaultValue) {
method getString (line 43) | default String getString(String key) {
method getInt (line 47) | default Integer getInt(String key, Integer defaultValue) {
method getInt (line 51) | default int getInt(String key) {
method getEnum (line 55) | default <T extends Enum<T>> T getEnum(Class<T> enumType, String key, T...
method getEnum (line 59) | default <T extends Enum<T>> T getEnum(Class<T> enumType, String key) {
method getLong (line 63) | default Long getLong(String key, Long defaultValue) {
method getLong (line 67) | default long getLong(String key) {
method getBoolean (line 71) | default Boolean getBoolean(String key, Boolean defaultValue) {
method getBoolean (line 75) | default boolean getBoolean(String key) {
method isConfigured (line 86) | default boolean isConfigured(String key, boolean defaultValue) {
class MissingKeyException (line 97) | @RequiredArgsConstructor
method getMessage (line 106) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/config/MapConfig.java
class MapConfig (line 6) | public class MapConfig implements ConfigAccessor {
method MapConfig (line 10) | public MapConfig(Map<String, String> config) {
method getType (line 14) | @Override
method getSource (line 19) | @Override
method containsKey (line 24) | @Override
method getValue (line 29) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/config/RealmConfig.java
class RealmConfig (line 8) | @Getter
method getType (line 17) | @Override
method getSource (line 22) | @Override
method getValue (line 27) | public String getValue(String key) {
method containsKey (line 31) | public boolean containsKey(String key) {
method prefixed (line 35) | private String prefixed(String key) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/consent/ConsentSelectionAction.java
class ConsentSelectionAction (line 39) | @AutoService(RequiredActionFactory.class)
method getScopeFieldMapping (line 46) | private Map<String, List<ScopeField>> getScopeFieldMapping() {
method getId (line 71) | @Override
method getDisplayText (line 76) | @Override
method create (line 81) | @Override
method initiatedActionSupport (line 86) | @Override
method evaluateTriggers (line 92) | @Override
method requiredActionChallenge (line 125) | @Override
method createForm (line 132) | protected Response createForm(RequiredActionContext context, Consumer<...
method processAction (line 172) | @Override
method init (line 259) | @Override
method postInit (line 264) | @Override
method close (line 269) | @Override
method getScopeInfo (line 274) | private ScopeInfo getScopeInfo(KeycloakSession session, Authentication...
method computeRequestedScopes (line 303) | private RequestedScopes computeRequestedScopes(AuthenticationSessionMo...
class ScopeInfo (line 331) | @Data
class RequestedScopes (line 341) | @Data
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/consent/ScopeBean.java
class ScopeBean (line 10) | @RequiredArgsConstructor
method isOptional (line 25) | public boolean isOptional() {
method isGranted (line 29) | public boolean isGranted() {
method getGuiOrder (line 33) | public String getGuiOrder() {
method getScopeModel (line 43) | public ClientScopeModel getScopeModel() {
method getName (line 47) | public String getName() {
method getDescription (line 51) | public String getDescription() {
method getFields (line 55) | public List<ScopeFieldBean> getFields() {
method toString (line 59) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/consent/ScopeField.java
class ScopeField (line 8) | @Data
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/consent/ScopeFieldBean.java
class ScopeFieldBean (line 6) | @Data
method getName (line 13) | public String getName() {
method getType (line 17) | public String getType() {
method getValue (line 21) | public String getValue() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/context/ContextSelectionAction.java
class ContextSelectionAction (line 27) | @JBossLog
method initiatedActionSupport (line 44) | @Override
method evaluateTriggers (line 49) | @Override
method isValidContextKey (line 98) | private boolean isValidContextKey(RequiredActionContext context, Strin...
method requiredActionChallenge (line 110) | @Override
method showContextSelectionForm (line 115) | private void showContextSelectionForm(RequiredActionContext context, C...
method getCurrentContextItem (line 138) | private static ContextItem getCurrentContextItem(RequiredActionContext...
method computeContextOptions (line 150) | private List<ContextItem> computeContextOptions(RequiredActionContext ...
method initiatedActionCanceled (line 161) | @Override
method processAction (line 167) | @Override
method close (line 201) | @Override
class ContextItem (line 206) | @Data
class Factory (line 213) | @AutoService(RequiredActionFactory.class)
method getId (line 218) | @Override
method getDisplayText (line 223) | @Override
method create (line 228) | @Override
method init (line 233) | @Override
method postInit (line 238) | @Override
method close (line 243) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/email/AcmeEmailSenderProvider.java
class AcmeEmailSenderProvider (line 19) | public class AcmeEmailSenderProvider extends DefaultEmailSenderProvider {
method AcmeEmailSenderProvider (line 23) | public AcmeEmailSenderProvider(KeycloakSession session, Map<EmailAuthe...
method send (line 28) | @Override
class Factory (line 37) | public static class Factory extends DefaultEmailSenderProviderFactory {
method create (line 41) | @Override
method init (line 46) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/CorsUtils.java
class CorsUtils (line 15) | public class CorsUtils {
method addCorsHeaders (line 19) | public static Cors addCorsHeaders(KeycloakSession session, //
method resolveClient (line 43) | private static ClientModel resolveClient(KeycloakSession session, Stri...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/CustomAdminResourceProvider.java
class CustomAdminResourceProvider (line 18) | @JBossLog
method CustomAdminResourceProvider (line 25) | public CustomAdminResourceProvider(UserProvisioningConfig privisioning...
method getResource (line 29) | @Override
method close (line 34) | @Override
class Factory (line 39) | @AutoService(AdminRealmResourceProviderFactory.class)
method getId (line 42) | @Override
method create (line 49) | @Override
method init (line 54) | @Override
method postInit (line 73) | @Override
method close (line 78) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/CustomResource.java
class CustomResource (line 40) | public class CustomResource {
method CustomResource (line 45) | public CustomResource(KeycloakSession session, AccessToken accessToken) {
method ping (line 50) | @GET
method preflight (line 67) | @OPTIONS
method settings (line 72) | @Path("me/settings")
method credentials (line 77) | @Path("me/credentials")
method applications (line 82) | @Path("me/applications")
method profile (line 87) | @Path("me/profile")
method account (line 92) | @Path("me/account")
method sessionPropagation (line 97) | @Path("mobile/session-propagation")
method branding (line 106) | @Path("branding")
method adminSettings (line 116) | @Path("admin/settings")
method tokenMigration (line 138) | @Path("migration/token")
method userMigration (line 143) | @Path("migration/users")
method idpApplications (line 148) | @Path("idp/applications")
method demoResource (line 153) | @Path("demos")
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/CustomResourceProvider.java
class CustomResourceProvider (line 23) | @JBossLog
method getResource (line 33) | @Override
method getAuth (line 61) | AdminPermissionEvaluator getAuth(KeycloakSession session) {
method close (line 66) | @Override
class Factory (line 71) | @JBossLog
method getId (line 77) | @Override
method create (line 82) | @Override
method init (line 87) | @Override
method postInit (line 93) | @Override
method close (line 98) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/account/AcmeAccountResource.java
class AcmeAccountResource (line 26) | public class AcmeAccountResource {
method AcmeAccountResource (line 31) | public AcmeAccountResource(KeycloakSession session, AccessToken token) {
method getCorsOptions (line 36) | @OPTIONS
method handleAccountDeletionRequest (line 41) | @DELETE
method withCors (line 71) | private Cors withCors(HttpRequest request) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/admin/AdminSettingsResource.java
class AdminSettingsResource (line 36) | @JBossLog
method AdminSettingsResource (line 53) | public AdminSettingsResource(KeycloakSession session, AuthenticationMa...
method adminUi (line 58) | @GET
method updateAdminSettings (line 74) | @POST
class RealmSettingsBean (line 107) | @RequiredArgsConstructor
method getAttributes (line 112) | public Map<String, String> getAttributes() {
method getSettings (line 116) | public List<ConfigSetting> getSettings() {
method getRawConfigSettings (line 122) | private List<ConfigSetting> getRawConfigSettings(Predicate<ConfigSet...
class ConfigSetting (line 136) | @Data
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/admin/CustomAdminResource.java
class CustomAdminResource (line 18) | public class CustomAdminResource {
method CustomAdminResource (line 30) | public CustomAdminResource(KeycloakSession session, RealmModel realm, ...
method getData (line 43) | @Path("/example")
method provisioningResource (line 59) | @Path("/users")
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/admin/UserProvisioningResource.java
class UserProvisioningResource (line 33) | @JBossLog
method UserProvisioningResource (line 46) | public UserProvisioningResource(KeycloakSession session, RealmModel re...
method provisionUsers (line 62) | @Path("/provisioning")
method isAuthorized (line 119) | private boolean isAuthorized() {
method createProvisioningResponse (line 131) | private UserProvisioningResponse createProvisioningResponse(UserProvis...
method provisionUser (line 149) | private void provisionUser(UserProvisioningResult result, UserRepresen...
method updateUserAttributes (line 196) | private UserProvisioningStatus updateUserAttributes(UserRepresentation...
class UserProvisioningRequest (line 234) | @Data
class UserProvisioningContext (line 240) | @Data
method UserProvisioningContext (line 253) | public UserProvisioningContext(RealmModel realm, UserProvider userPr...
method addResult (line 260) | public void addResult(UserProvisioningResult result) {
class UserProvisioningResponse (line 268) | @Data
type UserProvisioningStatus (line 275) | public static enum UserProvisioningStatus {
type UserProvisioningError (line 279) | public static enum UserProvisioningError {
class UserProvisioningResult (line 283) | @Data
class UserProvisioningConfig (line 299) | @Data
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/applications/ApplicationsInfoResource.java
class ApplicationsInfoResource (line 42) | public class ApplicationsInfoResource {
method ApplicationsInfoResource (line 47) | public ApplicationsInfoResource(KeycloakSession session, AccessToken t...
method getCorsOptions (line 52) | @OPTIONS
method readApplicationInfo (line 57) | @GET
method getApplicationsForUser (line 88) | public List<ClientRepresentation> getApplicationsForUser(RealmModel re...
method matches (line 122) | private boolean matches(ClientModel client, String name) {
method modelToRepresentation (line 135) | private ClientRepresentation modelToRepresentation(ClientModel model, ...
method getAccountMessages (line 153) | private Properties getAccountMessages(Locale locale) {
method modelToRepresentation (line 161) | private ConsentRepresentation modelToRepresentation(UserConsentModel m...
method withCors (line 168) | private Cors withCors() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/branding/BrandingResource.java
class BrandingResource (line 15) | public class BrandingResource {
method BrandingResource (line 19) | public BrandingResource(KeycloakSession session) {
method getBranding (line 23) | @GET
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/credentials/UserCredentialsInfoResource.java
class UserCredentialsInfoResource (line 48) | public class UserCredentialsInfoResource {
method UserCredentialsInfoResource (line 59) | public UserCredentialsInfoResource(KeycloakSession session, AccessToke...
method getCorsOptions (line 64) | @OPTIONS
method readCredentialInfo (line 69) | @GET
method removeCredentialByType (line 99) | @DELETE
method removeCredentialForUser (line 159) | private boolean removeCredentialForUser(RealmModel realm, UserModel us...
method loadCredentialInfosForUser (line 170) | private Map<String, List<CredentialInfo>> loadCredentialInfosForUser(R...
method newCredentialInfo (line 206) | private CredentialInfo newCredentialInfo(CredentialModel credential, S...
method isCurrentRequestFromGivenTrustedDevice (line 233) | private boolean isCurrentRequestFromGivenTrustedDevice(CredentialModel...
method shouldAggregate (line 243) | private boolean shouldAggregate(String credentialType) {
method withCors (line 247) | private Cors withCors(HttpRequest request) {
class CredentialInfo (line 251) | @Data
class RemoveCredentialRequest (line 265) | @Data
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/demo/DemosResource.java
class DemosResource (line 25) | @Consumes(MediaType.APPLICATION_JSON)
method DemosResource (line 31) | public DemosResource(KeycloakSession session) {
method demoCachedServiceAccountToken (line 42) | @Path("cached-serviceaccount-token")
method demoSlowQuery (line 66) | @Path("slow-query")
method demoAcmeUser (line 83) | @Path("acme-legacy-user")
method componentProviderLookupExample (line 114) | @Path("component-provider-lookup")
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/idp/IdpApplications.java
class IdpApplications (line 47) | @JBossLog
method IdpApplications (line 52) | public IdpApplications(KeycloakSession session) {
method getCorsOptions (line 56) | @OPTIONS
method applications (line 61) | @GET
method redirect (line 112) | private Response redirect(KeycloakContext context, String providerId, ...
method withCors (line 150) | private Cors withCors() {
class ApplicationsBean (line 155) | @Data
method getApplications (line 163) | public List<ApplicationInfo> getApplications() {
class ApplicationInfo (line 180) | @Data
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/migration/TokenMigrationResource.java
class TokenMigrationResource (line 30) | @RequiredArgsConstructor
method migrateToken (line 39) | @POST
method isAllowedMigration (line 116) | private boolean isAllowedMigration(TokenMigrationInput input) {
class TokenMigrationInput (line 120) | @Data
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/migration/UserImportMigrationResource.java
class UserImportMigrationResource (line 35) | @JBossLog
method migrateUsers (line 49) | @POST
method clearCache (line 152) | @Path("/cache")
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/offline/OfflineSessionPropagationResource.java
class OfflineSessionPropagationResource (line 25) | @JBossLog
method OfflineSessionPropagationResource (line 34) | public OfflineSessionPropagationResource(KeycloakSession session, Acce...
method propagateSession (line 51) | @POST
method resolveBaseUri (line 97) | private URI resolveBaseUri(ClientModel targetClient) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/offline/SessionPropagationActionToken.java
class SessionPropagationActionToken (line 6) | public class SessionPropagationActionToken extends DefaultActionToken {
method SessionPropagationActionToken (line 18) | public SessionPropagationActionToken(String userId, int absoluteExpira...
method SessionPropagationActionToken (line 29) | @SuppressWarnings("unused")
method getRedirectUri (line 33) | @JsonProperty(REDIRECT_URI)
method setRedirectUri (line 38) | @JsonProperty(REDIRECT_URI)
method getSourceClientId (line 47) | @JsonProperty(SOURCE_CLIENT_ID)
method setSourceClientId (line 52) | @JsonProperty(SOURCE_CLIENT_ID)
method getRememberMe (line 57) | @JsonProperty(REMEMBER_ME)
method setRememberMe (line 62) | @JsonProperty(REMEMBER_ME)
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/offline/SessionPropagationActionTokenHandler.java
class SessionPropagationActionTokenHandler (line 24) | @JBossLog
method SessionPropagationActionTokenHandler (line 31) | public SessionPropagationActionTokenHandler() {
method handleToken (line 35) | @Override
method redirectTo (line 81) | private Response redirectTo(String redirectUri) {
method getVerifiers (line 85) | @Override
method canUseTokenRepeatedly (line 92) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/profile/ProfileData.java
class ProfileData (line 5) | @Data
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/profile/UserProfileResource.java
class UserProfileResource (line 22) | public class UserProfileResource {
method UserProfileResource (line 30) | public UserProfileResource(KeycloakSession session, AccessToken token) {
method getCorsOptions (line 35) | @OPTIONS
method readProfile (line 40) | @GET
method updateProfile (line 61) | @PUT
method withCors (line 96) | private Cors withCors() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/endpoints/settings/UserSettingsResource.java
class UserSettingsResource (line 25) | public class UserSettingsResource {
method UserSettingsResource (line 33) | public UserSettingsResource(KeycloakSession session, AccessToken token) {
method getCorsOptions (line 38) | @OPTIONS
method readSettings (line 43) | @GET
method writeSettings (line 68) | @PUT
method withCors (line 98) | private Cors withCors() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/eventpublishing/AcmeEventPublisherEventListener.java
class AcmeEventPublisherEventListener (line 17) | @JBossLog
method onEvent (line 27) | @Override
method enrichUserEvent (line 32) | private Object enrichUserEvent(Event event) {
method onEvent (line 36) | @Override
method enrichAdminEvent (line 41) | private Object enrichAdminEvent(AdminEvent event, boolean includeRepre...
method close (line 45) | @Override
class Factory (line 50) | @AutoService(EventListenerProviderFactory.class)
method getId (line 55) | @Override
method create (line 60) | @Override // return singleton instance, create new AcmeAuditListener...
method init (line 65) | @Override
method createNatsPublisher (line 76) | private NatsEventPublisher createNatsPublisher(Config.Scope config) {
method postInit (line 90) | @Override // we could init our provider with information from other ...
method close (line 93) | @Override // close resources if necessary
method getOperationalInfo (line 100) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/eventpublishing/EventPublisher.java
type EventPublisher (line 5) | public interface EventPublisher {
method publish (line 7) | void publish(String topic, Object event);
method getOperationalInfo (line 9) | Map<String, String> getOperationalInfo();
method init (line 11) | void init();
method close (line 13) | void close();
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/eventpublishing/NatsEventPublisher.java
class NatsEventPublisher (line 13) | @JBossLog
method publish (line 25) | public void publish(String subject, Object event) {
method getOperationalInfo (line 46) | public Map<String, String> getOperationalInfo() {
method getStatus (line 50) | public String getStatus() {
method init (line 57) | public void init() {
method close (line 72) | public void close() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/eventpublishing/NoopPublisher.java
class NoopPublisher (line 7) | @JBossLog
method publish (line 10) | @Override
method getOperationalInfo (line 15) | @Override
method init (line 20) | @Override
method close (line 25) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/health/CustomHealthChecks.java
class CustomHealthChecks (line 26) | @JBossLog
method serverCheck (line 40) | @Produces
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/health/CustomReadinessCheck.java
class CustomReadinessCheck (line 11) | @Readiness
method call (line 18) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/idp/azure/CustomAzureADGroupMapper.java
class CustomAzureADGroupMapper (line 36) | @JBossLog
method supportsSyncMode (line 60) | @Override
method getConfigProperties (line 65) | @Override
method getId (line 70) | @Override
method getCompatibleProviders (line 75) | @Override
method getDisplayCategory (line 80) | @Override
method getDisplayType (line 85) | @Override
method getHelpText (line 90) | @Override
method importNewUser (line 95) | @Override
method updateBrokeredUser (line 100) | @Override
method updateGroupsIfNecessary (line 105) | private void updateGroupsIfNecessary(KeycloakSession session, RealmMod...
method fetchGroupListFromMsGraphApi (line 177) | private AADGroupList fetchGroupListFromMsGraphApi(KeycloakSession sess...
method queryMsGraphApi (line 195) | private SimpleHttpRequest queryMsGraphApi(KeycloakSession session, Str...
class AADData (line 203) | @Data
method setData (line 208) | @JsonAnySetter
class AADGroupInfo (line 214) | @Data
class AADGroupList (line 225) | @Data
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/idp/azure/CustomEntraIdProfileMapper.java
class CustomEntraIdProfileMapper (line 31) | @JBossLog
method supportsSyncMode (line 55) | @Override
method getConfigProperties (line 60) | @Override
method getId (line 65) | @Override
method getCompatibleProviders (line 70) | @Override
method getDisplayCategory (line 75) | @Override
method getDisplayType (line 80) | @Override
method getHelpText (line 85) | @Override
method importNewUser (line 90) | @Override
method updateBrokeredUser (line 95) | @Override
method updateProfileIfNecessary (line 100) | private void updateProfileIfNecessary(KeycloakSession session, RealmMo...
method updateLocaleInformation (line 123) | protected void updateLocaleInformation(RealmModel realm, UserModel use...
method updatePhoneInformation (line 143) | protected void updatePhoneInformation(UserModel user, GraphApiData gra...
method fetchProfileFromMsGraphApi (line 158) | private GraphApiData fetchProfileFromMsGraphApi(KeycloakSession sessio...
method queryMsGraphApi (line 177) | private SimpleHttpRequest queryMsGraphApi(KeycloakSession session, Str...
class GraphApiData (line 184) | @Data
method setData (line 191) | @JsonAnySetter
class EntraIdPhone (line 197) | @Data
method setData (line 204) | @JsonAnySetter
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/idp/brokering/RestrictBrokeredUserMapper.java
class RestrictBrokeredUserMapper (line 25) | @JBossLog
method getId (line 49) | @Override
method getCompatibleProviders (line 54) | @Override
method getDisplayCategory (line 59) | @Override
method getDisplayType (line 64) | @Override
method getHelpText (line 69) | @Override
method getConfigProperties (line 74) | @Override
method supportsSyncMode (line 79) | @Override
method create (line 84) | public IdentityProviderMapper create(KeycloakSession session) {
method preprocessFederatedIdentity (line 88) | @Override
method createErrorPageResponse (line 103) | private static Response createErrorPageResponse(KeycloakSession sessio...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/idp/linking/AcmeIdpLinkAction.java
class AcmeIdpLinkAction (line 29) | public class AcmeIdpLinkAction extends IdpLinkAction {
method getDisplayText (line 31) | @Override
method requiredActionChallenge (line 36) | @Override
method isAllowAccountLinkingForcedFor (line 82) | protected boolean isAllowAccountLinkingForcedFor(RealmModel realm, Cli...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/idp/oidc/AcmeOidcIdentityProvider.java
class AcmeOidcIdentityProvider (line 19) | public class AcmeOidcIdentityProvider extends OIDCIdentityProvider {
method AcmeOidcIdentityProvider (line 21) | public AcmeOidcIdentityProvider(KeycloakSession session, OIDCIdentityP...
method extractIdentity (line 25) | @Override
class Factory (line 36) | public static class Factory extends OIDCIdentityProviderFactory {
method create (line 38) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/idp/social/linkedin/LinkedInUserProfileImportIdpMapper.java
class LinkedInUserProfileImportIdpMapper (line 28) | @JBossLog
method getId (line 34) | @Override
method getCompatibleProviders (line 39) | @Override
method getDisplayCategory (line 44) | @Override
method getDisplayType (line 49) | @Override
method getHelpText (line 54) | @Override
method importNewUser (line 59) | @Override
method updateBrokeredUser (line 65) | @Override
type Action (line 71) | enum Action {
method updateUser (line 75) | private void updateUser(RealmModel realm, UserModel user, BrokeredIden...
method getConfigProperties (line 97) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/infinispan/CustomInfinispanUserSessionProviderFactory.java
class CustomInfinispanUserSessionProviderFactory (line 19) | @JBossLog
method create (line 23) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/jpa/CustomQuarkusJpaConnectionProviderFactory.java
class CustomQuarkusJpaConnectionProviderFactory (line 12) | @JBossLog
method getEntityManagerFactory (line 31) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/metrics/KeycloakMetric.java
class KeycloakMetric (line 6) | @Getter
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/metrics/KeycloakMetricAccessor.java
type KeycloakMetricAccessor (line 3) | public interface KeycloakMetricAccessor {
method getMetricValue (line 5) | Double getMetricValue(String metricKey);
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/metrics/KeycloakMetricStore.java
class KeycloakMetricStore (line 24) | @JBossLog
method KeycloakMetricStore (line 40) | public KeycloakMetricStore(KeycloakSessionFactory sessionFactory, Mete...
method getMetricValue (line 46) | public Double getMetricValue(String metricKey) {
method isRefreshNecessary (line 67) | private boolean isRefreshNecessary() {
method refreshMetricsIfNecessary (line 77) | private void refreshMetricsIfNecessary() {
method refreshMetrics (line 92) | private Map<String, Double> refreshMetrics() {
method collectCustomRealmMetricsIntoBuffer (line 114) | private void collectCustomRealmMetricsIntoBuffer(KeycloakSession sessi...
method registerCustomMetricIfMissing (line 154) | private String registerCustomMetricIfMissing(KeycloakMetric metric, Ta...
method toMetricKey (line 174) | private static String toMetricKey(String metricName, Tags tags) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/metrics/KeycloakMetrics.java
class KeycloakMetrics (line 25) | @JBossLog
method newKeycloakMetric (line 90) | private static KeycloakMetric newKeycloakMetric(String name, String de...
method KeycloakMetrics (line 100) | public KeycloakMetrics(MeterRegistry meterRegistry, KeycloakSessionFac...
method collectRealmSessionStats (line 131) | private RealmSessionStats collectRealmSessionStats(KeycloakSession ses...
class RealmSessionStats (line 139) | @Data
method registerInstanceMetrics (line 146) | public void registerInstanceMetrics() {
method getMeterRegistry (line 158) | public MeterRegistry getMeterRegistry() {
method removeRealmMetrics (line 162) | public void removeRealmMetrics(RealmModel realm) {
method initialize (line 189) | public void initialize() {
type Level (line 193) | public enum Level {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/metrics/RealmMetricUpdater.java
type RealmMetricUpdater (line 9) | public interface RealmMetricUpdater {
method updateMetricValue (line 20) | void updateMetricValue(KeycloakMetric keycloakMetric, MetricUpdateValu...
class MetricUpdateValue (line 22) | @Data
class MultiMetricUpdateValues (line 28) | class MultiMetricUpdateValues extends MetricUpdateValue<Map<Tags, Numb...
method MultiMetricUpdateValues (line 30) | public MultiMetricUpdateValues(Map<Tags, Number> value) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/metrics/RealmMetricsUpdater.java
type RealmMetricsUpdater (line 6) | public interface RealmMetricsUpdater {
method updateGlobalMetrics (line 8) | void updateGlobalMetrics(KeycloakSession session, RealmMetricUpdater m...
method updateRealmMetrics (line 10) | void updateRealmMetrics(KeycloakSession session, RealmMetricUpdater me...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/metrics/events/MetricEventListenerProvider.java
class MetricEventListenerProvider (line 21) | public class MetricEventListenerProvider implements EventListenerProvider {
method MetricEventListenerProvider (line 25) | public MetricEventListenerProvider(MetricEventRecorder recorder) {
method onEvent (line 29) | @Override
method onEvent (line 34) | @Override
method close (line 39) | @Override
class Factory (line 44) | @JBossLog
method getId (line 50) | @Override
method create (line 55) | @Override
method init (line 60) | @Override
method postInit (line 65) | @Override
method lookupMeterRegistry (line 91) | protected MeterRegistry lookupMeterRegistry() {
method close (line 95) | @Override
class NoopEventListenerProvider (line 101) | private static class NoopEventListenerProvider implements EventListene...
method onEvent (line 103) | @Override
method onEvent (line 109) | @Override
method close (line 115) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/metrics/events/MetricEventRecorder.java
class MetricEventRecorder (line 38) | @JBossLog
method MetricEventRecorder (line 52) | public MetricEventRecorder(KeycloakMetrics keycloakMetrics) {
method registerCustomUserEventHandlers (line 57) | private Map<EventType, Consumer<Event>> registerCustomUserEventHandler...
method recordEvent (line 78) | public void recordEvent(Event event) {
method recordEvent (line 82) | public void recordEvent(AdminEvent event, boolean includeRepresentatio...
method recordGenericAdminEvent (line 89) | private void recordGenericAdminEvent(AdminEvent event) {
method lookupUserEventHandler (line 101) | public Consumer<Event> lookupUserEventHandler(Event event) {
method recordOauthUserInfoRequestError (line 105) | protected void recordOauthUserInfoRequestError(Event event) {
method recordOauthUserInfoRequest (line 116) | protected void recordOauthUserInfoRequest(Event event) {
method recordOauthTokenExchange (line 126) | protected void recordOauthTokenExchange(Event event) {
method recordOauthTokenExchangeError (line 136) | protected void recordOauthTokenExchangeError(Event event) {
method recordUserLogout (line 146) | protected void recordUserLogout(Event event) {
method recordUserLogoutError (line 156) | protected void recordUserLogoutError(Event event) {
method recordOauthCodeToTokenError (line 167) | protected void recordOauthCodeToTokenError(Event event) {
method recordOauthCodeToToken (line 179) | protected void recordOauthCodeToToken(Event event) {
method recordClientLogin (line 190) | protected void recordClientLogin(Event event) {
method recordClientLoginError (line 200) | protected void recordClientLoginError(Event event) {
method recordOauthTokenRefreshError (line 211) | protected void recordOauthTokenRefreshError(Event event) {
method recordOauthTokenRefresh (line 223) | protected void recordOauthTokenRefresh(Event event) {
method recordUserRegistrationError (line 233) | protected void recordUserRegistrationError(Event event) {
method recordUserRegistration (line 245) | protected void recordUserRegistration(Event event) {
method recordUserLoginError (line 255) | protected void recordUserLoginError(Event event) {
method recordUserLogin (line 267) | protected void recordUserLogin(Event event) {
method recordGenericUserEvent (line 283) | protected void recordGenericUserEvent(Event event) {
method getIdentityProvider (line 305) | private String getIdentityProvider(Event event) {
method createCounter (line 322) | private Counter createCounter(String name, boolean isAdmin) {
method resolveClientId (line 328) | private String resolveClientId(String clientId) {
method resolveRealmName (line 335) | private String resolveRealmName(String realmId) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/migration/acmecred/AcmeCredentialModel.java
class AcmeCredentialModel (line 12) | public class AcmeCredentialModel extends CredentialModel {
method AcmeCredentialModel (line 20) | public AcmeCredentialModel(PasswordCredentialData acmeCredentialData, ...
method createFromCredentialModel (line 25) | public static AcmeCredentialModel createFromCredentialModel(Credential...
method getAcmeCredentialData (line 47) | public PasswordCredentialData getAcmeCredentialData() {
method getAcmeSecretData (line 51) | public PasswordSecretData getAcmeSecretData() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/migration/acmecred/AcmeCredentialProvider.java
class AcmeCredentialProvider (line 18) | @JBossLog
method AcmeCredentialProvider (line 23) | public AcmeCredentialProvider(KeycloakSession session) {
method getType (line 27) | @Override
method createCredential (line 32) | @Override
method deleteCredential (line 38) | @Override
method getCredentialFromModel (line 43) | @Override
method getCredentialTypeMetadata (line 53) | @Override
method supportsCredentialType (line 75) | @Override
method isConfiguredFor (line 82) | @Override
method isAcmeCredentialConfigured (line 89) | private boolean isAcmeCredentialConfigured(UserModel user) {
method isValid (line 93) | @Override
method migrateCredential (line 122) | protected void migrateCredential(RealmModel realm, UserModel user, Str...
class Factory (line 136) | @AutoService(CredentialProviderFactory.class)
method getId (line 139) | @Override
method create (line 144) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/migration/acmecred/AcmePasswordValidator.java
class AcmePasswordValidator (line 10) | public class AcmePasswordValidator {
method validateLegacyPassword (line 12) | public static boolean validateLegacyPassword(String password, AcmeCred...
method verifyPasswordSha1 (line 19) | private static boolean verifyPasswordSha1(String password, String expe...
method encodePassword (line 26) | public static String encodePassword(String password, String salt) {
method createHashedPassword (line 38) | private static byte[] createHashedPassword(byte[] passwordBytes, byte[...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/oauth/client/OauthClientCredentialsTokenManager.java
class OauthClientCredentialsTokenManager (line 23) | @JBossLog
method getToken (line 47) | public String getToken(KeycloakSession session) {
method createTokenCacheKey (line 86) | private String createTokenCacheKey(KeycloakSession session) {
method fetchToken (line 92) | protected AccessTokenResponse fetchToken(KeycloakSession session, Stri...
method createKeycloakSessionProxy (line 136) | private KeycloakSession createKeycloakSessionProxy(KeycloakSession tar...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/oauth/tokenexchange/ApiKeyTokenExchangeProvider.java
class ApiKeyTokenExchangeProvider (line 30) | @JBossLog
method exchangeClientToClient (line 44) | @Override
method exchangeExternalToken (line 86) | @Override
method exchangeToIdentityProvider (line 91) | @Override
method unsupportedResponse (line 96) | private Response unsupportedResponse() {
method supports (line 100) | @Override
method close (line 116) | @Override
class Factory (line 121) | @AutoService(TokenExchangeProviderFactory.class)
method getId (line 124) | @Override
method create (line 129) | @Override
method order (line 134) | @Override
method init (line 141) | @Override
method postInit (line 146) | @Override
method close (line 151) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/oauth/tokenexchange/CustomTokenExchangeProvider.java
class CustomTokenExchangeProvider (line 23) | @JBossLog
method exchangeClientToClient (line 32) | @Override
method exchangeExternalToken (line 37) | @Override
method exchangeToIdentityProvider (line 42) | @Override
method unsupportedResponse (line 64) | private Response unsupportedResponse() {
method supports (line 68) | @Override
method close (line 77) | @Override
class Factory (line 82) | @AutoService(TokenExchangeProviderFactory.class)
method getId (line 87) | @Override
method create (line 92) | @Override
method order (line 97) | @Override
method init (line 104) | @Override
method postInit (line 109) | @Override
method close (line 114) | @Override
method isSupported (line 119) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/oauth/tokenexchange/CustomV2TokenExchangeProvider.java
class CustomV2TokenExchangeProvider (line 18) | @JBossLog
method exchangeClientToOIDCClient (line 21) | @Override
class Factory (line 27) | public static class Factory extends StandardTokenExchangeProviderFacto...
method create (line 29) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/oidc/ageinfo/AgeInfoMapper.java
class AgeInfoMapper (line 26) | @AutoService(ProtocolMapper.class)
method getId (line 43) | @Override
method getDisplayType (line 48) | @Override
method getHelpText (line 53) | @Override
method getDisplayCategory (line 58) | @Override
method getConfigProperties (line 63) | @Override
method setClaim (line 68) | @Override
method computeAgeClass (line 78) | @VisibleForTesting
method parseLocalDate (line 106) | private LocalDate parseLocalDate(String maybeLocalDate) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/oidc/authzenclaims/AuthzenClaimMapper.java
class AuthzenClaimMapper (line 30) | @JBossLog
method getId (line 152) | @Override
method getDisplayType (line 157) | @Override
method getHelpText (line 162) | @Override
method getDisplayCategory (line 167) | @Override
method getConfigProperties (line 172) | @Override
method setClaim (line 177) | @Override
method copyAccessResultToClaim (line 214) | protected void copyAccessResultToClaim(IDToken token, MapConfig config...
method copySearchResultToClaim (line 218) | protected void copySearchResultToClaim(IDToken token, MapConfig config...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/oidc/opaclaims/OpaClaimMapper.java
class OpaClaimMapper (line 26) | @JBossLog
method getId (line 134) | @Override
method getDisplayType (line 139) | @Override
method getHelpText (line 144) | @Override
method getDisplayCategory (line 149) | @Override
method getConfigProperties (line 154) | @Override
method setClaim (line 159) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/oidc/remoteclaims/RemoteOidcMapper.java
class RemoteOidcMapper (line 57) | @JBossLog
method getDisplayCategory (line 113) | @Override
method getDisplayType (line 118) | @Override
method getHelpText (line 123) | @Override
method getConfigProperties (line 128) | @Override
method getId (line 133) | @Override
method setClaim (line 138) | @Override
method copyClaimsToRoot (line 184) | private boolean copyClaimsToRoot(Object claimValue, String claimName) {
method fetchRemoteClaims (line 188) | private Object fetchRemoteClaims(ProtocolMapperModel mappingModel, Use...
method createInternalAccessToken (line 215) | private String createInternalAccessToken(UserSessionModel userSession,...
method createUri (line 222) | protected String createUri(ProtocolMapperModel mappingModel, UserSessi...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/oidc/scopes/OnlyGrantedScopesMapper.java
class OnlyGrantedScopesMapper (line 24) | @AutoService(ProtocolMapper.class)
method getDisplayCategory (line 39) | @Override
method getDisplayType (line 44) | @Override
method getHelpText (line 49) | @Override
method getConfigProperties (line 54) | @Override
method getId (line 59) | @Override
method setClaim (line 64) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/oidc/userdata/AcmeUserInfoMapper.java
class AcmeUserInfoMapper (line 21) | @JBossLog
method getDisplayCategory (line 36) | @Override
method getDisplayType (line 41) | @Override
method getHelpText (line 46) | @Override
method getConfigProperties (line 51) | @Override
method getId (line 56) | @Override
method setClaim (line 61) | protected void setClaim(IDToken token, ProtocolMapperModel mappingMode...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/oidc/wellknown/AcmeOidcWellKnownProvider.java
class AcmeOidcWellKnownProvider (line 17) | public class AcmeOidcWellKnownProvider implements WellKnownProvider {
method AcmeOidcWellKnownProvider (line 22) | public AcmeOidcWellKnownProvider(KeycloakSession session, OIDCWellKnow...
method getConfig (line 27) | @Override
method close (line 56) | @Override
class Factory (line 65) | @AutoService(WellKnownProviderFactory.class)
method create (line 68) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/profile/AcmeUserAttributes.java
type AcmeUserAttributes (line 3) | public enum AcmeUserAttributes {
method AcmeUserAttributes (line 11) | AcmeUserAttributes(String name) {
method getAttributeName (line 15) | public String getAttributeName() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/profile/emailupdate/UpdateEmailRequiredAction.java
class UpdateEmailRequiredAction (line 37) | @JBossLog
method initiatedActionSupport (line 50) | @Override
method evaluateTriggers (line 56) | @Override
method requiredActionChallenge (line 72) | @Override
method createForm (line 79) | protected Response createForm(RequiredActionContext context, Consumer<...
method processAction (line 100) | @Override
method close (line 225) | @Override
class Factory (line 231) | @AutoService(RequiredActionFactory.class)
method create (line 236) | @Override
method init (line 241) | @Override
method postInit (line 246) | @Override
method close (line 251) | @Override
method getId (line 256) | @Override
method getDisplayText (line 261) | @Override
method isOneTimeAction (line 266) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/profile/phonenumber/AcmePhoneValidator.java
class AcmePhoneValidator (line 15) | @AutoService(ValidatorFactory.class)
method getId (line 51) | @Override
method getHelpText (line 56) | @Override
method getConfigProperties (line 61) | @Override
method doValidate (line 66) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/registration/actiontokens/AcmeExecuteActionsActionTokenHandler.java
class AcmeExecuteActionsActionTokenHandler (line 15) | @AutoService(ActionTokenHandlerFactory.class)
method startFreshAuthenticationSession (line 18) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/registration/formaction/CustomRegistrationUserCreation.java
class CustomRegistrationUserCreation (line 24) | @AutoService(FormActionFactory.class)
method getId (line 34) | @Override
method getDisplayType (line 39) | @Override
method validate (line 44) | @Override
method success (line 63) | @Override
method buildPage (line 69) | @Override
method addCustomDynamicProfileFields (line 77) | private void addCustomDynamicProfileFields(FormContext context, LoginF...
class CustomProfile (line 105) | public static class CustomProfile {
method CustomProfile (line 109) | public CustomProfile(UserProfileMetadata profileMetadata) {
method createAttributes (line 113) | private List<CustomAttribute> createAttributes(UserProfileMetadata p...
method getAttributes (line 124) | public List<CustomAttribute> getAttributes() {
class CustomAttribute (line 129) | public static class CustomAttribute {
method CustomAttribute (line 137) | public CustomAttribute(AttributeMetadata attributeMetadata, String v...
method getName (line 143) | public String getName() {
method getDisplayName (line 147) | public String getDisplayName() {
method isRequired (line 151) | public boolean isRequired() {
method isReadOnly (line 155) | public boolean isReadOnly() {
method getAutocomplete (line 159) | public String getAutocomplete() {
method getValue (line 163) | public String getValue() {
method getAnnotations (line 167) | public Map<String, Object> getAnnotations() {
method getGroup (line 171) | public String getGroup() {
method getGroupDisplayHeader (line 175) | public String getGroupDisplayHeader() {
method getGroupDisplayDescription (line 179) | public String getGroupDisplayDescription() {
method getGroupAnnotations (line 183) | public Map<String, Object> getGroupAnnotations() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/registration/formaction/WelcomeEmailFormAction.java
class WelcomeEmailFormAction (line 29) | @JBossLog
method buildPage (line 32) | @Override
method validate (line 37) | @Override
method success (line 42) | @Override
method getUserDisplayName (line 73) | private String getUserDisplayName(UserModel user) {
method requiresUser (line 85) | @Override
method configuredFor (line 91) | @Override
method setRequiredActions (line 96) | @Override
method close (line 101) | @Override
class Factory (line 106) | @AutoService(FormActionFactory.class)
method getId (line 113) | @Override
method getDisplayType (line 118) | @Override
method getHelpText (line 123) | @Override
method getReferenceCategory (line 128) | @Override
method isConfigurable (line 133) | @Override
method getRequirementChoices (line 138) | @Override
method isUserSetupAllowed (line 143) | @Override
method getConfigProperties (line 148) | @Override
method create (line 153) | @Override
method init (line 158) | @Override
method postInit (line 163) | @Override
method close (line 168) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/saml/AcmeSamlAuthenticationPreprocessor.java
class AcmeSamlAuthenticationPreprocessor (line 18) | @AutoService(SamlAuthenticationPreprocessor.class)
method getId (line 21) | @Override
method beforeProcessingLoginRequest (line 26) | @Override
method beforeProcessingLogoutRequest (line 31) | @Override
method beforeSendingLoginRequest (line 36) | @Override
method beforeSendingLogoutRequest (line 41) | @Override
method beforeProcessingLoginResponse (line 46) | @Override
method beforeSendingResponse (line 51) | @Override
method create (line 56) | @Override
method init (line 61) | @Override
method postInit (line 66) | @Override
method close (line 71) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/saml/brokering/AcmeSamlRoleImporter.java
class AcmeSamlRoleImporter (line 28) | @AutoService(IdentityProviderMapper.class)
method supportsSyncMode (line 72) | @Override
method getConfigProperties (line 77) | @Override
method getId (line 82) | @Override
method getCompatibleProviders (line 87) | @Override
method getDisplayCategory (line 92) | @Override
method getDisplayType (line 97) | @Override
method getHelpText (line 102) | @Override
method importNewUser (line 107) | @Override
method getRolesForUser (line 117) | private List<RoleModel> getRolesForUser(BrokeredIdentityContext contex...
method updateBrokeredUser (line 176) | @Override
method applies (line 199) | protected boolean applies(final IdentityProviderMapperModel mapperMode...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/saml/rolelist/AcmeSamlRoleListMapper.java
class AcmeSamlRoleListMapper (line 27) | @AutoService(ProtocolMapper.class)
method getDisplayCategory (line 87) | @Override
method getDisplayType (line 92) | @Override
method getHelpText (line 97) | @Override
method getConfigProperties (line 102) | @Override
method getId (line 107) | @Override
method transformAttributeStatement (line 112) | @Override
method create (line 158) | public static ProtocolMapperModel create(String name, String samlAttri...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/scheduling/ScheduledTaskProvider.java
type ScheduledTaskProvider (line 6) | public interface ScheduledTaskProvider extends Provider {
method getScheduledTask (line 8) | ScheduledTask getScheduledTask();
method getInterval (line 10) | long getInterval();
method getTaskName (line 12) | String getTaskName();
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/scheduling/ScheduledTaskProviderFactory.java
class ScheduledTaskProviderFactory (line 9) | @JBossLog
method postInit (line 14) | @Override
method close (line 28) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/scheduling/ScheduledTaskSpi.java
class ScheduledTaskSpi (line 8) | @AutoService(Spi.class)
method isInternal (line 11) | @Override
method getName (line 16) | @Override
method getProviderClass (line 21) | @Override
method getProviderFactoryClass (line 26) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/scheduling/tasks/AcmeScheduledTaskProvider.java
class AcmeScheduledTaskProvider (line 17) | @JBossLog
method getScheduledTask (line 25) | @Override
method getInterval (line 44) | @Override
method getTaskName (line 49) | @Override
method close (line 54) | @Override
class Factory (line 59) | @AutoService(ScheduledTaskProviderFactory.class)
method getId (line 66) | @Override
method create (line 71) | @Override
method init (line 76) | @Override
method getOperationalInfo (line 82) | @Override
method isSupported (line 93) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/security/filter/IpAccessFilter.java
class IpAccessFilter (line 26) | @JBossLog
method IpAccessFilter (line 41) | public IpAccessFilter() {
method createAdminIpFilterRules (line 45) | private PathIpFilterRules createAdminIpFilterRules(Config config) {
method makeContextPath (line 74) | private String makeContextPath(String contextPath, String subPath) {
method filter (line 81) | @Override
method isAdminRequestAllowed (line 99) | private boolean isAdminRequestAllowed() {
class PathIpFilterRules (line 112) | @Data
method toString (line 121) | public String toString() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/security/friendlycaptcha/FriendlyCaptcha.java
class FriendlyCaptcha (line 14) | @Getter
method FriendlyCaptcha (line 25) | public FriendlyCaptcha(KeycloakSession session, FriendlyCaptchaConfig ...
method FriendlyCaptcha (line 30) | public FriendlyCaptcha(KeycloakSession session) {
method configureForm (line 35) | public void configureForm(LoginFormsProvider form, Locale locale) {
method isEnabled (line 45) | public boolean isEnabled() {
method verifySolution (line 49) | public boolean verifySolution(String solutionValue) {
method verifySolution (line 53) | public VerificationResult verifySolution(MultivaluedMap<String, String...
class VerificationResult (line 69) | @Data
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/security/friendlycaptcha/FriendlyCaptchaClient.java
class FriendlyCaptchaClient (line 14) | @JBossLog
method FriendlyCaptchaClient (line 21) | public FriendlyCaptchaClient(KeycloakSession session, FriendlyCaptchaC...
method verifySolution (line 26) | public boolean verifySolution(String solutionValue) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/security/friendlycaptcha/FriendlyCaptchaConfig.java
class FriendlyCaptchaConfig (line 6) | public class FriendlyCaptchaConfig extends RealmConfig {
method FriendlyCaptchaConfig (line 10) | public FriendlyCaptchaConfig(RealmModel realm) {
method getSiteKey (line 14) | public String getSiteKey() {
method getSolutionFieldName (line 18) | public String getSolutionFieldName() {
method getSecret (line 22) | public String getSecret() {
method getStart (line 26) | public String getStart() {
method isEnabled (line 30) | public boolean isEnabled() {
method getSourceModule (line 34) | public String getSourceModule() {
method getSourceNoModule (line 38) | public String getSourceNoModule() {
method getUrl (line 42) | public String getUrl() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/security/friendlycaptcha/FriendlyCaptchaFormAction.java
class FriendlyCaptchaFormAction (line 24) | @JBossLog
method buildPage (line 27) | @Override
method validate (line 35) | @Override
method success (line 55) | @Override
method requiresUser (line 60) | @Override
method configuredFor (line 65) | @Override
method setRequiredActions (line 70) | @Override
method close (line 75) | @Override
class Factory (line 80) | @AutoService(FormActionFactory.class)
method getId (line 87) | @Override
method getDisplayType (line 92) | @Override
method getHelpText (line 97) | @Override
method getReferenceCategory (line 102) | @Override
method isConfigurable (line 107) | @Override
method getRequirementChoices (line 112) | @Override
method isUserSetupAllowed (line 117) | @Override
method getConfigProperties (line 122) | @Override
method create (line 127) | @Override
method init (line 132) | @Override
method postInit (line 137) | @Override
method close (line 142) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/support/AuthUtils.java
class AuthUtils (line 12) | public class AuthUtils {
method getAdminPermissionEvaluator (line 14) | public static AdminPermissionEvaluator getAdminPermissionEvaluator(Key...
method getAdminAuth (line 18) | public static AdminAuth getAdminAuth(KeycloakSession session) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/support/ConfigUtils.java
class ConfigUtils (line 7) | public class ConfigUtils {
method getConfig (line 9) | public static Map<String, String> getConfig(AuthenticatorConfigModel c...
method getConfigValue (line 23) | public static String getConfigValue(AuthenticatorConfigModel configMod...
method getConfigValue (line 32) | public static String getConfigValue(Map<String, String> config, String...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/support/CookieHelper.java
class CookieHelper (line 10) | public class CookieHelper {
method addCookie (line 26) | public static void addCookie(String name, String value, String path, S...
method addCookie (line 67) | public static void addCookie(String name, String value, String path, S...
method getCookieValue (line 71) | public static String getCookieValue(KeycloakSession session, String na...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/support/CookieUtils.java
class CookieUtils (line 11) | public class CookieUtils {
method parseCookie (line 13) | public static String parseCookie(String cookieName, HttpRequest httpRe...
method addCookie (line 21) | public static void addCookie(String cookieName, String cookieValue, Ke...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/support/CredentialUtils.java
class CredentialUtils (line 9) | public class CredentialUtils {
method findFirstOtpCredential (line 11) | public static Optional<CredentialModel> findFirstOtpCredential(UserMod...
method findFirstCredentialOfType (line 15) | public static Optional<CredentialModel> findFirstCredentialOfType(User...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/support/LocaleUtils.java
class LocaleUtils (line 8) | public class LocaleUtils {
method extractLocaleWithFallbackToRealmLocale (line 10) | public static Locale extractLocaleWithFallbackToRealmLocale(HttpReques...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/support/RealmUtils.java
class RealmUtils (line 5) | public class RealmUtils {
method getDisplayName (line 7) | public static String getDisplayName(RealmModel realm) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/support/RequiredActionUtils.java
class RequiredActionUtils (line 12) | public class RequiredActionUtils {
method isCancelApplicationInitiatedAction (line 14) | public static boolean isCancelApplicationInitiatedAction(RequiredActio...
method cancelApplicationInitiatedAction (line 21) | public static void cancelApplicationInitiatedAction(RequiredActionCont...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/support/ScopeUtils.java
class ScopeUtils (line 5) | public class ScopeUtils {
method hasScope (line 9) | public static boolean hasScope(String requiredScope, String scopeParam) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/support/TokenUtils.java
class TokenUtils (line 28) | public class TokenUtils {
method generateServiceAccountAccessToken (line 39) | public static String generateServiceAccountAccessToken(KeycloakSession...
method generateAccessToken (line 99) | public static String generateAccessToken(KeycloakSession session, User...
method generateAccessToken (line 140) | public static String generateAccessToken(KeycloakSession session, Real...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/support/UserSessionUtils.java
class UserSessionUtils (line 7) | public class UserSessionUtils {
method getUserSessionFromAuthenticationSession (line 9) | public static UserSessionModel getUserSessionFromAuthenticationSession...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/support/UserUtils.java
class UserUtils (line 5) | public class UserUtils {
method deriveDisplayName (line 7) | public static String deriveDisplayName(UserModel user) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/terms/AcmeTermsAndConditionsAction.java
class AcmeTermsAndConditionsAction (line 16) | @AutoService(RequiredActionFactory.class)
method create (line 31) | @Override
method init (line 36) | @Override
method postInit (line 41) | @Override
method getId (line 46) | @Override
method evaluateTriggers (line 52) | @Override
method hasUserAcceptedCurrentTerms (line 62) | private boolean hasUserAcceptedCurrentTerms(RequiredActionContext cont...
method getActiveTermsId (line 69) | private String getActiveTermsId() {
method requiredActionChallenge (line 74) | @Override
method processAction (line 82) | @Override
method getDisplayText (line 97) | @Override
method close (line 102) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/themes/login/AcmeFreeMarkerLoginFormsProvider.java
class AcmeFreeMarkerLoginFormsProvider (line 22) | @JBossLog
method AcmeFreeMarkerLoginFormsProvider (line 25) | public AcmeFreeMarkerLoginFormsProvider(KeycloakSession session) {
method processTemplate (line 29) | @Override
class Factory (line 47) | @AutoService(LoginFormsProviderFactory.class)
method create (line 50) | @Override
method init (line 55) | @Override
method postInit (line 60) | @Override
method close (line 65) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/themes/login/AcmeLoginBean.java
class AcmeLoginBean (line 19) | public class AcmeLoginBean {
method AcmeLoginBean (line 24) | public AcmeLoginBean(KeycloakSession session, AuthenticationContextBea...
method getAuthenticationSelections (line 35) | public List<AuthenticationSelectionOption> getAuthenticationSelections...
method narrowUserAuthenticationOptions (line 39) | private List<AuthenticationSelectionOption> narrowUserAuthenticationOp...
method getPasswordPolicy (line 65) | public String getPasswordPolicy() {
method getLastProcessedAction (line 73) | public String getLastProcessedAction() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/themes/login/AcmeUrlBean.java
class AcmeUrlBean (line 11) | public class AcmeUrlBean {
method AcmeUrlBean (line 31) | public AcmeUrlBean(KeycloakSession session) {
method AcmeUrlBean (line 35) | public AcmeUrlBean(KeycloakSession session, ClientBean clientBean) {
method getSiteUrl (line 49) | public String getSiteUrl() {
method getTermsUrl (line 53) | public String getTermsUrl() {
method getPrivacyUrl (line 58) | public String getPrivacyUrl() {
method getImprintUrl (line 63) | public String getImprintUrl() {
method getLogoUrl (line 68) | public String getLogoUrl() {
method getAccountDeletedUrl (line 73) | public String getAccountDeletedUrl() {
method clientAttribute (line 82) | private Optional<String> clientAttribute(String key) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/userstorage/adhoc/AdhocUserStorageProvider.java
class AdhocUserStorageProvider (line 33) | @JBossLog
method AdhocUserStorageProvider (line 48) | public AdhocUserStorageProvider(KeycloakSession session, ComponentMode...
method close (line 53) | @Override
method getUserById (line 58) | @Override
method getUserByUsername (line 64) | @Override
method getUserByEmail (line 94) | @Override
method supportsCredentialType (line 99) | @Override
method isConfiguredFor (line 104) | @Override
method isValid (line 109) | @Override
method addUser (line 117) | @Override
method removeUser (line 127) | @Override
method sync (line 134) | @Override
method syncSince (line 139) | @Override
method validate (line 144) | @Override
class Factory (line 151) | @SuppressWarnings("rawtypes")
method getId (line 155) | @Override
method getHelpText (line 160) | @Override
method create (line 165) | @Override
method create (line 171) | @Override
method getConfigProperties (line 176) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/userstorage/ldap/AcmeLDAPStorageProvider.java
class AcmeLDAPStorageProvider (line 24) | public class AcmeLDAPStorageProvider extends LDAPStorageProvider {
method AcmeLDAPStorageProvider (line 28) | public AcmeLDAPStorageProvider(LDAPStorageProviderFactory factory, Key...
method proxy (line 33) | @Override
class Factory (line 39) | @JBossLog
method init (line 47) | @Override
method create (line 55) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/userstorage/ldap/AcmeReadonlyLDAPUserModelDelegate.java
class AcmeReadonlyLDAPUserModelDelegate (line 11) | public class AcmeReadonlyLDAPUserModelDelegate extends ReadonlyLDAPUserM...
method AcmeReadonlyLDAPUserModelDelegate (line 15) | public AcmeReadonlyLDAPUserModelDelegate(UserModel delegate, Pattern l...
method setAttribute (line 20) | @Override
method removeAttribute (line 32) | @Override
method getRootDelegate (line 50) | private UserModel getRootDelegate(UserModel delegate) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/userstorage/remote/AcmeUserAdapter.java
class AcmeUserAdapter (line 12) | public class AcmeUserAdapter extends InMemoryUserAdapter {
method AcmeUserAdapter (line 14) | public AcmeUserAdapter(KeycloakSession session, RealmModel realm, Stri...
method getFederatedStorage (line 24) | public UserFederatedStorageProvider getFederatedStorage() {
method addRequiredAction (line 28) | @Override
method addRequiredAction (line 34) | @Override
method removeRequiredAction (line 39) | @Override
method removeRequiredAction (line 45) | @Override
method getRequiredActionsStream (line 50) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/userstorage/remote/AcmeUserStorageProvider.java
class AcmeUserStorageProvider (line 47) | @JBossLog
method close (line 76) | @Override
method getUserById (line 81) | @Override
method getUserByUsername (line 91) | @Override
method getUserByEmail (line 97) | @Override
method wrap (line 103) | private AcmeUserAdapter wrap(RealmModel realm, AcmeUser acmeUser) {
method supportsCredentialType (line 119) | public boolean supportsCredentialType(String credentialType) {
method isConfiguredFor (line 124) | public boolean isConfiguredFor(RealmModel realm, UserModel user, Strin...
method isValid (line 129) | public boolean isValid(RealmModel realm, UserModel user, CredentialInp...
method addUser (line 135) | @Override
method removeUser (line 140) | @Override
method getUsersCount (line 147) | public int getUsersCount(RealmModel realm, Map<String, String> params) {
method searchForUserStream (line 164) | @Override
method getGroupMembersStream (line 181) | @Override
method searchForUserByUserAttributeStream (line 186) | @Override
method sync (line 193) | @Override
method syncSince (line 201) | @Override
class Factory (line 206) | @AutoService(UserStorageProviderFactory.class)
method getId (line 209) | @Override
method getHelpText (line 214) | @Override
method create (line 219) | @Override
method getConfigProperties (line 232) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/userstorage/remote/accountclient/AccountClientOptions.java
class AccountClientOptions (line 6) | @Data
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/userstorage/remote/accountclient/AcmeAccountClient.java
type AcmeAccountClient (line 3) | public interface AcmeAccountClient {
method getUserByUsername (line 5) | AcmeUser getUserByUsername(String username);
method getUserByEmail (line 7) | AcmeUser getUserByEmail(String email);
method getUserById (line 9) | AcmeUser getUserById(String userId);
method verifyCredentials (line 11) | VerifyCredentialsOutput verifyCredentials(String userId, VerifyCredent...
method searchForUsers (line 13) | UserSearchOutput searchForUsers(UserSearchInput userSearchInput);
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/userstorage/remote/accountclient/AcmeUser.java
class AcmeUser (line 8) | @Data
method AcmeUser (line 22) | public AcmeUser(String id, String username, String email, boolean emai...
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/userstorage/remote/accountclient/SimpleAcmeAccountClient.java
class SimpleAcmeAccountClient (line 12) | @JBossLog
method getUserByUsername (line 20) | @Override
method createHttpClient (line 34) | protected SimpleHttp createHttpClient(KeycloakSession session) {
method getUserByEmail (line 45) | @Override
method getUserById (line 58) | @Override
method verifyCredentials (line 70) | @Override
method searchForUsers (line 83) | @Override
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/userstorage/remote/accountclient/UserSearchInput.java
class UserSearchInput (line 7) | @Data
method UserSearchInput (line 18) | public UserSearchInput(String search, Integer firstResult, Integer max...
type UserSearchOptions (line 25) | public enum UserSearchOptions {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/userstorage/remote/accountclient/UserSearchOutput.java
class UserSearchOutput (line 5) | public class UserSearchOutput {
method getUsers (line 11) | public List<AcmeUser> getUsers() {
method getCount (line 15) | public int getCount() {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/userstorage/remote/accountclient/VerifyCredentialsInput.java
class VerifyCredentialsInput (line 6) | @Data
method VerifyCredentialsInput (line 11) | public VerifyCredentialsInput(String password) {
FILE: keycloak/extensions/src/main/java/com/github/thomasdarimont/keycloak/custom/userstorage/remote/accountclient/VerifyCredentialsOutput.java
class VerifyCredentialsOutput (line 6) | @Data
method VerifyCredentialsOutput (line 12) | public VerifyCredentialsOutput(boolean valid) {
FILE: keycloak/extensions/src/main/resources/my-script-authenticator.js
function authenticate (line 3) | function authenticate(context) {
FILE: keycloak/extensions/src/test/java/com/github/thomasdarimont/keycloak/custom/BoostrapTest.java
class BoostrapTest (line 6) | public class BoostrapTest {
method shouldRunAsUnitTest (line 8) | @Test
FILE: keycloak/extensions/src/test/java/com/github/thomasdarimont/keycloak/custom/KeycloakEnvironment.java
class KeycloakEnvironment (line 10) | @Slf4j
method local (line 27) | public KeycloakEnvironment local() {
method custom (line 34) | public KeycloakEnvironment custom(String authServerUrl, String adminUs...
method start (line 44) | public void start() {
method stop (line 71) | public void stop() {
method getKeycloak (line 81) | public KeycloakContainer getKeycloak() {
method getKeycloakConfigCli (line 85) | public GenericContainer<?> getKeycloakConfigCli() {
method getAdminClient (line 89) | public Keycloak getAdminClient() {
method getTokenService (line 93) | public TokenService getTokenService() {
method getClientProxy (line 97) | public <T> T getClientProxy(Class<T> iface) {
method getAuthServerUrl (line 101) | public String getAuthServerUrl() {
method setAuthServerUrl (line 105) | public KeycloakEnvironment setAuthServerUrl(String authServerUrl) {
method getAdminUsername (line 110) | public String getAdminUsername() {
method setAdminUsername (line 114) | public KeycloakEnvironment setAdminUsername(String adminUsername) {
method getAdminPassword (line 119) | public String getAdminPassword() {
method setAdminPassword (line 123) | public KeycloakEnvironment setAdminPassword(String adminPassword) {
method getMode (line 128) | public Mode getMode() {
method setMode (line 132) | public void setMode(Mode mode) {
method isRunConfigCli (line 136) | public boolean isRunConfigCli() {
method setRunConfigCli (line 140) | public void setRunConfigCli(boolean runConfigCli) {
type Mode (line 144) | enum Mode {
FILE: keycloak/extensions/src/test/java/com/github/thomasdarimont/keycloak/custom/KeycloakIntegrationTest.java
class KeycloakIntegrationTest (line 31) | @Slf4j
method beforeAll (line 42) | @BeforeAll
method afterAll (line 47) | @AfterAll
method ageInfoMapperShouldAddAgeClassClaim (line 52) | @Test
method auditListenerShouldPrintLogMessage (line 89) | @Test
method pingResourceShouldBeAccessibleForUser (line 114) | @Test
type CustomResources (line 139) | interface CustomResources {
method ping (line 141) | @GET
FILE: keycloak/extensions/src/test/java/com/github/thomasdarimont/keycloak/custom/KeycloakTestSupport.java
class KeycloakTestSupport (line 31) | @Slf4j
method createKeycloakContainer (line 40) | public static KeycloakContainer createKeycloakContainer() {
method createKeycloakContainer (line 44) | public static KeycloakContainer createKeycloakContainer(String realmIm...
method createKeycloakContainer (line 48) | public static KeycloakContainer createKeycloakContainer(String imageNa...
method getResteasyWebTarget (line 68) | public static ResteasyWebTarget getResteasyWebTarget(KeycloakContainer...
method createOrUpdateTestUser (line 73) | public static UserRef createOrUpdateTestUser(RealmResource realm, Stri...
method createKeycloakConfigCliContainer (line 104) | public static GenericContainer<?> createKeycloakConfigCliContainer(Key...
class UserRef (line 131) | @Data
class CustomKeycloak (line 138) | @Getter
method start (line 147) | public void start() {
method followOutput (line 151) | @Override
FILE: keycloak/misc/custom-keycloak-server/src/main/java/demo/events/MyEventListener.java
class MyEventListener (line 12) | @AutoService(EventListenerProviderFactory.class)
method getId (line 15) | @Override
method onEvent (line 20) | @Override
method onEvent (line 25) | @Override
method create (line 30) | @Override
method init (line 35) | @Override
method postInit (line 39) | @Override
method close (line 43) | @Override
FILE: keycloak/patches/keycloak-model-infinispan-patch/src/main/java/org/keycloak/models/sessions/infinispan/CacheDecorators.java
class CacheDecorators (line 7) | public class CacheDecorators {
method CacheDecorators (line 12) | public CacheDecorators() {
method localCache (line 15) | public static <K, V> AdvancedCache<K, V> localCache(Cache<K, V> cache) {
method skipCacheLoaders (line 19) | public static <K, V> AdvancedCache<K, V> skipCacheLoaders(Cache<K, V> ...
method skipCacheStore (line 23) | public static <K, V> AdvancedCache<K, V> skipCacheStore(Cache<K, V> ca...
FILE: keycloak/patches/keycloak-model-infinispan-patch/src/main/java/org/keycloak/patch/infinispan/keymappers/CustomDefaultTwoWayKey2StringMapper.java
class CustomDefaultTwoWayKey2StringMapper (line 17) | public class CustomDefaultTwoWayKey2StringMapper implements TwoWayKey2St...
method getStringMapping (line 35) | @Override
method getKeyMapping (line 70) | @Override
method isSupportedType (line 108) | @Override
method generateString (line 113) | private String generateString(char identifier, String s) {
method isPrimitive (line 117) | private static boolean isPrimitive(Class<?> key) {
FILE: keycloak/patches/wildfly-clustering-infinispan-extension-patch-25.0.x/src/main/java/org/jboss/as/clustering/infinispan/subsystem/InfinispanSubsystemXMLReader.java
class InfinispanSubsystemXMLReader (line 64) | @SuppressWarnings({ "deprecation", "static-method" })
method InfinispanSubsystemXMLReader (line 69) | InfinispanSubsystemXMLReader(InfinispanSchema schema) {
method readElement (line 73) | @Override
method parseContainer (line 104) | private void parseContainer(XMLExtendedStreamReader reader, PathAddres...
method parseTransport (line 313) | private void parseTransport(XMLExtendedStreamReader reader, PathAddres...
method parseLocalCache (line 400) | private void parseLocalCache(XMLExtendedStreamReader reader, PathAddre...
method parseReplicatedCache (line 416) | private void parseReplicatedCache(XMLExtendedStreamReader reader, Path...
method parseScatteredCache (line 432) | private void parseScatteredCache(XMLExtendedStreamReader reader, PathA...
method parseDistributedCache (line 461) | private void parseDistributedCache(XMLExtendedStreamReader reader, Pat...
method parseInvalidationCache (line 519) | private void parseInvalidationCache(XMLExtendedStreamReader reader, Pa...
method parseCacheAttribute (line 535) | private void parseCacheAttribute(XMLExtendedStreamReader reader, int i...
method parseSegmentedCacheAttribute (line 608) | private void parseSegmentedCacheAttribute(XMLExtendedStreamReader read...
method parseClusteredCacheAttribute (line 630) | private void parseClusteredCacheAttribute(XMLExtendedStreamReader read...
method parseCacheElement (line 665) | private void parseCacheElement(XMLExtendedStreamReader reader, PathAdd...
method parseSharedStateCacheElement (line 780) | private void parseSharedStateCacheElement(XMLExtendedStreamReader read...
method parsePartitionHandling (line 812) | private void parsePartitionHandling(XMLExtendedStreamReader reader, Pa...
method parseStateTransfer (line 833) | private void parseStateTransfer(XMLExtendedStreamReader reader, PathAd...
method parseBackups (line 874) | private void parseBackups(XMLExtendedStreamReader reader, PathAddress ...
method parseBackup (line 894) | private void parseBackup(XMLExtendedStreamReader reader, PathAddress b...
method parseBackupFor (line 960) | private void parseBackupFor(XMLExtendedStreamReader reader, PathAddres...
method parseLocking (line 984) | private void parseLocking(XMLExtendedStreamReader reader, PathAddress ...
method parseTransaction (line 1017) | private void parseTransaction(XMLExtendedStreamReader reader, PathAddr...
method parseEviction (line 1062) | private void parseEviction(XMLExtendedStreamReader reader, PathAddress...
method parseExpiration (line 1094) | private void parseExpiration(XMLExtendedStreamReader reader, PathAddre...
method parseIndexing (line 1123) | private void parseIndexing(XMLExtendedStreamReader reader, PathAddress...
method parseHeapMemory (line 1155) | private void parseHeapMemory(XMLExtendedStreamReader reader, PathAddre...
method parseBinaryMemory (line 1178) | private void parseBinaryMemory(XMLExtendedStreamReader reader, PathAdd...
method parseOffHeapMemory (line 1190) | private void parseOffHeapMemory(XMLExtendedStreamReader reader, PathAd...
method parseBinaryMemoryAttribute (line 1217) | private void parseBinaryMemoryAttribute(XMLExtendedStreamReader reader...
method parseMemoryAttribute (line 1231) | private void parseMemoryAttribute(XMLExtendedStreamReader reader, int ...
method parseCustomStore (line 1245) | private void parseCustomStore(XMLExtendedStreamReader reader, PathAddr...
method parseFileStore (line 1277) | private void parseFileStore(XMLExtendedStreamReader reader, PathAddres...
method parseRemoteStore (line 1309) | private void parseRemoteStore(XMLExtendedStreamReader reader, PathAddr...
method parseHotRodStore (line 1385) | private void parseHotRodStore(XMLExtendedStreamReader reader, PathAddr...
method parseJDBCStore (line 1416) | private void parseJDBCStore(XMLExtendedStreamReader reader, PathAddres...
method parseLegacyJDBCStore (line 1442) | private void parseLegacyJDBCStore(XMLExtendedStreamReader reader, Path...
method parseBinaryKeyedJDBCStore (line 1499) | private void parseBinaryKeyedJDBCStore(XMLExtendedStreamReader reader,...
method parseStringKeyedJDBCStore (line 1525) | private void parseStringKeyedJDBCStore(XMLExtendedStreamReader reader,...
method parseMixedKeyedJDBCStore (line 1551) | private void parseMixedKeyedJDBCStore(XMLExtendedStreamReader reader, ...
method parseJDBCStoreAttributes (line 1581) | private void parseJDBCStoreAttributes(XMLExtendedStreamReader reader, ...
method parseJDBCStoreBinaryTable (line 1616) | private void parseJDBCStoreBinaryTable(XMLExtendedStreamReader reader,...
method parseJDBCStoreStringTable (line 1638) | private void parseJDBCStoreStringTable(XMLExtendedStreamReader reader,...
method parseJDBCStoreTableAttribute (line 1660) | private void parseJDBCStoreTableAttribute(XMLExtendedStreamReader read...
method parseJDBCStoreTableElements (line 1693) | private void parseJDBCStoreTableElements(XMLExtendedStreamReader reade...
method parseJDBCStoreColumn (line 1723) | private void parseJDBCStoreColumn(XMLExtendedStreamReader reader, Colu...
method removeStoreOperations (line 1743) | private void removeStoreOperations(PathAddress storeAddress, Map<PathA...
method parseStoreAttribute (line 1747) | private void parseStoreAttribute(XMLExtendedStreamReader reader, int i...
method parseStoreElement (line 1786) | private void parseStoreElement(XMLExtendedStreamReader reader, PathAdd...
method parseStoreWriteBehind (line 1808) | private void parseStoreWriteBehind(XMLExtendedStreamReader reader, Pat...
method parseThreadPool (line 1850) | private <P extends ThreadPoolDefinition & ResourceDefinitionProvider> ...
method parseScheduledThreadPool (line 1887) | private <P extends ScheduledThreadPoolDefinition & ResourceDefinitionP...
method parseRemoteContainer (line 1921) | private void parseRemoteContainer(XMLExtendedStreamReader reader, Path...
method parseInvalidationNearCache (line 2051) | private void parseInvalidationNearCache(XMLExtendedStreamReader reader...
method parseConnectionPool (line 2071) | private void parseConnectionPool(XMLExtendedStreamReader reader, PathA...
method parseRemoteClusters (line 2107) | private void parseRemoteClusters(XMLExtendedStreamReader reader, PathA...
method parseRemoteCluster (line 2124) | private void parseRemoteCluster(XMLExtendedStreamReader reader, PathAd...
method parseRemoteCacheContainerSecurity (line 2149) | private void parseRemoteCacheContainerSecurity(XMLExtendedStreamReader...
method parseRemoteTransaction (line 2169) | private void parseRemoteTransaction(XMLExtendedStreamReader reader, Pa...
method require (line 2196) | private static String require(XMLExtendedStreamReader reader, XMLAttri...
method readAttribute (line 2204) | private static ModelNode readAttribute(XMLExtendedStreamReader reader,...
method readAttribute (line 2209) | private static void readAttribute(XMLExtendedStreamReader reader, int ...
method setAttribute (line 2213) | private static void setAttribute(XMLExtendedStreamReader reader, Strin...
method readElement (line 2218) | private static void readElement(XMLExtendedStreamReader reader, ModelN...
FILE: keycloak/patches/wildfly-clustering-infinispan-extension-patch-25.0.x/src/main/java/org/jboss/as/clustering/infinispan/subsystem/RemoteStoreResourceDefinition.java
class RemoteStoreResourceDefinition (line 50) | @Deprecated
type Attribute (line 56) | enum Attribute implements org.jboss.as.clustering.controller.Attribute {
method Attribute (line 67) | Attribute(String name, ModelType type, ModelNode defaultValue) {
method Attribute (line 77) | Attribute(String name) {
method getDefinition (line 85) | @Override
method RemoteStoreResourceDefinition (line 91) | RemoteStoreResourceDefinition() {
method createServiceConfigurator (line 96) | @Override
FILE: keycloak/patches/wildfly-clustering-infinispan-extension-patch-25.0.x/src/main/java/org/jboss/as/clustering/infinispan/subsystem/RemoteStoreServiceConfigurator.java
class RemoteStoreServiceConfigurator (line 53) | @Deprecated
method RemoteStoreServiceConfigurator (line 65) | public RemoteStoreServiceConfigurator(PathAddress address) {
method register (line 69) | @Override
method configure (line 77) | @Override
method accept (line 91) | @Override
FILE: keycloak/patches/wildfly-clustering-infinispan-extension-patch-25.0.x/src/main/java/org/jboss/as/clustering/infinispan/subsystem/remote/RemoteCacheContainerResourceDefinition.java
class RemoteCacheContainerResourceDefinition (line 71) | public class RemoteCacheContainerResourceDefinition extends ChildResourc...
method pathElement (line 75) | public static PathElement pathElement(String containerName) {
type Capability (line 79) | public enum Capability implements CapabilityProvider {
method Capability (line 86) | Capability(UnaryRequirement requirement) {
method getCapability (line 90) | @Override
type Attribute (line 96) | public enum Attribute implements org.jboss.as.clustering.controller.At...
method apply (line 99) | @Override
method apply (line 105) | @Override
method apply (line 121) | @Override
method apply (line 131) | @Override
method Attribute (line 140) | Attribute(String name) {
method Attribute (line 147) | Attribute(String name, ModelType type, ModelNode defaultValue) {
method getDefinition (line 156) | @Override
method apply (line 161) | @Override
type ListAttribute (line 167) | public enum ListAttribute implements org.jboss.as.clustering.controlle...
method apply (line 169) | @Override
method ListAttribute (line 177) | ListAttribute(Str
Condensed preview — 914 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,561K chars).
[
{
"path": ".github/workflows/build.yml",
"chars": 1202,
"preview": "name: ACME Keycloak Build\n\non:\n push:\n branches: [ main ]\n pull_request:\n branches: [ main ]\n\njobs:\n build:\n "
},
{
"path": ".github/workflows/e2e-tests.yml",
"chars": 2531,
"preview": "name: Acme e2e Test CI\n\non:\n push:\n branches: [ main ]\n pull_request:\n branches: [ main ]\n\njobs:\n e2e-tests:\n "
},
{
"path": ".gitignore",
"chars": 7543,
"preview": "!testrun/.gitkeep\ntestrun/\n!run/.gitkeep\nrun/\ndeployments/local/dev/run/\n\ndeployments/local/cluster/haproxy-external-isp"
},
{
"path": ".run/Acme Backend API Quarkus.run.xml",
"chars": 1234,
"preview": "<component name=\"ProjectRunConfigurationManager\">\n <configuration default=\"false\" name=\"backend-api-quarkus\" type=\"Quar"
},
{
"path": ".run/Keycloak Remote.run.xml",
"chars": 632,
"preview": "<component name=\"ProjectRunConfigurationManager\">\n <configuration default=\"false\" name=\"Keycloak Remote\" type=\"Remote\">"
},
{
"path": ".run/OfflineSessionClient (logout).run.xml",
"chars": 699,
"preview": "<component name=\"ProjectRunConfigurationManager\">\n <configuration default=\"false\" name=\"OfflineSessionClient (logout)\" "
},
{
"path": ".run/OfflineSessionClient.run.xml",
"chars": 716,
"preview": "<component name=\"ProjectRunConfigurationManager\">\n <configuration default=\"false\" name=\"OfflineSessionClient\" type=\"Spr"
},
{
"path": ".run/acme-webapp-saml-node-express.run.xml",
"chars": 610,
"preview": "<component name=\"ProjectRunConfigurationManager\">\n <configuration default=\"false\" name=\"acme-webapp-saml-node-express\" "
},
{
"path": ".run/backend-api-micronaut.run.xml",
"chars": 809,
"preview": "<component name=\"ProjectRunConfigurationManager\">\n <configuration default=\"false\" name=\"backend-api-micronaut\" type=\"Mi"
},
{
"path": ".run/backend-api-springboot-reactive.run.xml",
"chars": 585,
"preview": "<component name=\"ProjectRunConfigurationManager\">\n <configuration default=\"false\" name=\"backend-api-springboot-reactive"
},
{
"path": ".run/backend-api-springboot.run.xml",
"chars": 556,
"preview": "<component name=\"ProjectRunConfigurationManager\">\n <configuration default=\"false\" name=\"backend-api-springboot\" type=\"S"
},
{
"path": ".run/backend-api-springboot3.run.xml",
"chars": 559,
"preview": "<component name=\"ProjectRunConfigurationManager\">\n <configuration default=\"false\" name=\"backend-api-springboot3\" type=\""
},
{
"path": ".run/frontend-webapp-springboot-otel.run.xml",
"chars": 1033,
"preview": "<component name=\"ProjectRunConfigurationManager\">\n <configuration default=\"false\" name=\"frontend-webapp-springboot-otel"
},
{
"path": ".run/frontend-webapp-springboot.run.xml",
"chars": 603,
"preview": "<component name=\"ProjectRunConfigurationManager\">\n <configuration default=\"false\" name=\"frontend-webapp-springboot\" t"
},
{
"path": ".run/frontend-webapp-springboot3.run.xml",
"chars": 745,
"preview": "<component name=\"ProjectRunConfigurationManager\">\n <configuration default=\"false\" name=\"frontend-webapp-springboot3\" ty"
},
{
"path": ".vscode/settings.json",
"chars": 52,
"preview": "{\n \"java.compile.nullAnalysis.mode\": \"disabled\"\n}"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": " Apache License\n Version 2.0, January 2004\n "
},
{
"path": "apps/account-svc/.dockerignore",
"chars": 75,
"preview": "*\n!target/*-runner\n!target/*-runner.jar\n!target/lib/*\n!target/quarkus-app/*"
},
{
"path": "apps/account-svc/.gitignore",
"chars": 396,
"preview": "#Maven\ntarget/\npom.xml.tag\npom.xml.releaseBackup\npom.xml.versionsBackup\nrelease.properties\n.flattened-pom.xml\n\n# Eclipse"
},
{
"path": "apps/account-svc/.mvn/wrapper/.gitignore",
"chars": 18,
"preview": "maven-wrapper.jar\n"
},
{
"path": "apps/account-svc/.mvn/wrapper/MavenWrapperDownloader.java",
"chars": 3174,
"preview": "/*\n * Licensed to the Apache Software Foundation (ASF) under one\n * or more contributor license agreements. See the NOT"
},
{
"path": "apps/account-svc/.mvn/wrapper/maven-wrapper.properties",
"chars": 1018,
"preview": "# Licensed to the Apache Software Foundation (ASF) under one\n# or more contributor license agreements. See the NOTICE f"
},
{
"path": "apps/account-svc/README.md",
"chars": 73,
"preview": "# account-svc\n\nMinimal quarkus backend for a custom remote user storage.\n"
},
{
"path": "apps/account-svc/mvnw",
"chars": 11289,
"preview": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Softwa"
},
{
"path": "apps/account-svc/mvnw.cmd",
"chars": 7591,
"preview": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software F"
},
{
"path": "apps/account-svc/pom.xml",
"chars": 4525,
"preview": "<?xml version=\"1.0\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-"
},
{
"path": "apps/account-svc/src/main/docker/Dockerfile.jvm",
"chars": 5416,
"preview": "####\n# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode\n#\n# Before bu"
},
{
"path": "apps/account-svc/src/main/docker/Dockerfile.legacy-jar",
"chars": 5225,
"preview": "####\n# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode\n#\n# Before bu"
},
{
"path": "apps/account-svc/src/main/docker/Dockerfile.native",
"chars": 690,
"preview": "####\n# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.\n"
},
{
"path": "apps/account-svc/src/main/docker/Dockerfile.native-micro",
"chars": 915,
"preview": "####\n# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode.\n"
},
{
"path": "apps/account-svc/src/main/java/com/thomasdarimont/keycloak/training/accounts/User.java",
"chars": 1146,
"preview": "package com.thomasdarimont.keycloak.training.accounts;\n\nimport com.fasterxml.jackson.annotation.JsonIgnore;\nimport lombo"
},
{
"path": "apps/account-svc/src/main/java/com/thomasdarimont/keycloak/training/accounts/UserRepository.java",
"chars": 6477,
"preview": "package com.thomasdarimont.keycloak.training.accounts;\n\nimport com.thomasdarimont.keycloak.training.accounts.UserResourc"
},
{
"path": "apps/account-svc/src/main/java/com/thomasdarimont/keycloak/training/accounts/UserResource.java",
"chars": 3117,
"preview": "package com.thomasdarimont.keycloak.training.accounts;\n\nimport jakarta.ws.rs.Consumes;\nimport jakarta.ws.rs.GET;\nimport "
},
{
"path": "apps/account-svc/src/main/resources/application.properties",
"chars": 223,
"preview": "quarkus.container-image.build=true \nquarkus.container-image.group=training\nquarkus.container-image.name=account-svc\nqua"
},
{
"path": "apps/acme-account-console/index.html",
"chars": 36846,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n\n <title>Acme Account Console</title>\n\n <style>"
},
{
"path": "apps/acme-greetme/index.html",
"chars": 9061,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n\n <title>App: ClientId</title>\n\n <style>\n "
},
{
"path": "apps/acme-webapp-saml-node-express/package.json",
"chars": 637,
"preview": "{\n \"name\": \"acme-webapp-saml-node-express\",\n \"version\": \"1.0.0\",\n \"main\": \"src/index.js\",\n \"author\": \"Thomas Darimon"
},
{
"path": "apps/acme-webapp-saml-node-express/src/config.js",
"chars": 1416,
"preview": "import fs from \"fs\";\n\nconst IDP_ISSUER = process.env.IDP_ISSUER || \"https://id.acme.test:8443/auth/realms/acme-internal\""
},
{
"path": "apps/acme-webapp-saml-node-express/src/express.js",
"chars": 7632,
"preview": "import express from \"express\";\nimport session from \"express-session\";\nimport passport from \"passport\";\nimport {Strategy "
},
{
"path": "apps/acme-webapp-saml-node-express/src/index.js",
"chars": 284,
"preview": "'use strict'\n\nimport config from './config.js';\nimport initLogging from './logging.js';\n\nimport createExpressApp from '."
},
{
"path": "apps/acme-webapp-saml-node-express/src/logging.js",
"chars": 895,
"preview": "import winston from \"winston\";\n\nfunction initLogging(config) {\n\n const loggingFormat = winston.format.combine(\n "
},
{
"path": "apps/acme-webapp-saml-node-express/src/server.js",
"chars": 2203,
"preview": "import fs from \"fs\";\nimport stoppable from \"stoppable\";\nimport {promisify} from \"es6-promisify\";\n\nimport spdy from \"spdy"
},
{
"path": "apps/acme-webapp-saml-node-express/views/pages/app.ejs",
"chars": 559,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <%- include('../partials/head'); %>\n</head>\n<body class=\"container\">\n\n<heade"
},
{
"path": "apps/acme-webapp-saml-node-express/views/pages/error.ejs",
"chars": 343,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <%- include('../partials/head'); %>\n</head>\n<body class=\"container\">\n\n<heade"
},
{
"path": "apps/acme-webapp-saml-node-express/views/pages/index.ejs",
"chars": 325,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <%- include('../partials/head'); %>\n</head>\n<body class=\"container\">\n\n<heade"
},
{
"path": "apps/acme-webapp-saml-node-express/views/pages/page1.ejs",
"chars": 562,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <%- include('../partials/head'); %>\n</head>\n<body class=\"container\">\n\n<heade"
},
{
"path": "apps/acme-webapp-saml-node-express/views/partials/footer.ejs",
"chars": 70,
"preview": "<p class=\"text-center text-muted\">© Copyright 2022 Thomas Darimont</p>"
},
{
"path": "apps/acme-webapp-saml-node-express/views/partials/head.ejs",
"chars": 284,
"preview": "<meta charset=\"UTF-8\">\n<title>Acme Webapp with SAML and NodeJS Express</title>\n\n<!-- CSS (load bootstrap from a CDN) -->"
},
{
"path": "apps/acme-webapp-saml-node-express/views/partials/header.ejs",
"chars": 787,
"preview": "<nav class=\"navbar navbar-expand-lg navbar-light bg-light\">\n <a class=\"navbar-brand\" href=\"/\">Acme Webapp SAML Node</"
},
{
"path": "apps/backend-api-dnc/api/.dockerignore",
"chars": 312,
"preview": "**/.dockerignore\n**/.env\n**/.git\n**/.gitignore\n**/.project\n**/.settings\n**/.toolstarget\n**/.vs\n**/.vscode\n**/.idea\n**/*"
},
{
"path": "apps/backend-api-dnc/api/.gitignore",
"chars": 37,
"preview": "# Visual Studio\nbin/\nobj/\n.vs/\n*.user"
},
{
"path": "apps/backend-api-dnc/api/Controllers/UsersController.cs",
"chars": 1012,
"preview": "using Microsoft.AspNetCore.Authorization;\nusing Microsoft.AspNetCore.Mvc;\n\nnamespace Api.Controllers;\n\n[ApiController]\n["
},
{
"path": "apps/backend-api-dnc/api/Dockerfile",
"chars": 479,
"preview": "FROM mcr.microsoft.com/dotnet/aspnet:6.0 AS base\nWORKDIR /app\nEXPOSE 80\nEXPOSE 443\n\nFROM mcr.microsoft.com/dotnet/sdk:6"
},
{
"path": "apps/backend-api-dnc/api/JwtBearerOptions.cs",
"chars": 493,
"preview": "namespace Api;\n\n/// <summary>\n/// Options for JWT Bearer authentication.\n/// </summary>\npublic class JwtBearerOptions\n{\n"
},
{
"path": "apps/backend-api-dnc/api/Program.cs",
"chars": 1470,
"preview": "using Microsoft.AspNetCore.Authentication.JwtBearer;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Add services"
},
{
"path": "apps/backend-api-dnc/api/Properties/launchSettings.json",
"chars": 1055,
"preview": "{\n \"$schema\": \"https://json.schemastore.org/launchsettings.json\",\n \"iisSettings\": {\n \"windowsAuthentication\": fals"
},
{
"path": "apps/backend-api-dnc/api/api.csproj",
"chars": 608,
"preview": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n <PropertyGroup>\n <TargetFramework>net6.0</TargetFramework>\n <Nu"
},
{
"path": "apps/backend-api-dnc/api/appsettings.Development.json",
"chars": 535,
"preview": "{\n \"Logging\": {\n \"LogLevel\": {\n \"Default\": \"Information\",\n \"Microsoft.AspNetCore\": \"Warning\"\n }\n },\n "
},
{
"path": "apps/backend-api-dnc/api/appsettings.json",
"chars": 438,
"preview": "{\n \"Logging\": {\n \"LogLevel\": {\n \"Default\": \"Information\",\n \"Microsoft.AspNetCore\": \"Warning\"\n }\n },\n "
},
{
"path": "apps/backend-api-dnc/backend-api-dnc.sln",
"chars": 762,
"preview": "\nMicrosoft Visual Studio Solution File, Format Version 12.00\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"api\","
},
{
"path": "apps/backend-api-micronaut/.gitignore",
"chars": 115,
"preview": "Thumbs.db\n.DS_Store\n.gradle\nbuild/\ntarget/\nout/\n.idea\n*.iml\n*.ipr\n*.iws\n.project\n.settings\n.classpath\n.factorypath\n"
},
{
"path": "apps/backend-api-micronaut/.mvn/wrapper/MavenWrapperDownloader.java",
"chars": 5165,
"preview": "/*\n * Copyright 2007-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \""
},
{
"path": "apps/backend-api-micronaut/.mvn/wrapper/maven-wrapper.properties",
"chars": 218,
"preview": "distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.3/apache-maven-3.6.3-bin.zip\nwrap"
},
{
"path": "apps/backend-api-micronaut/README.md",
"chars": 631,
"preview": "## Micronaut 3.3.4 Documentation\n\n- [User Guide](https://docs.micronaut.io/3.3.4/guide/index.html)\n- [API Reference](htt"
},
{
"path": "apps/backend-api-micronaut/micronaut-cli.yml",
"chars": 313,
"preview": "applicationType: default\ndefaultPackage: com.acme.backend.micronaut\ntestFramework: junit\nsourceLanguage: java\nbuildTool:"
},
{
"path": "apps/backend-api-micronaut/mvnw",
"chars": 10070,
"preview": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Softwa"
},
{
"path": "apps/backend-api-micronaut/mvnw.bat",
"chars": 6608,
"preview": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software F"
},
{
"path": "apps/backend-api-micronaut/pom.xml",
"chars": 4248,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "apps/backend-api-micronaut/src/main/java/com/acme/backend/micronaut/Application.java",
"chars": 206,
"preview": "package com.acme.backend.micronaut;\n\nimport io.micronaut.runtime.Micronaut;\n\npublic class Application {\n\n public stat"
},
{
"path": "apps/backend-api-micronaut/src/main/java/com/acme/backend/micronaut/api/UsersResource.java",
"chars": 1068,
"preview": "package com.acme.backend.micronaut.api;\n\nimport io.micronaut.http.HttpRequest;\nimport io.micronaut.http.annotation.Contr"
},
{
"path": "apps/backend-api-micronaut/src/main/resources/application.yml",
"chars": 881,
"preview": "micronaut:\n application:\n name: backendApiMicronaut\n ssl:\n enabled: true\n keyStore:\n path: file:config/s"
},
{
"path": "apps/backend-api-micronaut/src/main/resources/logback.xml",
"chars": 519,
"preview": "<configuration>\n\n <appender name=\"STDOUT\" class=\"ch.qos.logback.core.ConsoleAppender\">\n <withJansi>true</withJ"
},
{
"path": "apps/backend-api-node-express/package.json",
"chars": 556,
"preview": "{\n \"name\": \"backend-api-node-express\",\n \"version\": \"1.0.0\",\n \"main\": \"src/index.js\",\n \"author\": \"Thomas Darimont\",\n "
},
{
"path": "apps/backend-api-node-express/readme.md",
"chars": 277,
"preview": "Acme Backend API Node Express\n---\n\n# Setup\n\nAdd rootCA for self-signed certificates - required for fetching public keys "
},
{
"path": "apps/backend-api-node-express/src/api.js",
"chars": 651,
"preview": "/**\n * Initializes the API endpoints\n * @param app\n * @param LOG\n */\nfunction createApiEndpoints(app, config, LOG) {\n\n "
},
{
"path": "apps/backend-api-node-express/src/config.js",
"chars": 1081,
"preview": "const ISSUER = process.env.ISSUER || \"https://id.acme.test:8443/auth/realms/acme-internal\";\nconst PORT = process.env.POR"
},
{
"path": "apps/backend-api-node-express/src/express.js",
"chars": 1691,
"preview": "import express from \"express\";\nimport cors from \"cors\";\nimport jwksRsa from \"jwks-rsa\";\nimport jwt from \"express-jwt\";\n\n"
},
{
"path": "apps/backend-api-node-express/src/index.js",
"chars": 365,
"preview": "'use strict'\n\nimport config from './config.js';\nimport initLogging from './logging.js';\n\nimport createExpressApp from '."
},
{
"path": "apps/backend-api-node-express/src/logging.js",
"chars": 882,
"preview": "import winston from \"winston\";\n\nfunction initLogging(config) {\n\n const loggingFormat = winston.format.combine(\n "
},
{
"path": "apps/backend-api-node-express/src/server.js",
"chars": 2130,
"preview": "import fs from \"fs\";\nimport stoppable from \"stoppable\";\nimport {promisify} from \"es6-promisify\";\n\nimport spdy from \"spdy"
},
{
"path": "apps/backend-api-quarkus/.dockerignore",
"chars": 75,
"preview": "*\n!target/*-runner\n!target/*-runner.jar\n!target/lib/*\n!target/quarkus-app/*"
},
{
"path": "apps/backend-api-quarkus/.gitignore",
"chars": 334,
"preview": "#Maven\ntarget/\npom.xml.tag\npom.xml.releaseBackup\npom.xml.versionsBackup\nrelease.properties\n\n# Eclipse\n.project\n.classpat"
},
{
"path": "apps/backend-api-quarkus/README.md",
"chars": 1972,
"preview": "backend-api-quarkus project\n---\n\nSimple backend API example that can be access with an Access-Token from the oidc-js-spa"
},
{
"path": "apps/backend-api-quarkus/pom.xml",
"chars": 5410,
"preview": "<?xml version=\"1.0\"?>\n<project xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-"
},
{
"path": "apps/backend-api-quarkus/src/main/docker/Dockerfile.jvm",
"chars": 2135,
"preview": "####\n# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode\n#\n# Before bu"
},
{
"path": "apps/backend-api-quarkus/src/main/docker/Dockerfile.legacy-jar",
"chars": 1932,
"preview": "####\n# This Dockerfile is used in order to build a container that runs the Quarkus application in JVM mode\n#\n# Before bu"
},
{
"path": "apps/backend-api-quarkus/src/main/docker/Dockerfile.native",
"chars": 688,
"preview": "####\n# This Dockerfile is used in order to build a container that runs the Quarkus application in native (no JVM) mode\n#"
},
{
"path": "apps/backend-api-quarkus/src/main/docker/Dockerfile.native-distroless",
"chars": 591,
"preview": "####\n# This Dockerfile is used in order to build a distroless container that runs the Quarkus application in native (no "
},
{
"path": "apps/backend-api-quarkus/src/main/java/com/acme/backend/quarkus/users/UsersResource.java",
"chars": 2270,
"preview": "package com.acme.backend.quarkus.users;\n\nimport io.quarkus.security.Authenticated;\nimport jakarta.annotation.security.Ro"
},
{
"path": "apps/backend-api-quarkus/src/main/resources/META-INF/resources/index.html",
"chars": 5292,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <title>backend-api-quarkus - 1.0-SNAPSHOT</title>"
},
{
"path": "apps/backend-api-quarkus/src/main/resources/application.properties",
"chars": 1350,
"preview": "quarkus.http.port=4500\n\n# Allows access via host.docker.internal from container\nquarkus.http.host=0.0.0.0\n\nquarkus.http."
},
{
"path": "apps/backend-api-rust-actix/.gitignore",
"chars": 8,
"preview": "/target\n"
},
{
"path": "apps/backend-api-rust-actix/Cargo.toml",
"chars": 620,
"preview": "[package]\nname = \"backend-api-rust-actix\"\nversion = \"0.1.0\"\nedition = \"2021\"\nauthors = [\"Thomas Darimont <thomas.darimon"
},
{
"path": "apps/backend-api-rust-actix/rustfmt.toml",
"chars": 15,
"preview": "max_width = 120"
},
{
"path": "apps/backend-api-rust-actix/rustup-toolchain.toml",
"chars": 31,
"preview": "[toolchain]\nchannel = \"nightly\""
},
{
"path": "apps/backend-api-rust-actix/src/api/me_info.rs",
"chars": 888,
"preview": "use crate::middleware::jwt_auth::FoundClaims;\nuse actix_4_jwt_auth::AuthenticatedUser;\nuse actix_web::{get, HttpResponse"
},
{
"path": "apps/backend-api-rust-actix/src/api/mod.rs",
"chars": 17,
"preview": "pub mod me_info;\n"
},
{
"path": "apps/backend-api-rust-actix/src/config.rs",
"chars": 1008,
"preview": "use std::env;\npub struct Config {\n pub server_bind_addr: String,\n pub cert_location: String,\n pub key_location:"
},
{
"path": "apps/backend-api-rust-actix/src/main.rs",
"chars": 1117,
"preview": "#![feature(decl_macro)]\n\nuse actix_web::middleware::Logger;\nuse actix_web::{App, HttpServer};\n\nmod api;\nmod config;\nmod "
},
{
"path": "apps/backend-api-rust-actix/src/middleware/cors.rs",
"chars": 490,
"preview": "use actix_cors::Cors;\nuse actix_web::http::header;\n\npub fn create_cors_config(allowed_origin: String) -> Cors {\n Cors"
},
{
"path": "apps/backend-api-rust-actix/src/middleware/jwt_auth.rs",
"chars": 860,
"preview": "use actix_4_jwt_auth::{OIDCValidator, OIDCValidatorConfig};\nuse actix_web::rt::task;\nuse serde::Deserialize;\nuse serde_j"
},
{
"path": "apps/backend-api-rust-actix/src/middleware/mod.rs",
"chars": 45,
"preview": "pub mod cors;\npub mod jwt_auth;\npub mod ssl;\n"
},
{
"path": "apps/backend-api-rust-actix/src/middleware/ssl.rs",
"chars": 415,
"preview": "use openssl::ssl::{SslAcceptor, SslAcceptorBuilder, SslFiletype, SslMethod};\n\npub fn create_ssl_acceptor_builder(cert_lo"
},
{
"path": "apps/backend-api-rust-rocket/.gitignore",
"chars": 25,
"preview": "/target\n.idea/\n.DS_Store\n"
},
{
"path": "apps/backend-api-rust-rocket/.run/Run backend-api-rust-rocket.run.xml",
"chars": 949,
"preview": "<component name=\"ProjectRunConfigurationManager\">\n <configuration default=\"false\" name=\"Run backend-api-rust-rocket\" ty"
},
{
"path": "apps/backend-api-rust-rocket/Cargo.toml",
"chars": 491,
"preview": "[package]\nname = \"backend-api-rust-rocket\"\nversion = \"0.1.0\"\nauthors = [\"Thomas Darimont <thomas.darimont@gmail.com>\"]\ne"
},
{
"path": "apps/backend-api-rust-rocket/README.md",
"chars": 412,
"preview": "# Backend API with JWK authentication based on Rocket (Rust)\n\n## Features\n- Validate JWT issued by Keycloak\n- Validate J"
},
{
"path": "apps/backend-api-rust-rocket/Rocket.toml",
"chars": 300,
"preview": "# see https://rocket.rs/v0.5-rc/guide/configuration/#overview\n[debug]\naddress = \"127.0.0.1\"\nport = 4853\nworkers = 2\nkeep"
},
{
"path": "apps/backend-api-rust-rocket/rustfmt.toml",
"chars": 16,
"preview": "edition = \"2021\""
},
{
"path": "apps/backend-api-rust-rocket/rustup-toolchain.toml",
"chars": 31,
"preview": "[toolchain]\nchannel = \"nightly\""
},
{
"path": "apps/backend-api-rust-rocket/src/domain/mod.rs",
"chars": 14,
"preview": "pub mod user;\n"
},
{
"path": "apps/backend-api-rust-rocket/src/domain/user.rs",
"chars": 148,
"preview": "pub struct User {\n pub uid: String,\n pub username: String,\n pub email: String,\n // TODO add other claims\n "
},
{
"path": "apps/backend-api-rust-rocket/src/main.rs",
"chars": 1291,
"preview": "//#![feature(proc_macro_hygiene, decl_macro)]\n\n#[macro_use]\nextern crate rocket;\n\nuse rocket::routes;\nuse std::error::Er"
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/auth/jwt/auth.rs",
"chars": 1992,
"preview": "use crate::middleware::auth::jwt::{fetch_jwks_keys, Claims, JwkKeys, JwtVerifier};\nuse crate::support::scheduling::use_r"
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/auth/jwt/claims.rs",
"chars": 123,
"preview": "use rocket::serde::json::serde_json;\nuse std::collections::HashMap;\n\npub type Claims = HashMap<String, serde_json::Value"
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/auth/jwt/config.rs",
"chars": 659,
"preview": "use crate::middleware;\n\n#[derive(Debug)]\npub struct JwtConfig {\n pub jwk_url: String,\n pub audience: String,\n /"
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/auth/jwt/get_max_age.rs",
"chars": 1712,
"preview": "use reqwest::blocking::Response;\nuse reqwest::header::HeaderValue;\nuse std::time::Duration;\n\npub enum MaxAgeParseError {"
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/auth/jwt/jwks.rs",
"chars": 1296,
"preview": "use crate::middleware::auth::jwt;\nuse crate::middleware::auth::jwt::get_max_age::get_max_age;\nuse crate::middleware::aut"
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/auth/jwt/mod.rs",
"chars": 169,
"preview": "mod auth;\nmod claims;\nmod config;\nmod jwks;\nmod get_max_age;\nmod verifier;\n\npub use auth::*;\npub use claims::*;\npub use "
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/auth/jwt/verifier.rs",
"chars": 2625,
"preview": "use crate::middleware::auth::jwt;\nuse crate::middleware::auth::jwt::claims::Claims;\nuse crate::middleware::auth::jwt::{J"
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/auth/jwt_auth_request_guard.rs",
"chars": 3104,
"preview": "use crate::domain::user::User;\nuse crate::middleware::auth::jwt::JwtAuth;\nuse rocket::http::Status;\nuse rocket::outcome:"
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/auth/mod.rs",
"chars": 76,
"preview": "pub mod jwt;\nmod jwt_auth_request_guard;\npub use jwt_auth_request_guard::*;\n"
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/cors/cors.rs",
"chars": 893,
"preview": "use rocket::fairing::Fairing;\nuse rocket::fairing::Info;\nuse rocket::fairing::Kind;\nuse rocket::http::Header;\nuse rocket"
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/cors/mod.rs",
"chars": 32,
"preview": "pub mod cors;\n\npub use cors::*;\n"
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/logging/logging.rs",
"chars": 454,
"preview": "use chrono::Local;\nuse env_logger::Builder;\nuse log;\nuse log::LevelFilter;\nuse std::io::Write;\n\npub fn init_logging() {\n"
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/logging/mod.rs",
"chars": 38,
"preview": "pub mod logging;\n\npub use logging::*;\n"
},
{
"path": "apps/backend-api-rust-rocket/src/middleware/mod.rs",
"chars": 421,
"preview": "use std::env;\n\npub mod auth;\npub mod cors;\npub mod logging;\n\n#[cfg(debug_assertions)]\npub fn expect_env_var(name: &str, "
},
{
"path": "apps/backend-api-rust-rocket/src/support/mod.rs",
"chars": 20,
"preview": "pub mod scheduling;\n"
},
{
"path": "apps/backend-api-rust-rocket/src/support/scheduling/mod.rs",
"chars": 58,
"preview": "pub mod use_repeating_job;\n\npub use use_repeating_job::*;\n"
},
{
"path": "apps/backend-api-rust-rocket/src/support/scheduling/use_repeating_job.rs",
"chars": 767,
"preview": "use std::sync::mpsc::{self, TryRecvError};\nuse std::thread;\nuse std::time::Duration;\n\ntype Delay = Duration;\ntype Cancel"
},
{
"path": "apps/backend-api-rust-rocket/tests/fetch_keys.rs",
"chars": 873,
"preview": "use jwk_example::fetch_keys_for_config;\nuse jwk_example::JwkConfiguration;\nuse jwk_example::JwkKey;\n\nfn assert_is_valid_"
},
{
"path": "apps/backend-api-springboot/.gitignore",
"chars": 395,
"preview": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**/target/\n!**/src/test/**/target/\n\n### STS ###\n.apt_genera"
},
{
"path": "apps/backend-api-springboot/.mvn/wrapper/MavenWrapperDownloader.java",
"chars": 4942,
"preview": "/*\n * Copyright 2007-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \""
},
{
"path": "apps/backend-api-springboot/.mvn/wrapper/maven-wrapper.properties",
"chars": 218,
"preview": "distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip\nwrap"
},
{
"path": "apps/backend-api-springboot/mvnw",
"chars": 10070,
"preview": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Softwa"
},
{
"path": "apps/backend-api-springboot/mvnw.cmd",
"chars": 6608,
"preview": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software F"
},
{
"path": "apps/backend-api-springboot/pom.xml",
"chars": 2413,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/BackendApiSpringbootApp.java",
"chars": 447,
"preview": "package com.acme.backend.springboot.users;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframewor"
},
{
"path": "apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/config/AcmeServiceProperties.java",
"chars": 723,
"preview": "package com.acme.backend.springboot.users.config;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframewor"
},
{
"path": "apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/config/JwtSecurityConfig.java",
"chars": 3467,
"preview": "package com.acme.backend.springboot.users.config;\n\nimport com.acme.backend.springboot.users.support.keycloak.KeycloakGra"
},
{
"path": "apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/config/MethodSecurityConfig.java",
"chars": 2036,
"preview": "package com.acme.backend.springboot.users.config;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.con"
},
{
"path": "apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/config/WebSecurityConfig.java",
"chars": 3450,
"preview": "package com.acme.backend.springboot.users.config;\n\nimport com.acme.backend.springboot.users.support.access.AccessControl"
},
{
"path": "apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/support/access/AccessController.java",
"chars": 875,
"preview": "package com.acme.backend.springboot.users.support.access;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework."
},
{
"path": "apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakAudienceValidator.java",
"chars": 1129,
"preview": "package com.acme.backend.springboot.users.support.keycloak;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springfra"
},
{
"path": "apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakGrantedAuthoritiesConverter.java",
"chars": 4151,
"preview": "package com.acme.backend.springboot.users.support.keycloak;\n\nimport org.springframework.core.convert.converter.Converter"
},
{
"path": "apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakJwtAuthenticationConverter.java",
"chars": 1600,
"preview": "package com.acme.backend.springboot.users.support.keycloak;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springfra"
},
{
"path": "apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/support/permissions/DefaultPermissionEvaluator.java",
"chars": 1216,
"preview": "package com.acme.backend.springboot.users.support.permissions;\n\nimport lombok.RequiredArgsConstructor;\nimport lombok.ext"
},
{
"path": "apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/support/permissions/DomainObjectReference.java",
"chars": 264,
"preview": "package com.acme.backend.springboot.users.support.permissions;\n\nimport lombok.Data;\n\n/**\n * Defines a single domain obje"
},
{
"path": "apps/backend-api-springboot/src/main/java/com/acme/backend/springboot/users/web/UsersController.java",
"chars": 1001,
"preview": "package com.acme.backend.springboot.users.web;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.security.co"
},
{
"path": "apps/backend-api-springboot/src/main/resources/application.yml",
"chars": 828,
"preview": "spring:\n jackson:\n serialization:\n write-dates-as-timestamps: false\n deserialization:\n # deals with sin"
},
{
"path": "apps/backend-api-springboot/src/test/java/com/acme/backend/springboot/users/BackendApiSpringbootAppTests.java",
"chars": 231,
"preview": "package com.acme.backend.springboot.users;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.cont"
},
{
"path": "apps/backend-api-springboot-reactive/.gitignore",
"chars": 395,
"preview": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**/target/\n!**/src/test/**/target/\n\n### STS ###\n.apt_genera"
},
{
"path": "apps/backend-api-springboot-reactive/.mvn/wrapper/maven-wrapper.properties",
"chars": 233,
"preview": "distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.3/apache-maven-3.8.3-bin.zip\nwrap"
},
{
"path": "apps/backend-api-springboot-reactive/mvnw",
"chars": 10284,
"preview": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Softwa"
},
{
"path": "apps/backend-api-springboot-reactive/mvnw.cmd",
"chars": 6734,
"preview": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software F"
},
{
"path": "apps/backend-api-springboot-reactive/pom.xml",
"chars": 2786,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/BackendApiSpringbootReactiveApp.java",
"chars": 364,
"preview": "package com.acme.backend.springreactive;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframework."
},
{
"path": "apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/config/AcmeServiceProperties.java",
"chars": 721,
"preview": "package com.acme.backend.springreactive.config;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframework."
},
{
"path": "apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/config/JwtSecurityConfig.java",
"chars": 3495,
"preview": "package com.acme.backend.springreactive.config;\n\nimport com.acme.backend.springreactive.support.keycloak.KeycloakGranted"
},
{
"path": "apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/config/MethodSecurityConfig.java",
"chars": 999,
"preview": "package com.acme.backend.springreactive.config;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.conte"
},
{
"path": "apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/config/WebFluxConfig.java",
"chars": 666,
"preview": "package com.acme.backend.springreactive.config;\n\nimport org.springframework.context.annotation.Configuration;\nimport org"
},
{
"path": "apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/config/WebFluxRoutes.java",
"chars": 950,
"preview": "package com.acme.backend.springreactive.config;\n\nimport com.acme.backend.springreactive.users.UserHandlers;\nimport org.s"
},
{
"path": "apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/config/WebSecurityConfig.java",
"chars": 2490,
"preview": "package com.acme.backend.springreactive.config;\n\nimport com.acme.backend.springreactive.support.keycloak.KeycloakJwtAuth"
},
{
"path": "apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/support/keycloak/KeycloakAudienceValidator.java",
"chars": 1127,
"preview": "package com.acme.backend.springreactive.support.keycloak;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springframe"
},
{
"path": "apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/support/keycloak/KeycloakGrantedAuthoritiesConverter.java",
"chars": 4149,
"preview": "package com.acme.backend.springreactive.support.keycloak;\n\nimport org.springframework.core.convert.converter.Converter;\n"
},
{
"path": "apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/support/keycloak/KeycloakJwtAuthenticationConverter.java",
"chars": 1662,
"preview": "package com.acme.backend.springreactive.support.keycloak;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springframe"
},
{
"path": "apps/backend-api-springboot-reactive/src/main/java/com/acme/backend/springreactive/users/UserHandlers.java",
"chars": 916,
"preview": "package com.acme.backend.springreactive.users;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.stereotype."
},
{
"path": "apps/backend-api-springboot-reactive/src/main/resources/application.yml",
"chars": 733,
"preview": "spring:\n jackson:\n serialization:\n write-dates-as-timestamps: false\n deserialization:\n # deals with sin"
},
{
"path": "apps/backend-api-springboot-reactive/src/test/java/com/acme/backend/springreactive/BackendApiSpringbootReactiveAppTests.java",
"chars": 246,
"preview": "package com.acme.backend.springreactive;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.contex"
},
{
"path": "apps/backend-api-springboot3/.gitignore",
"chars": 395,
"preview": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**/target/\n!**/src/test/**/target/\n\n### STS ###\n.apt_genera"
},
{
"path": "apps/backend-api-springboot3/.mvn/wrapper/MavenWrapperDownloader.java",
"chars": 4942,
"preview": "/*\n * Copyright 2007-present the original author or authors.\n *\n * Licensed under the Apache License, Version 2.0 (the \""
},
{
"path": "apps/backend-api-springboot3/.mvn/wrapper/maven-wrapper.properties",
"chars": 218,
"preview": "distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip\nwrap"
},
{
"path": "apps/backend-api-springboot3/mvnw",
"chars": 10070,
"preview": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Softwa"
},
{
"path": "apps/backend-api-springboot3/mvnw.cmd",
"chars": 6608,
"preview": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software F"
},
{
"path": "apps/backend-api-springboot3/pom.xml",
"chars": 2653,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/BackendApiSpringboot3App.java",
"chars": 449,
"preview": "package com.acme.backend.springboot.users;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframewor"
},
{
"path": "apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/AcmeServiceProperties.java",
"chars": 723,
"preview": "package com.acme.backend.springboot.users.config;\n\nimport lombok.Getter;\nimport lombok.Setter;\nimport org.springframewor"
},
{
"path": "apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/JwtSecurityConfig.java",
"chars": 3467,
"preview": "package com.acme.backend.springboot.users.config;\n\nimport com.acme.backend.springboot.users.support.keycloak.KeycloakGra"
},
{
"path": "apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/MethodSecurityConfig.java",
"chars": 1747,
"preview": "package com.acme.backend.springboot.users.config;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springframework.con"
},
{
"path": "apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/config/WebSecurityConfig.java",
"chars": 3498,
"preview": "package com.acme.backend.springboot.users.config;\n\nimport com.acme.backend.springboot.users.support.access.AccessControl"
},
{
"path": "apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/access/AccessController.java",
"chars": 971,
"preview": "package com.acme.backend.springboot.users.support.access;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework."
},
{
"path": "apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakAudienceValidator.java",
"chars": 1129,
"preview": "package com.acme.backend.springboot.users.support.keycloak;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springfra"
},
{
"path": "apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakGrantedAuthoritiesConverter.java",
"chars": 4151,
"preview": "package com.acme.backend.springboot.users.support.keycloak;\n\nimport org.springframework.core.convert.converter.Converter"
},
{
"path": "apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/keycloak/KeycloakJwtAuthenticationConverter.java",
"chars": 1600,
"preview": "package com.acme.backend.springboot.users.support.keycloak;\n\nimport lombok.RequiredArgsConstructor;\nimport org.springfra"
},
{
"path": "apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/permissions/DefaultPermissionEvaluator.java",
"chars": 1216,
"preview": "package com.acme.backend.springboot.users.support.permissions;\n\nimport lombok.RequiredArgsConstructor;\nimport lombok.ext"
},
{
"path": "apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/support/permissions/DomainObjectReference.java",
"chars": 264,
"preview": "package com.acme.backend.springboot.users.support.permissions;\n\nimport lombok.Data;\n\n/**\n * Defines a single domain obje"
},
{
"path": "apps/backend-api-springboot3/src/main/java/com/acme/backend/springboot/users/web/UsersController.java",
"chars": 1002,
"preview": "package com.acme.backend.springboot.users.web;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframework.security.co"
},
{
"path": "apps/backend-api-springboot3/src/main/resources/application.yml",
"chars": 733,
"preview": "spring:\n jackson:\n serialization:\n write-dates-as-timestamps: false\n deserialization:\n # deals with sin"
},
{
"path": "apps/backend-api-springboot3/src/test/java/com/acme/backend/springboot/users/BackendApiSpringboot3AppTests.java",
"chars": 232,
"preview": "package com.acme.backend.springboot.users;\n\nimport org.junit.jupiter.api.Test;\nimport org.springframework.boot.test.cont"
},
{
"path": "apps/bff-springboot/.gitignore",
"chars": 395,
"preview": "HELP.md\ntarget/\n!.mvn/wrapper/maven-wrapper.jar\n!**/src/main/**/target/\n!**/src/test/**/target/\n\n### STS ###\n.apt_genera"
},
{
"path": "apps/bff-springboot/.mvn/wrapper/maven-wrapper.properties",
"chars": 233,
"preview": "distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.4/apache-maven-3.8.4-bin.zip\nwrap"
},
{
"path": "apps/bff-springboot/mvnw",
"chars": 10284,
"preview": "#!/bin/sh\n# ----------------------------------------------------------------------------\n# Licensed to the Apache Softwa"
},
{
"path": "apps/bff-springboot/mvnw.cmd",
"chars": 6734,
"preview": "@REM ----------------------------------------------------------------------------\n@REM Licensed to the Apache Software F"
},
{
"path": "apps/bff-springboot/pom.xml",
"chars": 3398,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2"
},
{
"path": "apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/BffApp.java",
"chars": 317,
"preview": "package com.github.thomasdarimont.apps.bff;\n\nimport org.springframework.boot.SpringApplication;\nimport org.springframewo"
},
{
"path": "apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/api/UsersResource.java",
"chars": 1911,
"preview": "package com.github.thomasdarimont.apps.bff.api;\n\nimport org.springframework.beans.factory.annotation.Qualifier;\nimport o"
},
{
"path": "apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/config/OAuth2RestTemplateConfig.java",
"chars": 1378,
"preview": "package com.github.thomasdarimont.apps.bff.config;\n\nimport com.github.thomasdarimont.apps.bff.oauth.TokenAccessor;\nimpor"
},
{
"path": "apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/config/SessionConfig.java",
"chars": 677,
"preview": "package com.github.thomasdarimont.apps.bff.config;\n\nimport org.springframework.context.annotation.Bean;\nimport org.sprin"
},
{
"path": "apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/config/WebSecurityConfig.java",
"chars": 4387,
"preview": "package com.github.thomasdarimont.apps.bff.config;\n\nimport com.github.thomasdarimont.apps.bff.config.keycloak.KeycloakLo"
},
{
"path": "apps/bff-springboot/src/main/java/com/github/thomasdarimont/apps/bff/config/keycloak/KeycloakLogoutHandler.java",
"chars": 2089,
"preview": "package com.github.thomasdarimont.apps.bff.config.keycloak;\n\nimport lombok.extern.slf4j.Slf4j;\nimport org.springframewor"
}
]
// ... and 714 more files (download for full content)
About this extraction
This page contains the full source code of the thomasdarimont/keycloak-project-example GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 914 files (3.2 MB), approximately 889.8k tokens, and a symbol index with 2509 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.