From 9e8480324cb347c96ee39dc39b3473665edefead Mon Sep 17 00:00:00 2001 From: Sergei Trofimov Date: Mon, 21 Aug 2023 15:10:46 +0100 Subject: [PATCH] Implement API auth Implement API authentication and authorization. - Define IAuthorizer interface that can be used to obtain a gin middleware handler that performs authorisation. - Add a mechanism to obtain an IAuthorizer for a particular role base on Veraison configuration. - Implement "passthrough" authorizer that duplicates existing behavior (no auth). - Implement "basic" authorizer that does not rely on an external authorization server. - Implement "keycloak" authorizer that uses Keycloak service for authentication. - Update provisioning service to authorize based on "provisioner" role. - Update management service to authorize based on "manager" role. - Add the previously missing README for the management service. Signed-off-by: Sergei Trofimov --- auth/README.md | 133 ++ auth/authorizer.go | 47 + auth/basic.go | 149 ++ auth/iauthorizer.go | 25 + auth/keycloak.go | 109 + auth/passthrough.go | 37 + auth/roles.go | 7 + deployments/docker/Makefile | 19 +- deployments/docker/deployment.cfg | 1 + deployments/docker/src/builder-dispatcher | 2 + deployments/docker/src/config.yaml.template | 4 + deployments/docker/src/keycloak.conf.template | 5 + deployments/docker/src/keycloak.docker | 17 + deployments/docker/src/load-config.mk | 1 + deployments/docker/src/veraison-realm.json | 1841 +++++++++++++++++ deployments/docker/veraison | 29 +- go.mod | 12 +- go.sum | 40 +- integration-tests/docker/bashrc | 1 + integration-tests/tests/common.yaml | 11 + .../tests/test_enacttrust_badkey.tavern.yaml | 1 + .../tests/test_enacttrust_badnode.tavern.yaml | 1 + .../tests/test_end_to_end.tavern.yaml | 1 + .../tests/test_multinonce.tavern.yaml | 1 + .../tests/test_policy_management.tavern.yaml | 14 + .../test_provisioning_empty_body.tavern.yaml | 1 + ...test_provisioning_unauthorized.tavern.yaml | 23 + ...ification_bad_session_attester.tavern.yaml | 1 + integration-tests/utils/conftest.py | 1 + integration-tests/utils/hooks.py | 24 +- integration-tests/utils/util.py | 37 + management/api/router.go | 8 +- management/cmd/management-service/README.md | 39 + management/cmd/management-service/config.yaml | 5 + management/cmd/management-service/main.go | 18 +- provisioning/api/handler_test.go | 13 +- provisioning/api/router.go | 4 +- .../cmd/provisioning-service/README.md | 7 +- provisioning/cmd/provisioning-service/main.go | 20 +- 39 files changed, 2681 insertions(+), 28 deletions(-) create mode 100644 auth/README.md create mode 100644 auth/authorizer.go create mode 100644 auth/basic.go create mode 100644 auth/iauthorizer.go create mode 100644 auth/keycloak.go create mode 100644 auth/passthrough.go create mode 100644 auth/roles.go create mode 100644 deployments/docker/src/keycloak.conf.template create mode 100644 deployments/docker/src/keycloak.docker create mode 100644 deployments/docker/src/veraison-realm.json create mode 100644 integration-tests/tests/test_provisioning_unauthorized.tavern.yaml create mode 100644 management/cmd/management-service/README.md diff --git a/auth/README.md b/auth/README.md new file mode 100644 index 00000000..605a6111 --- /dev/null +++ b/auth/README.md @@ -0,0 +1,133 @@ +## Overview + +This directory implements authentication and authorization for Veraison API. +Authentication can be performed using the Basic HTTP scheme (with the `basic` +backend), or using a Bearer token (with the `keycloak` backend). Once an API +user is authenticated, authorization is +[role-based](https://en.wikipedia.org/wiki/Role-based_access_control). See +documentation for specific services for which role(s) are needed to access +their API. + + +## Configuration + +- `backend`: specifies which auth backend will be used by the service. The + valid options are: + + - `passthrough`: a backend that does not perform any authentication, allowing + all requests. + - `none`: alias for `passthrough`. + - `basic`: Uses the Basic HTTP authentication scheme. See + [RFC7617](https://datatracker.ietf.org/doc/html/rfc7617) for details. This + is not intended for production. + - `keycloak`: Uses OpenID Connect protocol as implemented by the Keycloak + authentication server. + + See below for details of how to configure individual backends. + +### Passthrough + +No additional configuration is required. `passthrough` will allow all requests. +This is the default if `auth` configuration is not provided. + +### Basic + +- `users`: this is a mapping of user names onto their bcrypt password hashes + and roles. The key of the mapping is the user name, the value is a futher + mapping for the details with the following fields: + + - `password`: the bcrypt hash of the user's password. + - `roles`: either a single role or a list of roles associated with the + user. API authrization will be performed based on the user's roles. + +bcrypt hashes can be generated on the command line using `mkpasswd` utility, +e.g.: + +```bash +mkpasswd -m bcrypt --stdin <<< Passw0rd! +``` + +For example: + +```yaml +auth: + backend: basic + users: + user1: + password: "$2b$05$XgVBveh6QPrRHXI.8S/J9uobBR7Wv9z4CL8yACHEmKIQmYSSyKAqC" # Passw0rd! + roles: provisioner + user2: + password: "$2b$05$x5fvAV5WPkX0KXzqf5FMKODz0uyi2ioew1lOrF2Czp2aNH1LQmhki" # @s3cr3t + roles: [manager, provisioner] +``` + +### Keycloak + +- `host` (optional): host name of the Keycloak service. Defaults to + `localhost`. +- `port` (optional): the port on which the Keycloak service is listening. + Defaults to `8080`. +- `realm` (optional): the Keycloak realm used by Veraison. A realm contains the + configuration for clients, users, roles, etc. It is roughly analogous to a + "tenant id". Defaults to `veraison`. + +For example: + +```yaml +auth: + backend: keycloak + host: keycloak.example.com + port: 11111 + realm: veraison +``` + +## Usage + +```go +"github.com/gin-gonic/gin" +"github.com/veraison/services/auth" +"github.com/veraison/services/config" +"github.com/veraison/services/log" + +func main() { + // Load authroizer config. + v, err := config.ReadRawConfig(*config.File, false) + if err != nil { + log.Fatalf("Could not read config: %v", err) + } + subs, err := config.GetSubs(v, "*auth") + if err != nil { + log.Fatalf("Could not parse config: %v", err) + } + + // Create new authorizer based on the loaded config. + authorizer, err := auth.NewAuthorizer(subs["auth"], log.Named("auth")) + if err != nil { + log.Fatalf("could not init authorizer: %v", err) + } + + // Ensure the authorizer is terminated properly on exit + defer func() { + err := authorizer.Close() + if err != nil { + log.Errorf("Could not close authorizer: %v", err) + } + }() + + // Use the authorizer to set a middleware handler in the appropriate gin + // router, with an appropriate role. + router := gin.Default() + router.Use(authorizer.GetGinHandler(auth.ManagerRole)) + + // Set up route handling here + // ... + // ... + + // Run the service. + if err := router.Run("0.0.0.0:80"); err != nil { + log.Errorf("Gin engine failed: %v", err) + } +} + +``` + diff --git a/auth/authorizer.go b/auth/authorizer.go new file mode 100644 index 00000000..26a2be45 --- /dev/null +++ b/auth/authorizer.go @@ -0,0 +1,47 @@ +// Copyright 2023 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package auth + +import ( + "fmt" + + "github.com/spf13/viper" + "github.com/veraison/services/config" + "go.uber.org/zap" +) + +type cfg struct { + Backend string `mapstructure:"backend,omitempty"` + BackendConfigs map[string]interface{} `mapstructure:",remain"` +} + +func NewAuthorizer(v *viper.Viper, logger *zap.SugaredLogger) (IAuthorizer, error) { + cfg := cfg{ + Backend: "passthrough", + } + + loader := config.NewLoader(&cfg) + if err := loader.LoadFromViper(v); err != nil { + return nil, err + } + + var a IAuthorizer + + switch cfg.Backend { + case "none", "passthrough": + a = &PassthroughAuthorizer{} + case "basic": + a = &BasicAuthorizer{} + case "keycloak": + a = &KeycloakAuthorizer{} + default: + return nil, fmt.Errorf("backend %q is not supported", cfg.Backend) + } + + if err := a.Init(v, logger); err != nil { + return nil, err + } + + return a, nil +} diff --git a/auth/basic.go b/auth/basic.go new file mode 100644 index 00000000..9d0a6ed5 --- /dev/null +++ b/auth/basic.go @@ -0,0 +1,149 @@ +// Copyright 2023 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package auth + +import ( + "errors" + "fmt" + "net/http" + + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + "github.com/veraison/services/log" + "go.uber.org/zap" + "golang.org/x/crypto/bcrypt" +) + +type basicAuthUser struct { + Password string `mapstructure:"password"` + Roles []string `mapstructure:"roles"` +} + +func newBasicAuthUser(m map[string]interface{}) (*basicAuthUser, error) { + var newUser basicAuthUser + + passRaw, ok := m["password"] + if !ok { + return nil, errors.New("password not set") + } + + switch t := passRaw.(type) { + case string: + newUser.Password = t + default: + return nil, fmt.Errorf("invalid password: expected string found %T", t) + } + + rolesRaw, ok := m["roles"] + if ok { + switch t := rolesRaw.(type) { + case []string: + newUser.Roles = t + case string: + newUser.Roles = make([]string, 1) + newUser.Roles[0] = t + default: + return nil, fmt.Errorf( + "invalid roles: expected []string or string, found %T", + t, + ) + } + } else { + newUser.Roles = make([]string, 0) + } + + return &newUser, nil +} + +type BasicAuthorizer struct { + logger *zap.SugaredLogger + users map[string]*basicAuthUser +} + +func (o *BasicAuthorizer) Init(v *viper.Viper, logger *zap.SugaredLogger) error { + if logger == nil { + return errors.New("nil logger") + } + o.logger = logger + + o.users = make(map[string]*basicAuthUser) + if rawUsers := v.GetStringMap("users"); rawUsers != nil { + for name, rawUser := range rawUsers { + switch t := rawUser.(type) { + case map[string]interface{}: + newUser, err := newBasicAuthUser(t) + if err != nil { + return fmt.Errorf("invalid user %q: %w", name, err) + + } + o.logger.Debugw("registered user", + "user", name, + "password", newUser.Password, + "roles", newUser.Roles, + ) + o.users[name] = newUser + default: + return fmt.Errorf( + "invalid user %q: expected map[string]interface{}, got %T", + name, t, + ) + } + } + } + + return nil +} + +func (o *BasicAuthorizer) Close() error { + return nil +} + +func (o *BasicAuthorizer) GetGinHandler(role string) gin.HandlerFunc { + return func(c *gin.Context) { + o.logger.Debugw("auth basic", "path", c.Request.URL.Path) + + userName, password, hasAuth := c.Request.BasicAuth() + if !hasAuth { + c.Writer.Header().Set("WWW-Authenticate", "Basic realm=veraison") + c.AbortWithStatus(http.StatusUnauthorized) + return + } + + userInfo, ok := o.users[userName] + if !ok { + c.Writer.Header().Set("WWW-Authenticate", "Basic realm=veraison") + c.AbortWithStatus(http.StatusUnauthorized) + return + } + + if err := bcrypt.CompareHashAndPassword( + []byte(userInfo.Password), + []byte(password), + ); err != nil { + o.logger.Debugf("password check failed: %v", err) + c.Writer.Header().Set("WWW-Authenticate", "Basic realm=veraison") + c.AbortWithStatus(http.StatusUnauthorized) + return + } + + gotRole := false + if role == NoRole { + gotRole = true + } else { + for _, userRole := range userInfo.Roles { + if userRole == role { + gotRole = true + break + } + } + } + + if gotRole { + log.Debugw("user authenticated", "user", userName, "role", role) + } else { + c.Writer.Header().Set("WWW-Authenticate", "Basic realm=veraison") + c.AbortWithStatus(http.StatusUnauthorized) + } + } +} diff --git a/auth/iauthorizer.go b/auth/iauthorizer.go new file mode 100644 index 00000000..11762e06 --- /dev/null +++ b/auth/iauthorizer.go @@ -0,0 +1,25 @@ +// Copyright 2023 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 + +package auth + +import ( + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + "go.uber.org/zap" +) + +// IAuthorizer defines the interface that must be implemented by the veraison +// auth backends. +type IAuthorizer interface { + // Init initializes the backend based on the configuration inside the + // provided Viper object and using the provided logger. + Init(v *viper.Viper, logger *zap.SugaredLogger) error + // Close terminates the backend. The exact nature of this method is + // backend-specific. + Close() error + // GetGinHandler returns a gin.HandlerFunc that performs authorization + // based on the specified role. This function can be set as gin + // middleware by passing it to gin.Engine.Use(). + GetGinHandler(role string) gin.HandlerFunc +} diff --git a/auth/keycloak.go b/auth/keycloak.go new file mode 100644 index 00000000..412ac474 --- /dev/null +++ b/auth/keycloak.go @@ -0,0 +1,109 @@ +// Copyright 2023 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package auth + +import ( + "errors" + "flag" + "fmt" + + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + "github.com/tbaehler/gin-keycloak/pkg/ginkeycloak" + "github.com/veraison/services/config" + "go.uber.org/zap" + "gopkg.in/square/go-jose.v2/jwt" +) + +type keycloakCfg struct { + Backend string `mapstructure:"backend"` + Host string `mapstructure:"host"` + Port string `mapstructure:"port"` + Realm string `mapstructure:"realm"` +} + +type KeycloakAuthorizer struct { + logger *zap.SugaredLogger + config ginkeycloak.KeycloakConfig +} + +func (o *KeycloakAuthorizer) Init(v *viper.Viper, logger *zap.SugaredLogger) error { + if logger == nil { + return errors.New("nil logger") + } + o.logger = logger + + // This prevents glog--the logging package used by ginkeycloak--from complaining. + flag.Parse() + + cfg := keycloakCfg{ + Host: "localhost", + Port: "1111", + Realm: "veraison", + } + + loader := config.NewLoader(&cfg) + if err := loader.LoadFromViper(v); err != nil { + return err + } + + o.config = ginkeycloak.KeycloakConfig{ + Url: fmt.Sprintf("http://%s:%s", cfg.Host, cfg.Port), + Realm: cfg.Realm, + CustomClaimsMapper: mapTenantID, + } + return nil +} + +func (o *KeycloakAuthorizer) Close() error { + return nil +} + +func (o *KeycloakAuthorizer) GetGinHandler(role string) gin.HandlerFunc { + return ginkeycloak.Auth(o.getAuthCheck([]string{role}), o.config) +} + +func (o *KeycloakAuthorizer) getAuthCheck( + roles []string, +) ginkeycloak.AccessCheckFunction { + return func(tc *ginkeycloak.TokenContainer, ctx *gin.Context) bool { + ctx.Set("token", *tc.KeyCloakToken) + ctx.Set("uid", tc.KeyCloakToken.PreferredUsername) + + roleOK := ginkeycloak.RealmCheck(roles)(tc, ctx) + + o.logger.Debugw("auth check", "role", roleOK) + + return roleOK + } +} + +func mapTenantID(jsonWebToken *jwt.JSONWebToken, keyCloakToken *ginkeycloak.KeyCloakToken) error { + var claims map[string]interface{} + + // note: this mapper function will only be called once the JWT had + // alreadybeen verified by ginkeycloak, so extracting claims without + // verification here is, in fact, safe. + if err := jsonWebToken.UnsafeClaimsWithoutVerification(&claims); err != nil { + return err + } + + var tenantId string + rawTenantId, ok := claims["tenant_id"] + if ok { + tenantId, ok = rawTenantId.(string) + if !ok { + return fmt.Errorf("tenant_id not a string: %v (%T)", + rawTenantId, rawTenantId) + } + } else { + + tenantId = "" + } + + keyCloakToken.CustomClaims = map[string]string{ + "tenant_id": tenantId, + } + + return nil +} diff --git a/auth/passthrough.go b/auth/passthrough.go new file mode 100644 index 00000000..9ab56de6 --- /dev/null +++ b/auth/passthrough.go @@ -0,0 +1,37 @@ +// Copyright 2023 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package auth + +import ( + "errors" + + "github.com/gin-gonic/gin" + "github.com/spf13/viper" + "go.uber.org/zap" +) + +type PassthroughAuthorizer struct { + logger *zap.SugaredLogger +} + +func NewPassthroughAuthorizer(logger *zap.SugaredLogger) IAuthorizer { + return &PassthroughAuthorizer{logger: logger} +} + +func (o *PassthroughAuthorizer) Init(v *viper.Viper, logger *zap.SugaredLogger) error { + if logger == nil { + return errors.New("nil logger") + } + o.logger = logger + return nil +} + +func (o *PassthroughAuthorizer) Close() error { + return nil +} + +func (o *PassthroughAuthorizer) GetGinHandler(role string) gin.HandlerFunc { + return func(c *gin.Context) { + o.logger.Debugw("passthrough", "path", c.Request.URL.Path) + } +} diff --git a/auth/roles.go b/auth/roles.go new file mode 100644 index 00000000..543bb701 --- /dev/null +++ b/auth/roles.go @@ -0,0 +1,7 @@ +// Copyright 2023 Contributors to the Veraison project. +// SPDX-License-Identifier: Apache-2.0 +package auth + +var NoRole = "" +var ManagerRole = "manager" +var ProvisionerRole = "provisioner" diff --git a/deployments/docker/Makefile b/deployments/docker/Makefile index 3ca4a547..3a1f512e 100644 --- a/deployments/docker/Makefile +++ b/deployments/docker/Makefile @@ -27,6 +27,8 @@ vts_FLAGS := -v $(STORES_VOLUME):/opt/veraison/stores management_FLAGS := -v $(STORES_VOLUME):/opt/veraison/stores -p $(MANAGEMENT_PORT):$(MANAGEMENT_PORT) provisioning_FLAGS := -p $(PROVISIONING_PORT):$(PROVISIONING_PORT) verification_FLAGS := -p $(VERIFICATION_PORT):$(VERIFICATION_PORT) +keycloak_FLAGS := -p $(KEYCLOAK_PORT):$(KEYCLOAK_PORT) -e KEYCLOAK_ADMIN=admin \ + -e KEYCLOAK_ADMIN_PASSWORD=admin ifneq ($(DEBUG_PORT),) DEBUG_PORT_FLAG := -p $(DEBUG_PORT):$(DEBUG_PORT) @@ -86,8 +88,8 @@ services: @# image targets (possibly because of the need to recursively resolve %, @# but I haven't looked too much into it). Recursively calling $(MAKE) here @# resolves the issue. - $(MAKE) .built/vts-container .built/provisioning-container .built/verification-container \ - .built/management-container + $(MAKE) .built/keycloak-container .built/vts-container .built/provisioning-container \ + .built/verification-container .built/management-container .PHONY: vts vts: deploy .built/vts-container @@ -113,6 +115,13 @@ management: deploy .built/management-container .PHONY: management-image management-image: deploy .built/management-image +.PHONY: keycloak +keycloak: deploy .built/keycloak-container + +.PHONY: keycloak-image +keycloak-image: deploy .built/keycloak-image + + .PHONY: network network: .built/network @@ -173,11 +182,12 @@ docker-clean: docker volume rm -f $(DEPLOY_DEST); \ fi @# -f ensures exit code 0, even if image doesn't exist - docker container rm -f vts-service provisioning-service verification-service management-service + docker container rm -f keycloak-service vts-service provisioning-service \ + verification-service management-service docker volume rm -f veraison-logs veraison-stores @# ubuntu uses an older version of docker without -f option for network; hence the || : cludge docker network rm $(VERAISON_NETWORK) || : - docker image rm -f veraison/builder veraison/vts veraison/provisioning \ + docker image rm -f veraison/builder veraison/keycloak veraison/vts veraison/provisioning \ veraison/verification veraison/manager rm -rf .built @@ -188,6 +198,7 @@ host-clean: rm -rf $(DEPLOY_DEST); \ fi rm -rf $(CONTEXT_DIR) + rm -f .built/deploy .PHONY: really-clean really-clean: clean docker-clean host-clean diff --git a/deployments/docker/deployment.cfg b/deployments/docker/deployment.cfg index 3bdd2077..f38a7676 100644 --- a/deployments/docker/deployment.cfg +++ b/deployments/docker/deployment.cfg @@ -13,6 +13,7 @@ VTS_PORT=50051 PROVISIONING_PORT=8888 VERIFICATION_PORT=8080 MANAGEMENT_PORT=8088 +KEYCLOAK_PORT=11111 # Deploy destination is either an absolute path to a directory on the host, or # the name of a docker volume. diff --git a/deployments/docker/src/builder-dispatcher b/deployments/docker/src/builder-dispatcher index 74175878..e37e8f63 100755 --- a/deployments/docker/src/builder-dispatcher +++ b/deployments/docker/src/builder-dispatcher @@ -37,6 +37,7 @@ function deploy() { cp $BUILD_DIR/scheme/bin/* $DEPLOY_DIR/plugins/ cp $BUILD_DIR/deployments/docker/src/skey.jwk $DEPLOY_DIR/ cp $BUILD_DIR/deployments/docker/src/service-entrypoint $DEPLOY_DIR/ + cp $BUILD_DIR/deployments/docker/src/veraison-realm.json $DEPLOY_DIR/ cp $gobin/evcli $DEPLOY_DIR/utils/ cp $gobin/cocli $DEPLOY_DIR/utils/ cp $gobin/pocli $DEPLOY_DIR/utils/ @@ -46,6 +47,7 @@ function deploy() { source $BUILD_DIR/deployments/docker/deployment.cfg set +a cat $BUILD_DIR/deployments/docker/src/config.yaml.template | envsubst > $DEPLOY_DIR/config.yaml + cat $BUILD_DIR/deployments/docker/src/keycloak.conf.template | envsubst > $DEPLOY_DIR/keycloak.conf echo "initializing stores" for t in en ta po diff --git a/deployments/docker/src/config.yaml.template b/deployments/docker/src/config.yaml.template index 717ab91d..b6a46a19 100644 --- a/deployments/docker/src/config.yaml.template +++ b/deployments/docker/src/config.yaml.template @@ -35,4 +35,8 @@ po-store: datasource: stores/vts/po-store.sql po-agent: backend: opa +auth: + backend: keycloak + host: keycloak-service + port: 11111 # vim: set ft=yaml: diff --git a/deployments/docker/src/keycloak.conf.template b/deployments/docker/src/keycloak.conf.template new file mode 100644 index 00000000..cb830852 --- /dev/null +++ b/deployments/docker/src/keycloak.conf.template @@ -0,0 +1,5 @@ +# See https://www.keycloak.org/server/all-config for all alvailable configuration. +http-enabled=true +http-port=${KEYCLOAK_PORT} +hostname-strict=false + diff --git a/deployments/docker/src/keycloak.docker b/deployments/docker/src/keycloak.docker new file mode 100644 index 00000000..44c170d9 --- /dev/null +++ b/deployments/docker/src/keycloak.docker @@ -0,0 +1,17 @@ +FROM quay.io/keycloak/keycloak:22.0.1 as keycloak-builder + +WORKDIR /opt/keycloak +# note: for development set up early; use proper certification in production. +RUN keytool -genkeypair -storepass password -storetype PKCS12 -keyalg RSA -keysize 2048 \ + -dname "CN=server" -alias server -ext "SAN:c=DNS:localhost,IP:127.0.0.1" \ + -keystore conf/server.keystore + +RUN /opt/keycloak/bin/kc.sh build + +FROM quay.io/keycloak/keycloak:22.0.1 +COPY --from=keycloak-builder /opt/keycloak/ /opt/keycloak/ +COPY keycloak.conf /opt/keycloak/conf/keycloak.conf +COPY veraison-realm.json /opt/keycloak/data/import/veraison-realm.json + +ENTRYPOINT ["/opt/keycloak/bin/kc.sh"] +CMD ["start", "--optimized", "--import-realm"] diff --git a/deployments/docker/src/load-config.mk b/deployments/docker/src/load-config.mk index d074c7e8..24a33c45 100644 --- a/deployments/docker/src/load-config.mk +++ b/deployments/docker/src/load-config.mk @@ -11,6 +11,7 @@ VTS_PORT ?= 50051 PROVISIONING_PORT ?= 8888 VERIFICATION_PORT ?= 8080 MANAGEMENT_PORT ?= 8088 +KEYCLOAK_PORT ?= 11111 # Deploy destination is either an absolute path to a directory on the host, or # the name of a docker volume. diff --git a/deployments/docker/src/veraison-realm.json b/deployments/docker/src/veraison-realm.json new file mode 100644 index 00000000..0fd76cb4 --- /dev/null +++ b/deployments/docker/src/veraison-realm.json @@ -0,0 +1,1841 @@ +{ + "id" : "f1c336ca-84a0-4bbf-b075-d6276bfb8f5e", + "realm" : "veraison", + "notBefore" : 0, + "defaultSignatureAlgorithm" : "RS256", + "revokeRefreshToken" : false, + "refreshTokenMaxReuse" : 0, + "accessTokenLifespan" : 1800, + "accessTokenLifespanForImplicitFlow" : 1800, + "ssoSessionIdleTimeout" : 1800, + "ssoSessionMaxLifespan" : 36000, + "ssoSessionIdleTimeoutRememberMe" : 0, + "ssoSessionMaxLifespanRememberMe" : 0, + "offlineSessionIdleTimeout" : 2592000, + "offlineSessionMaxLifespanEnabled" : false, + "offlineSessionMaxLifespan" : 5184000, + "clientSessionIdleTimeout" : 0, + "clientSessionMaxLifespan" : 0, + "clientOfflineSessionIdleTimeout" : 0, + "clientOfflineSessionMaxLifespan" : 0, + "accessCodeLifespan" : 60, + "accessCodeLifespanUserAction" : 300, + "accessCodeLifespanLogin" : 1800, + "actionTokenGeneratedByAdminLifespan" : 43200, + "actionTokenGeneratedByUserLifespan" : 300, + "oauth2DeviceCodeLifespan" : 600, + "oauth2DevicePollingInterval" : 5, + "enabled" : true, + "sslRequired" : "external", + "registrationAllowed" : false, + "registrationEmailAsUsername" : false, + "rememberMe" : false, + "verifyEmail" : false, + "loginWithEmailAllowed" : true, + "duplicateEmailsAllowed" : false, + "resetPasswordAllowed" : false, + "editUsernameAllowed" : false, + "bruteForceProtected" : false, + "permanentLockout" : false, + "maxFailureWaitSeconds" : 900, + "minimumQuickLoginWaitSeconds" : 60, + "waitIncrementSeconds" : 60, + "quickLoginCheckMilliSeconds" : 1000, + "maxDeltaTimeSeconds" : 43200, + "failureFactor" : 30, + "roles" : { + "realm" : [ { + "id" : "3c14c82e-ef6e-4c35-8fc5-b95322e12698", + "name" : "manager", + "description" : "Manages policies.", + "composite" : false, + "clientRole" : false, + "containerId" : "f1c336ca-84a0-4bbf-b075-d6276bfb8f5e", + "attributes" : { } + }, { + "id" : "29a6925f-81e8-4177-bb95-3c36bf4b7645", + "name" : "offline_access", + "description" : "${role_offline-access}", + "composite" : false, + "clientRole" : false, + "containerId" : "f1c336ca-84a0-4bbf-b075-d6276bfb8f5e", + "attributes" : { } + }, { + "id" : "03e833d2-8f65-4e1d-848a-87a01650b4d5", + "name" : "provisioner", + "description" : "Provisions trust anchors and endorsements.", + "composite" : false, + "clientRole" : false, + "containerId" : "f1c336ca-84a0-4bbf-b075-d6276bfb8f5e", + "attributes" : { } + }, { + "id" : "3c85b41b-2cd1-40af-9e31-c6a9d24114ce", + "name" : "default-roles-veraison", + "description" : "${role_default-roles}", + "composite" : true, + "composites" : { + "realm" : [ "offline_access", "uma_authorization" ], + "client" : { + "account" : [ "view-profile", "manage-account" ] + } + }, + "clientRole" : false, + "containerId" : "f1c336ca-84a0-4bbf-b075-d6276bfb8f5e", + "attributes" : { } + }, { + "id" : "a40e1662-6ddb-4fd7-829a-ffece56b48d2", + "name" : "uma_authorization", + "description" : "${role_uma_authorization}", + "composite" : false, + "clientRole" : false, + "containerId" : "f1c336ca-84a0-4bbf-b075-d6276bfb8f5e", + "attributes" : { } + } ], + "client" : { + "realm-management" : [ { + "id" : "66fc745f-b46a-4efa-bd17-77e060d7b2a0", + "name" : "view-realm", + "description" : "${role_view-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "b0d0efb7-3691-4ead-b33a-f16191bc5789", + "name" : "realm-admin", + "description" : "${role_realm-admin}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "view-realm", "view-authorization", "view-clients", "manage-identity-providers", "query-clients", "query-groups", "manage-events", "create-client", "manage-users", "manage-clients", "view-users", "view-identity-providers", "manage-realm", "manage-authorization", "query-realms", "impersonation", "query-users", "view-events" ] + } + }, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "a34cb720-d7c5-408b-8b52-ed426d6d809c", + "name" : "view-authorization", + "description" : "${role_view-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "44017973-fe85-45b5-b7f5-f53a757bce73", + "name" : "view-clients", + "description" : "${role_view-clients}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-clients" ] + } + }, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "00eb870e-9ca7-4933-8809-4c536c1a22f6", + "name" : "manage-identity-providers", + "description" : "${role_manage-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "c1fa45d6-dd02-4487-9cc2-6293f825467b", + "name" : "query-clients", + "description" : "${role_query-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "0d5c3ba5-7763-472c-9239-f946931e413f", + "name" : "query-groups", + "description" : "${role_query-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "fcc850bb-f082-4dd6-b5ab-510d1cc89311", + "name" : "create-client", + "description" : "${role_create-client}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "2b8e4b72-1c63-4528-9be5-271868c1372a", + "name" : "manage-events", + "description" : "${role_manage-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "bcf9a96e-d875-4548-adb0-8768404e54f7", + "name" : "manage-users", + "description" : "${role_manage-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "a9cb8f89-fec3-4679-a0fc-3557cacc8c0f", + "name" : "manage-clients", + "description" : "${role_manage-clients}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "9186b791-8864-4373-85d4-f27a4895ec9b", + "name" : "view-users", + "description" : "${role_view-users}", + "composite" : true, + "composites" : { + "client" : { + "realm-management" : [ "query-groups", "query-users" ] + } + }, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "67eeb9b5-6368-4489-9606-d04a7c78e330", + "name" : "view-identity-providers", + "description" : "${role_view-identity-providers}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "50da5487-88c2-4c51-b95c-a7249e283df2", + "name" : "manage-realm", + "description" : "${role_manage-realm}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "aca9a2d7-f1bc-4b2e-827d-d366fdfce45a", + "name" : "manage-authorization", + "description" : "${role_manage-authorization}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "93cdc235-c527-4818-9601-3f27503a5988", + "name" : "query-realms", + "description" : "${role_query-realms}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "41419687-e0a3-4a1b-a380-8a200f2ae2a8", + "name" : "impersonation", + "description" : "${role_impersonation}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "66c8d39f-46de-4861-934e-440998d5e427", + "name" : "query-users", + "description" : "${role_query-users}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + }, { + "id" : "50d9bd9d-d100-48be-8239-2661a6a13ca7", + "name" : "view-events", + "description" : "${role_view-events}", + "composite" : false, + "clientRole" : true, + "containerId" : "4882f437-a423-46a1-878c-10616b7d6117", + "attributes" : { } + } ], + "security-admin-console" : [ ], + "admin-cli" : [ ], + "account-console" : [ ], + "broker" : [ { + "id" : "cdeea646-d366-479d-b2d2-40853d6d363d", + "name" : "read-token", + "description" : "${role_read-token}", + "composite" : false, + "clientRole" : true, + "containerId" : "e9f5fb23-6688-4a97-897c-fe9f6a370c64", + "attributes" : { } + } ], + "account" : [ { + "id" : "0b90f930-8203-4599-be96-e5a5cac8ee7b", + "name" : "view-applications", + "description" : "${role_view-applications}", + "composite" : false, + "clientRole" : true, + "containerId" : "b8302e03-6c05-4a42-85e9-a46370d2b76b", + "attributes" : { } + }, { + "id" : "2c7d0710-a3d8-4a40-9f2e-8143f2e9e153", + "name" : "view-profile", + "description" : "${role_view-profile}", + "composite" : false, + "clientRole" : true, + "containerId" : "b8302e03-6c05-4a42-85e9-a46370d2b76b", + "attributes" : { } + }, { + "id" : "d3434c63-75fc-4ac2-af54-91ce26ace472", + "name" : "manage-account", + "description" : "${role_manage-account}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "manage-account-links" ] + } + }, + "clientRole" : true, + "containerId" : "b8302e03-6c05-4a42-85e9-a46370d2b76b", + "attributes" : { } + }, { + "id" : "7846f314-a5f3-4bac-a02c-7da437c300ce", + "name" : "manage-consent", + "description" : "${role_manage-consent}", + "composite" : true, + "composites" : { + "client" : { + "account" : [ "view-consent" ] + } + }, + "clientRole" : true, + "containerId" : "b8302e03-6c05-4a42-85e9-a46370d2b76b", + "attributes" : { } + }, { + "id" : "2f69f35f-6748-4002-aecf-85d194c28d94", + "name" : "manage-account-links", + "description" : "${role_manage-account-links}", + "composite" : false, + "clientRole" : true, + "containerId" : "b8302e03-6c05-4a42-85e9-a46370d2b76b", + "attributes" : { } + }, { + "id" : "1edba5fd-9d7e-4a15-8dcf-3a14a4b738cc", + "name" : "delete-account", + "description" : "${role_delete-account}", + "composite" : false, + "clientRole" : true, + "containerId" : "b8302e03-6c05-4a42-85e9-a46370d2b76b", + "attributes" : { } + }, { + "id" : "ce9b2c54-d838-42ae-bbe6-d6ee70e46902", + "name" : "view-consent", + "description" : "${role_view-consent}", + "composite" : false, + "clientRole" : true, + "containerId" : "b8302e03-6c05-4a42-85e9-a46370d2b76b", + "attributes" : { } + }, { + "id" : "4df2f06c-a286-4f29-bb5e-c5259780099c", + "name" : "view-groups", + "description" : "${role_view-groups}", + "composite" : false, + "clientRole" : true, + "containerId" : "b8302e03-6c05-4a42-85e9-a46370d2b76b", + "attributes" : { } + } ], + "veraison-client" : [ ] + } + }, + "groups" : [ ], + "defaultRole" : { + "id" : "3c85b41b-2cd1-40af-9e31-c6a9d24114ce", + "name" : "default-roles-veraison", + "description" : "${role_default-roles}", + "composite" : true, + "clientRole" : false, + "containerId" : "f1c336ca-84a0-4bbf-b075-d6276bfb8f5e" + }, + "requiredCredentials" : [ "password" ], + "otpPolicyType" : "totp", + "otpPolicyAlgorithm" : "HmacSHA1", + "otpPolicyInitialCounter" : 0, + "otpPolicyDigits" : 6, + "otpPolicyLookAheadWindow" : 1, + "otpPolicyPeriod" : 30, + "otpPolicyCodeReusable" : false, + "otpSupportedApplications" : [ "totpAppMicrosoftAuthenticatorName", "totpAppGoogleName", "totpAppFreeOTPName" ], + "webAuthnPolicyRpEntityName" : "keycloak", + "webAuthnPolicySignatureAlgorithms" : [ "ES256" ], + "webAuthnPolicyRpId" : "", + "webAuthnPolicyAttestationConveyancePreference" : "not specified", + "webAuthnPolicyAuthenticatorAttachment" : "not specified", + "webAuthnPolicyRequireResidentKey" : "not specified", + "webAuthnPolicyUserVerificationRequirement" : "not specified", + "webAuthnPolicyCreateTimeout" : 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyAcceptableAaguids" : [ ], + "webAuthnPolicyPasswordlessRpEntityName" : "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms" : [ "ES256" ], + "webAuthnPolicyPasswordlessRpId" : "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference" : "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment" : "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey" : "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement" : "not specified", + "webAuthnPolicyPasswordlessCreateTimeout" : 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister" : false, + "webAuthnPolicyPasswordlessAcceptableAaguids" : [ ], + "users" : [ { + "id" : "778a3424-b538-415c-b9c6-ade0e483d818", + "createdTimestamp" : 1692274136073, + "username" : "veraison-manager", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "firstName" : "", + "lastName" : "", + "credentials" : [ { + "id" : "086eb891-30fd-408d-91a0-7d4c8a701f54", + "type" : "password", + "userLabel" : "My password", + "createdDate" : 1692274151671, + "secretData" : "{\"value\":\"KDJZv/qvMYMCb5v18ymqGrKy9ZPk/3zB3WvrzwFogRI=\",\"salt\":\"zU0ayGQFxfgyU2T2EU90+w==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "manager", "default-roles-veraison" ], + "notBefore" : 0, + "groups" : [ ] + }, { + "id" : "3d0bfa21-50b0-496a-9a22-c6e1f63238f9", + "createdTimestamp" : 1692274044033, + "username" : "veraison-provisioner", + "enabled" : true, + "totp" : false, + "emailVerified" : false, + "firstName" : "", + "lastName" : "", + "credentials" : [ { + "id" : "0dd61192-932a-4972-a168-2c4867673396", + "type" : "password", + "userLabel" : "My password", + "createdDate" : 1692275392983, + "secretData" : "{\"value\":\"+uFdoOr+hk62Z87HGA9RvWcXhJMNX4YHPjmkjJSK16U=\",\"salt\":\"s/dmj1YbJ+/yLdbnmAg/8Q==\",\"additionalParameters\":{}}", + "credentialData" : "{\"hashIterations\":27500,\"algorithm\":\"pbkdf2-sha256\",\"additionalParameters\":{}}" + } ], + "disableableCredentialTypes" : [ ], + "requiredActions" : [ ], + "realmRoles" : [ "provisioner", "default-roles-veraison" ], + "notBefore" : 0, + "groups" : [ ] + } ], + "scopeMappings" : [ { + "clientScope" : "offline_access", + "roles" : [ "offline_access" ] + } ], + "clientScopeMappings" : { + "account" : [ { + "client" : "account-console", + "roles" : [ "manage-account", "view-groups" ] + } ] + }, + "clients" : [ { + "id" : "b8302e03-6c05-4a42-85e9-a46370d2b76b", + "clientId" : "account", + "name" : "${client_account}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/veraison/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/veraison/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "0124f2b3-be1b-49b5-a113-352d1ffe299a", + "clientId" : "account-console", + "name" : "${client_account-console}", + "rootUrl" : "${authBaseUrl}", + "baseUrl" : "/realms/veraison/account/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/realms/veraison/account/*" ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+", + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "3b63fc08-5779-4dc5-a2ce-5a22a201fd49", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "b2e061bf-883b-4534-925b-f3aafb433fd7", + "clientId" : "admin-cli", + "name" : "${client_admin-cli}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : false, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "e9f5fb23-6688-4a97-897c-fe9f6a370c64", + "clientId" : "broker", + "name" : "${client_broker}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "4882f437-a423-46a1-878c-10616b7d6117", + "clientId" : "realm-management", + "name" : "${client_realm-management}", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ ], + "webOrigins" : [ ], + "notBefore" : 0, + "bearerOnly" : true, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "9fc0fda8-3c5e-46d4-ae64-126fa11ecbb3", + "clientId" : "security-admin-console", + "name" : "${client_security-admin-console}", + "rootUrl" : "${authAdminUrl}", + "baseUrl" : "/admin/veraison/console/", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : false, + "clientAuthenticatorType" : "client-secret", + "redirectUris" : [ "/admin/veraison/console/*" ], + "webOrigins" : [ "+" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : false, + "serviceAccountsEnabled" : false, + "publicClient" : true, + "frontchannelLogout" : false, + "protocol" : "openid-connect", + "attributes" : { + "post.logout.redirect.uris" : "+", + "pkce.code.challenge.method" : "S256" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : false, + "nodeReRegistrationTimeout" : 0, + "protocolMappers" : [ { + "id" : "7bd436f6-4a54-425e-bb6c-7de806fcf84d", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + } ], + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + }, { + "id" : "30ea0b69-30fe-46bd-82f7-ac1f980b6928", + "clientId" : "veraison-client", + "name" : "", + "description" : "", + "rootUrl" : "", + "adminUrl" : "", + "baseUrl" : "", + "surrogateAuthRequired" : false, + "enabled" : true, + "alwaysDisplayInConsole" : true, + "clientAuthenticatorType" : "client-secret", + "secret" : "YifmabB4cVSPPtFLAmHfq7wKaEHQn10Z", + "redirectUris" : [ "/*" ], + "webOrigins" : [ "/*" ], + "notBefore" : 0, + "bearerOnly" : false, + "consentRequired" : false, + "standardFlowEnabled" : true, + "implicitFlowEnabled" : false, + "directAccessGrantsEnabled" : true, + "serviceAccountsEnabled" : false, + "publicClient" : false, + "frontchannelLogout" : true, + "protocol" : "openid-connect", + "attributes" : { + "oidc.ciba.grant.enabled" : "false", + "client.secret.creation.time" : "1692267068", + "backchannel.logout.session.required" : "true", + "post.logout.redirect.uris" : "+", + "oauth2.device.authorization.grant.enabled" : "false", + "display.on.consent.screen" : "false", + "backchannel.logout.revoke.offline.tokens" : "false" + }, + "authenticationFlowBindingOverrides" : { }, + "fullScopeAllowed" : true, + "nodeReRegistrationTimeout" : -1, + "defaultClientScopes" : [ "web-origins", "acr", "profile", "roles", "email" ], + "optionalClientScopes" : [ "address", "phone", "offline_access", "microprofile-jwt" ] + } ], + "clientScopes" : [ { + "id" : "cdb2454d-355f-46e6-8c75-5ee7d104011d", + "name" : "profile", + "description" : "OpenID Connect built-in scope: profile", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${profileScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "5a0ee988-c3b5-400d-a77a-b6db95b44583", + "name" : "zoneinfo", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "zoneinfo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "zoneinfo", + "jsonType.label" : "String" + } + }, { + "id" : "57f0aa40-359f-4f54-8413-1c414d95dc62", + "name" : "given name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "firstName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "given_name", + "jsonType.label" : "String" + } + }, { + "id" : "2fb49e8e-fceb-4ebf-a4f8-b7b074d076fb", + "name" : "nickname", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "nickname", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "nickname", + "jsonType.label" : "String" + } + }, { + "id" : "fe6d8736-c643-4189-bff0-22179ccd0173", + "name" : "gender", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "gender", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "gender", + "jsonType.label" : "String" + } + }, { + "id" : "1407f674-94da-4baf-85a7-4825673df97a", + "name" : "full name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-full-name-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "access.token.claim" : "true", + "userinfo.token.claim" : "true" + } + }, { + "id" : "7d79f487-aa57-414e-b68f-b731056aef2a", + "name" : "birthdate", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "birthdate", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "birthdate", + "jsonType.label" : "String" + } + }, { + "id" : "d2296431-072a-4bf1-87be-6e0f390e255a", + "name" : "middle name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "middleName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "middle_name", + "jsonType.label" : "String" + } + }, { + "id" : "162ede80-8a96-47ae-9671-0c6eb1bfe520", + "name" : "username", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "preferred_username", + "jsonType.label" : "String" + } + }, { + "id" : "c93b9d49-5826-45ac-b05a-c4c5fafa5b96", + "name" : "family name", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "lastName", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "family_name", + "jsonType.label" : "String" + } + }, { + "id" : "e7cf775c-3af5-4ae4-aaf4-85a84999d064", + "name" : "picture", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "picture", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "picture", + "jsonType.label" : "String" + } + }, { + "id" : "15c2e269-faff-4013-a68d-ed20ea46031e", + "name" : "locale", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "locale", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "locale", + "jsonType.label" : "String" + } + }, { + "id" : "70ad35eb-7736-487d-b4c0-42fd4fe0d563", + "name" : "updated at", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "updatedAt", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "updated_at", + "jsonType.label" : "long" + } + }, { + "id" : "b4b48ad4-f324-47d9-a0dc-7d5a47c5126d", + "name" : "website", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "website", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "website", + "jsonType.label" : "String" + } + }, { + "id" : "ed92a954-3a49-4cda-ad97-c5c605639344", + "name" : "profile", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "profile", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "profile", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "622a036e-ec1b-4591-8304-38f6383d5405", + "name" : "offline_access", + "description" : "OpenID Connect built-in scope: offline_access", + "protocol" : "openid-connect", + "attributes" : { + "consent.screen.text" : "${offlineAccessScopeConsentText}", + "display.on.consent.screen" : "true" + } + }, { + "id" : "a53cf6f7-1ecc-403d-9574-f0691388e401", + "name" : "web-origins", + "description" : "OpenID Connect scope for add allowed web origins to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false", + "consent.screen.text" : "" + }, + "protocolMappers" : [ { + "id" : "798ddcba-546b-452d-9d15-27cd5b12b1be", + "name" : "allowed web origins", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-allowed-origins-mapper", + "consentRequired" : false, + "config" : { } + } ] + }, { + "id" : "801544eb-e426-478f-b9f1-d9292d521147", + "name" : "address", + "description" : "OpenID Connect built-in scope: address", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${addressScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "7461381f-3dbf-49d7-b033-619b0148ca09", + "name" : "address", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-address-mapper", + "consentRequired" : false, + "config" : { + "user.attribute.formatted" : "formatted", + "user.attribute.country" : "country", + "user.attribute.postal_code" : "postal_code", + "userinfo.token.claim" : "true", + "user.attribute.street" : "street", + "id.token.claim" : "true", + "user.attribute.region" : "region", + "access.token.claim" : "true", + "user.attribute.locality" : "locality" + } + } ] + }, { + "id" : "01d158bf-8c4f-4b3d-b84a-141e114c0b8f", + "name" : "role_list", + "description" : "SAML role list", + "protocol" : "saml", + "attributes" : { + "consent.screen.text" : "${samlRoleListScopeConsentText}", + "display.on.consent.screen" : "true" + }, + "protocolMappers" : [ { + "id" : "4eb1eb4a-5f27-434b-a141-a9f6902d93d5", + "name" : "role list", + "protocol" : "saml", + "protocolMapper" : "saml-role-list-mapper", + "consentRequired" : false, + "config" : { + "single" : "false", + "attribute.nameformat" : "Basic", + "attribute.name" : "Role" + } + } ] + }, { + "id" : "3f241149-6525-4a09-89da-649094ab0e47", + "name" : "email", + "description" : "OpenID Connect built-in scope: email", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${emailScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "43909b68-6505-4119-abd9-df8447ab6dfc", + "name" : "email", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "email", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email", + "jsonType.label" : "String" + } + }, { + "id" : "1caf557c-c8c4-4e5e-bf42-20365baa40e1", + "name" : "email verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-property-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "emailVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "email_verified", + "jsonType.label" : "boolean" + } + } ] + }, { + "id" : "c8fa1b3b-d9ef-4fef-b291-35318d6817ad", + "name" : "roles", + "description" : "OpenID Connect scope for add user roles to the access token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${rolesScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "e1fbb06d-9b7f-4e2f-ae8c-a2d0cd41dc76", + "name" : "realm roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "access.token.claim" : "true", + "claim.name" : "realm_access.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + }, { + "id" : "b3875b32-f72d-4fed-ac28-fe48b94261bf", + "name" : "audience resolve", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-audience-resolve-mapper", + "consentRequired" : false, + "config" : { } + }, { + "id" : "e9094f82-a0ed-47e2-b484-377e55e24d68", + "name" : "client roles", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-client-role-mapper", + "consentRequired" : false, + "config" : { + "user.attribute" : "foo", + "access.token.claim" : "true", + "claim.name" : "resource_access.${client_id}.roles", + "jsonType.label" : "String", + "multivalued" : "true" + } + } ] + }, { + "id" : "23735c41-4b70-46b0-8bd8-66d6db6ae200", + "name" : "microprofile-jwt", + "description" : "Microprofile - JWT built-in scope", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "4d7eb99e-09bb-450f-9f22-324d52dc58da", + "name" : "groups", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-realm-role-mapper", + "consentRequired" : false, + "config" : { + "multivalued" : "true", + "userinfo.token.claim" : "true", + "user.attribute" : "foo", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "groups", + "jsonType.label" : "String" + } + }, { + "id" : "70c1a038-13c6-405a-8e90-ea23930a7ff3", + "name" : "upn", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "username", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "upn", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "e24a3896-7bc6-4007-9582-852cf918aaab", + "name" : "phone", + "description" : "OpenID Connect built-in scope: phone", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "true", + "display.on.consent.screen" : "true", + "consent.screen.text" : "${phoneScopeConsentText}" + }, + "protocolMappers" : [ { + "id" : "523c6a94-87a6-4022-bdbf-842b2b2a2ac4", + "name" : "phone number verified", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumberVerified", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number_verified", + "jsonType.label" : "boolean" + } + }, { + "id" : "4adfae7f-d902-467f-91a0-22bbfa3b845f", + "name" : "phone number", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-usermodel-attribute-mapper", + "consentRequired" : false, + "config" : { + "userinfo.token.claim" : "true", + "user.attribute" : "phoneNumber", + "id.token.claim" : "true", + "access.token.claim" : "true", + "claim.name" : "phone_number", + "jsonType.label" : "String" + } + } ] + }, { + "id" : "a867d920-baaf-424b-8e56-8c941f79bbd9", + "name" : "acr", + "description" : "OpenID Connect scope for add acr (authentication context class reference) to the token", + "protocol" : "openid-connect", + "attributes" : { + "include.in.token.scope" : "false", + "display.on.consent.screen" : "false" + }, + "protocolMappers" : [ { + "id" : "da651414-ffb1-4e47-a2ca-cdd1c6270481", + "name" : "acr loa level", + "protocol" : "openid-connect", + "protocolMapper" : "oidc-acr-mapper", + "consentRequired" : false, + "config" : { + "id.token.claim" : "true", + "access.token.claim" : "true", + "userinfo.token.claim" : "true" + } + } ] + } ], + "defaultDefaultClientScopes" : [ "role_list", "profile", "email", "roles", "web-origins", "acr" ], + "defaultOptionalClientScopes" : [ "offline_access", "address", "phone", "microprofile-jwt" ], + "browserSecurityHeaders" : { + "contentSecurityPolicyReportOnly" : "", + "xContentTypeOptions" : "nosniff", + "referrerPolicy" : "no-referrer", + "xRobotsTag" : "none", + "xFrameOptions" : "SAMEORIGIN", + "contentSecurityPolicy" : "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection" : "1; mode=block", + "strictTransportSecurity" : "max-age=31536000; includeSubDomains" + }, + "smtpServer" : { }, + "eventsEnabled" : false, + "eventsListeners" : [ "jboss-logging" ], + "enabledEventTypes" : [ ], + "adminEventsEnabled" : false, + "adminEventsDetailsEnabled" : false, + "identityProviders" : [ ], + "identityProviderMappers" : [ ], + "components" : { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy" : [ { + "id" : "838db39f-26e9-49f4-a032-522e8a817212", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "5516ee07-cd4c-40c2-8ee0-c39010f6c521", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "saml-user-property-mapper", "oidc-usermodel-attribute-mapper", "saml-user-attribute-mapper", "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "oidc-full-name-mapper", "saml-role-list-mapper", "oidc-usermodel-property-mapper" ] + } + }, { + "id" : "961ce4e7-198c-49bc-b988-6b87f313b89b", + "name" : "Max Clients Limit", + "providerId" : "max-clients", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "max-clients" : [ "200" ] + } + }, { + "id" : "ad3a8ca5-9bd9-4c97-a7c7-ec04a2ad6279", + "name" : "Consent Required", + "providerId" : "consent-required", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "875ae783-21e0-4971-8643-e0d9dfbce3e1", + "name" : "Allowed Protocol Mapper Types", + "providerId" : "allowed-protocol-mappers", + "subType" : "authenticated", + "subComponents" : { }, + "config" : { + "allowed-protocol-mapper-types" : [ "oidc-address-mapper", "oidc-sha256-pairwise-sub-mapper", "saml-role-list-mapper", "oidc-usermodel-attribute-mapper", "oidc-full-name-mapper", "saml-user-attribute-mapper", "saml-user-property-mapper", "oidc-usermodel-property-mapper" ] + } + }, { + "id" : "4bce5375-223e-41cd-af02-1d3813895b07", + "name" : "Full Scope Disabled", + "providerId" : "scope", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { } + }, { + "id" : "23ace297-c838-4fa3-ae94-3f0e01d257d5", + "name" : "Allowed Client Scopes", + "providerId" : "allowed-client-templates", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "allow-default-scopes" : [ "true" ] + } + }, { + "id" : "69da926b-3bb5-433c-80bd-906a4180a8bf", + "name" : "Trusted Hosts", + "providerId" : "trusted-hosts", + "subType" : "anonymous", + "subComponents" : { }, + "config" : { + "host-sending-registration-request-must-match" : [ "true" ], + "client-uris-must-match" : [ "true" ] + } + } ], + "org.keycloak.keys.KeyProvider" : [ { + "id" : "94bc520a-7994-42a9-8083-3c185e66eca8", + "name" : "hmac-generated", + "providerId" : "hmac-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "a7e63c45-88cb-4a77-a458-a55473909d17" ], + "secret" : [ "tbWy-FjQ4PPZClLRCByN5PAWOh5oHwlPjJklDF-WyYpr4WCQnfBnUPnBdEI6ThyGEZ1oSGEq3wnivoQMARYLOA" ], + "priority" : [ "100" ], + "algorithm" : [ "HS256" ] + } + }, { + "id" : "ea51c427-9158-4564-ad9c-fccff828ea2a", + "name" : "rsa-enc-generated", + "providerId" : "rsa-enc-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEpQIBAAKCAQEAwQ1evDFc9jC1e6SZuM4oAVs+O1Mj8iXK6otj4aYG5ox2I9Vg2AjaF53oX0b9PIUyvkdxpPYBPIqkfe7P6woXjOZEiUo/vQfR79qdjwjfWLhOGuLezj2OQjAEzRdg4A2LhMDYv8rc5S3aTJ1Q7hdXe+ETDg6o/2ou/IJyIXcz9HDnIelrtPTemmQbrSFvYh8NLJwLqLfa4KxCVnUiwOGWed6L96lV8Z6W+R7ssN/XekaPf8fsfxXn4DFU7mGHEpjEfInUHg7oQMSFotCbDFg1JFKLRIFOZvo3690cgdf/VaeWvYuc5WEK+hEHq2POXIYTpUtNndGasdKQBnhY88ZZqwIDAQABAoIBAAWMOCVkWG2NZ3RkKIlnsz1GvU/AdeSm3WFGxtoHMWToCG/DLq3xTdh75d+cZKPxQqIL34zZXPO7xY+w5dy1RN6nB1/X+GOa7peGoBx/fsZH6vFZhQRG6ehRBPJNMlrTSNJ0evDCsv0LB55IBGQIhlpoVL8vVf/xBzn5GFqJ2GkKgMdUTVeLIOt48V/raoN4lS0g8jJMypOorXs17JLPKsECOFm4VKKzYQ/S5JHi/Cq9PcSex+V2nD/blh5FqbVWYxGP5hFPHx0N37Hi8fxZAXAT8mHShNyT7NnPsdgy6kEJ09tET9KP3A7ymlzXD8BXoWEKBMvvepfyle4GTNxDuuECgYEA46+2yQaAINnKMzFcI4Smk8H8vLM3lXl5bXWBqYTx4FeB0VOsLBn46IOu8pxJw2nx2htPmKUDkcQZO0NqOz3MTIxVgjwidRnzmp3p0K4GDeKdnO7KGyDxScQxqNl4zuQc/l15YfQN09jBxt6WtjF+qXUV6qGiNHGkQFxMRF4T6LMCgYEA2Q8YLIjgJybWsHQ7fvHNNMQjQGGRAdSWRHJLfpJU/icfjrLCB/3i+Pc17UmovRtJIYUzHVs54rAB5tl7yNc7g0XMhTCxCV/0ETPYlKL3Yb18aZvSvwp7R3Nxru/y1l/E1R9vyF8bwzVthe2Any53Ru/cJhhUknXZPHYI4++aFykCgYEA1kI8V9/uIvvP82y3sBTcTJ94HnroC5lMU10Ir2WT1/GBEGMU2kt2mBeTQmsgXuwL05tvw81FFp7av5IpHaaB4mcM8Il2Q4wwWYfQx7d7qwVeHJf5SJ4vcaNWt/YuYUL4pcWAvFTVzk1jzKkaWkkpUH4GKc4AvilSz94LRyrgwVECgYEArAnytxml0GJQN3tozK0KYJA1AIpUTIcasxWEEMYa53ZK5Od6MqtggsQt0e1X+Mrvo8nXQaVUs/+dAkPOgNlXKizgdZCqQSv0Xs4hE243dRiiy3HeD91W6MLvkCBO8OrnL6TDDKWVc5udO1GLaJ+Dmo3yh58xKQSPMgS79y2pjEECgYEA2yjd8vfqRVcsnz6LimX2YIMIlRYd867de4sEIhJHSfXspxD5UgVj9cxn6BUvzAafFH1cFV+LR7DU4IjgBsWsYWYq1Kt1SXrrxwh7LmYT6PX2z7jfk6jRcpsZPNJdCDqmW03Ex+xLGUKKj7C5vMhe/fZqV383rGTKPuO81AVxjKI=" ], + "certificate" : [ "MIICnzCCAYcCBgGKA2Q2rTANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAh2ZXJhaXNvbjAeFw0yMzA4MTcxMjA1MTNaFw0zMzA4MTcxMjA2NTNaMBMxETAPBgNVBAMMCHZlcmFpc29uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwQ1evDFc9jC1e6SZuM4oAVs+O1Mj8iXK6otj4aYG5ox2I9Vg2AjaF53oX0b9PIUyvkdxpPYBPIqkfe7P6woXjOZEiUo/vQfR79qdjwjfWLhOGuLezj2OQjAEzRdg4A2LhMDYv8rc5S3aTJ1Q7hdXe+ETDg6o/2ou/IJyIXcz9HDnIelrtPTemmQbrSFvYh8NLJwLqLfa4KxCVnUiwOGWed6L96lV8Z6W+R7ssN/XekaPf8fsfxXn4DFU7mGHEpjEfInUHg7oQMSFotCbDFg1JFKLRIFOZvo3690cgdf/VaeWvYuc5WEK+hEHq2POXIYTpUtNndGasdKQBnhY88ZZqwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBykUMKuwsNci+zvJdnRPINREzBxVJGbpwJTYdWT8dNYHLakP0HhRXDqAzWdBQkuqSTroUjCSxKsLfnoon3dAQkYM/64yCHFo13a1wtg0pJw0o8BTM5j2TrjnFWvj7XR0xiRGpj2yz0as4gN29Gj3Atw1IEkBnSO4BySEyTou7fGEqWcE6OUWAeyA5OCuCs7geSbghNNCrCMnyKAGLIgidGI7CgopZMQqJ/UoiPXHNuor+N3TMiDYZ3knsi9jY8bJ1DixbkjOVmaG3VI7z5iwNF7jrOpY7XR9SMKt32QFxf1VXMGzygiBoRPIpt6OENGO4naJTIAVLwaZxaUxClOz+G" ], + "priority" : [ "100" ], + "algorithm" : [ "RSA-OAEP" ] + } + }, { + "id" : "af7c0bdc-1ea0-4c0a-9a95-035e49102c23", + "name" : "rsa-generated", + "providerId" : "rsa-generated", + "subComponents" : { }, + "config" : { + "privateKey" : [ "MIIEpAIBAAKCAQEApJR7Ia2PCedukU9Rsb4CPlzs4UNiAIk5ou/4bTLEMQx8Cb6P4UNJoG95Wpf8jsaZtRUVei+SB7BWLfcPi4w7x6JRhrS67vOxH+P4BbtMqdg5aID/fCxUTMJMiSWx9R39PC6mFzc4ZvxzBvNmIbBBiFWuIHeYZOR/3lcrLTh1r9pCYywRzGPbY0u/8CWDxaQJGrNSGjnEXqL97TTuMuu2t07XJAglPsJR63fxOqgd5RET39uDHQqbLy7bxNiCq9+vMcF6JTr13KYDHmtb4qPT95zoqhRHrCI7EI+ruozpoQG6OV/IOXGJhYyFBjMZLCOIMWWoX510QPmQyRNwHsUT3wIDAQABAoIBABpmLXYSe+jlHumKD/BIf92hqZGHQyITi5OPld7A5OglONmV9UhMiHPb+FryxDKMDWhsMFzADVbUZI53nHO66R/gRomAAKLcTg4afX9AiE86KBiTkJJKHgo4pG7fWrNBveFjGNs3zVafqefJ2m5kR668Z5488MybkR3eB5v3ptEFGgU2ruCFbcLSLM0Rg5MwvXuxNrBFLLvQFsAatofFuDEcGHEXX6Rc+3WY8zK/rvFPhB1O2hCuoj+Ka2NcjEQgetlK4KKYBm42mwV0vqNE6t8ewR3+MvJnr6fWOfTlqR+UQ4BbPEteXrV8Hwi4hSAWrrr9MZgBBzUeKroSHgsAUrkCgYEAzhDK4FQCuEGCoEFVKGGD996qXI1j+yLXC4QrIqHyu8Al+GNpJwVgsUWsF9MfhVNjtctBb2qkIdwfV3nlAA2Sg8gHSDVWA5hAgK8d05qCj3aEuxk/xkb2naluuAvztycVaub7Wn54hq8pY3wOifgMl4Qz+7FoAxFNv8HAgrgIJxUCgYEAzHYk7VXjmiTY9DEXXnd6SugVZu5WTSqykPB7nFfosIIdgi0uInFHdhDMdHR97dW7GZkMB1p8zoVdSrJaU6iiDelfbXFX69tQtPbi3eVqls5htUuvozCNyz7eeZnHQ2EKsxpIZC+OOWHTJbUtGDYRG6yvOqqGR1ZTUNUB9g03zCMCgYB8ABTlKwi78gf2AXqKIywzo1Um/ppUjGGVd4Ixg/y6SGVQ9BlZtt25rzBg4dXM+CI/SkFlF2oPShO+IwbPolsxW9Qt+pJ49UyTY01ygT7hr7Mtl4MOALP0qfmLXP3aj/VOcBJ/IS3L9mnUiNmC4rZJEu/pHJd3iRkdNC1xO+cEBQKBgQCGenqFQ8Wkn/G2gwds0ca0t/tDrSVEMf4qyJF03nkkhyAje9XpP3qSFDB1tB0Trk0WZAx+VazbJOqcc7xnY/XakpF6aV87uQ9XRz8mVXuK3wly9en6ure4Y4xujI98KLqh3HqaspCn+0imd4jGcOFFw4mpW3lgOE4qTz+v9zeo4wKBgQCNdhsXJs1gGwgwr5cyUA6XWvoXt5XaQPbSDe8g1h5Va4K28aU3Z+FoDrq6xCkb7klk38S0grQmykGXnVKw/6R09I3WRwe7U9OGjxiN99jDG/wc0qIxdW2XxlvPgphi4AR/XbD16hvhVHecL3p4frjJAu2kp7GFieNcVFPjtcQm2g==" ], + "certificate" : [ "MIICnzCCAYcCBgGKA2Q3iTANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAh2ZXJhaXNvbjAeFw0yMzA4MTcxMjA1MTRaFw0zMzA4MTcxMjA2NTRaMBMxETAPBgNVBAMMCHZlcmFpc29uMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApJR7Ia2PCedukU9Rsb4CPlzs4UNiAIk5ou/4bTLEMQx8Cb6P4UNJoG95Wpf8jsaZtRUVei+SB7BWLfcPi4w7x6JRhrS67vOxH+P4BbtMqdg5aID/fCxUTMJMiSWx9R39PC6mFzc4ZvxzBvNmIbBBiFWuIHeYZOR/3lcrLTh1r9pCYywRzGPbY0u/8CWDxaQJGrNSGjnEXqL97TTuMuu2t07XJAglPsJR63fxOqgd5RET39uDHQqbLy7bxNiCq9+vMcF6JTr13KYDHmtb4qPT95zoqhRHrCI7EI+ruozpoQG6OV/IOXGJhYyFBjMZLCOIMWWoX510QPmQyRNwHsUT3wIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQA/zFEkpuhffnzxjKRZU05qjA0fEOp7t8C6YI0ERd+bhp0wS5thicSCPhTZgIe3RH23Ozd8lbsmBpnqsOg2PGw/mVjFcutTZrHObCYmmAIQBYlfwfC4UqIx5UjjY+3H/mdsS9XsUAtR9OIuK8NBTSZqHTIK56ifYuifvpVUVbotqM+Yg4r1D6lPBwsvo9OdRxKODrEocfwmMjUJfNX4p1ywXE8sazlBm0CbHASugLEBRU5fQAig+D6RyEijPBXKGrVJxXOwEGO/nukkgmPYruPwNy+h3WmURwkQ5IbnvTBacu9iTYMN/vaRRq1imHNWnjFbZnDCJr+TWIPbVQjY6FY4" ], + "priority" : [ "100" ] + } + }, { + "id" : "1351fa5d-2a4a-4780-8fae-d3927b012acb", + "name" : "aes-generated", + "providerId" : "aes-generated", + "subComponents" : { }, + "config" : { + "kid" : [ "b3f2725f-76e5-4f0d-9b86-328a2995ef85" ], + "secret" : [ "CC51rVYsGuwM7wnkjylqcA" ], + "priority" : [ "100" ] + } + } ] + }, + "internationalizationEnabled" : false, + "supportedLocales" : [ ], + "authenticationFlows" : [ { + "id" : "2015fa69-e7e2-47f2-85a9-72083f2d5799", + "alias" : "Account verification options", + "description" : "Method with which to verity the existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-email-verification", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Verify Existing Account by Re-authentication", + "userSetupAllowed" : false + } ] + }, { + "id" : "c33ebc38-f2c7-4f51-a53e-1ba9370f670a", + "alias" : "Browser - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "edb6e773-66f4-4c5d-96e8-72161fd4aca9", + "alias" : "Direct Grant - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "direct-grant-validate-otp", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "22dda1be-7bc3-4bd9-9792-d54b114e7273", + "alias" : "First broker login - Conditional OTP", + "description" : "Flow to determine if the OTP is required for the authentication", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-otp-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "cbf77531-658d-4b21-bce9-341e21357133", + "alias" : "Handle Existing Account", + "description" : "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-confirm-link", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Account verification options", + "userSetupAllowed" : false + } ] + }, { + "id" : "5df209de-e792-43dd-8fd8-ca9462d5c3d7", + "alias" : "Reset - Conditional OTP", + "description" : "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "conditional-user-configured", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-otp", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "26fccf30-44b5-43a6-8bea-621d74ad48c4", + "alias" : "User creation or linking", + "description" : "Flow for the existing/non-existing user alternatives", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "create unique user config", + "authenticator" : "idp-create-user-if-unique", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Handle Existing Account", + "userSetupAllowed" : false + } ] + }, { + "id" : "a77263c0-036d-4b0f-a749-adf9bc01e32a", + "alias" : "Verify Existing Account by Re-authentication", + "description" : "Reauthentication of existing account", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "idp-username-password-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "First broker login - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "e62b015b-62cf-44e9-aaef-b782278d1f94", + "alias" : "browser", + "description" : "browser based authentication", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-cookie", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "auth-spnego", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "identity-provider-redirector", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 25, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "ALTERNATIVE", + "priority" : 30, + "autheticatorFlow" : true, + "flowAlias" : "forms", + "userSetupAllowed" : false + } ] + }, { + "id" : "d9f9ab6a-a6ae-4f8f-a411-8dd0a9a11a46", + "alias" : "clients", + "description" : "Base authentication for clients", + "providerId" : "client-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "client-secret", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-jwt", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-secret-jwt", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 30, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "client-x509", + "authenticatorFlow" : false, + "requirement" : "ALTERNATIVE", + "priority" : 40, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "b63e66d7-e30d-4458-b56c-e3d10c48ad9a", + "alias" : "direct grant", + "description" : "OpenID Connect Resource Owner Grant", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "direct-grant-validate-username", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "direct-grant-validate-password", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 30, + "autheticatorFlow" : true, + "flowAlias" : "Direct Grant - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "20dd3a17-943d-40a4-a320-b78a018c7740", + "alias" : "docker auth", + "description" : "Used by Docker clients to authenticate against the IDP", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "docker-http-basic-authenticator", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "8dc9f372-c43c-48c3-80a4-f7fccb183a10", + "alias" : "first broker login", + "description" : "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticatorConfig" : "review profile config", + "authenticator" : "idp-review-profile", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "User creation or linking", + "userSetupAllowed" : false + } ] + }, { + "id" : "2a615cce-f472-44dc-a379-c7b28ac78e2b", + "alias" : "forms", + "description" : "Username, password, otp and other auth forms.", + "providerId" : "basic-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "auth-username-password-form", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 20, + "autheticatorFlow" : true, + "flowAlias" : "Browser - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "e929e547-123a-4d1d-9d53-da597fda78ce", + "alias" : "registration", + "description" : "registration flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-page-form", + "authenticatorFlow" : true, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : true, + "flowAlias" : "registration form", + "userSetupAllowed" : false + } ] + }, { + "id" : "f2166939-6982-468f-9be9-0217f35c2386", + "alias" : "registration form", + "description" : "registration form", + "providerId" : "form-flow", + "topLevel" : false, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "registration-user-creation", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-profile-action", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 40, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-password-action", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 50, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "registration-recaptcha-action", + "authenticatorFlow" : false, + "requirement" : "DISABLED", + "priority" : 60, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + }, { + "id" : "6db0cf80-5f81-4bcf-8e0b-3c4a682995eb", + "alias" : "reset credentials", + "description" : "Reset credentials for a user if they forgot their password or something", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "reset-credentials-choose-user", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-credential-email", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 20, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticator" : "reset-password", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 30, + "autheticatorFlow" : false, + "userSetupAllowed" : false + }, { + "authenticatorFlow" : true, + "requirement" : "CONDITIONAL", + "priority" : 40, + "autheticatorFlow" : true, + "flowAlias" : "Reset - Conditional OTP", + "userSetupAllowed" : false + } ] + }, { + "id" : "8afa88d2-dbd0-4e51-bf01-3032c1221d34", + "alias" : "saml ecp", + "description" : "SAML ECP Profile Authentication Flow", + "providerId" : "basic-flow", + "topLevel" : true, + "builtIn" : true, + "authenticationExecutions" : [ { + "authenticator" : "http-basic-authenticator", + "authenticatorFlow" : false, + "requirement" : "REQUIRED", + "priority" : 10, + "autheticatorFlow" : false, + "userSetupAllowed" : false + } ] + } ], + "authenticatorConfig" : [ { + "id" : "629cf0f7-f153-4f85-9bfe-2f5c78491119", + "alias" : "create unique user config", + "config" : { + "require.password.update.after.registration" : "false" + } + }, { + "id" : "2ee0fe91-8964-4c02-982a-f3640f0fa9de", + "alias" : "review profile config", + "config" : { + "update.profile.on.first.login" : "missing" + } + } ], + "requiredActions" : [ { + "alias" : "CONFIGURE_TOTP", + "name" : "Configure OTP", + "providerId" : "CONFIGURE_TOTP", + "enabled" : true, + "defaultAction" : false, + "priority" : 10, + "config" : { } + }, { + "alias" : "TERMS_AND_CONDITIONS", + "name" : "Terms and Conditions", + "providerId" : "TERMS_AND_CONDITIONS", + "enabled" : false, + "defaultAction" : false, + "priority" : 20, + "config" : { } + }, { + "alias" : "UPDATE_PASSWORD", + "name" : "Update Password", + "providerId" : "UPDATE_PASSWORD", + "enabled" : true, + "defaultAction" : false, + "priority" : 30, + "config" : { } + }, { + "alias" : "UPDATE_PROFILE", + "name" : "Update Profile", + "providerId" : "UPDATE_PROFILE", + "enabled" : true, + "defaultAction" : false, + "priority" : 40, + "config" : { } + }, { + "alias" : "VERIFY_EMAIL", + "name" : "Verify Email", + "providerId" : "VERIFY_EMAIL", + "enabled" : true, + "defaultAction" : false, + "priority" : 50, + "config" : { } + }, { + "alias" : "delete_account", + "name" : "Delete Account", + "providerId" : "delete_account", + "enabled" : false, + "defaultAction" : false, + "priority" : 60, + "config" : { } + }, { + "alias" : "webauthn-register", + "name" : "Webauthn Register", + "providerId" : "webauthn-register", + "enabled" : true, + "defaultAction" : false, + "priority" : 70, + "config" : { } + }, { + "alias" : "webauthn-register-passwordless", + "name" : "Webauthn Register Passwordless", + "providerId" : "webauthn-register-passwordless", + "enabled" : true, + "defaultAction" : false, + "priority" : 80, + "config" : { } + }, { + "alias" : "update_user_locale", + "name" : "Update User Locale", + "providerId" : "update_user_locale", + "enabled" : true, + "defaultAction" : false, + "priority" : 1000, + "config" : { } + } ], + "browserFlow" : "browser", + "registrationFlow" : "registration", + "directGrantFlow" : "direct grant", + "resetCredentialsFlow" : "reset credentials", + "clientAuthenticationFlow" : "clients", + "dockerAuthenticationFlow" : "docker auth", + "attributes" : { + "cibaBackchannelTokenDeliveryMode" : "poll", + "cibaExpiresIn" : "120", + "cibaAuthRequestedUserHint" : "login_hint", + "oauth2DeviceCodeLifespan" : "600", + "clientOfflineSessionMaxLifespan" : "0", + "oauth2DevicePollingInterval" : "5", + "clientSessionIdleTimeout" : "0", + "parRequestUriLifespan" : "60", + "clientSessionMaxLifespan" : "0", + "clientOfflineSessionIdleTimeout" : "0", + "cibaInterval" : "5", + "realmReusableOtpCode" : "false" + }, + "keycloakVersion" : "22.0.1", + "userManagedAccessAllowed" : false, + "clientProfiles" : { + "profiles" : [ ] + }, + "clientPolicies" : { + "policies" : [ ] + } +} diff --git a/deployments/docker/veraison b/deployments/docker/veraison index cb8c213e..5f686b2d 100755 --- a/deployments/docker/veraison +++ b/deployments/docker/veraison @@ -9,20 +9,24 @@ function status() { local prov=$(_get_container_state provisioning-service) local verif=$(_get_container_state verification-service) local manage=$(_get_container_state management-service) + local keycloak=$(_get_container_state keycloak-service) if [[ $_quiet == true ]]; then local vts=$(_strip_color $vts) local prov=$(_strip_color $prov) local verif=$(_strip_color $verif) local manage=$(_strip_color $manage) + local keycloak=$(_strip_color $keycloak) local status="${_yell}stopped${_reset}" - if [[ "$vts" == "running" || "$prov" == "running" || "$verif" == "running" || "$manage" == "running" ]]; then + if [[ "$vts" == "running" || "$prov" == "running" || "$verif" == "running" || \ + "$manage" == "running" || "$keycloak" == "running" ]]; then status="${_yell}partial${_yell}" fi - if [[ "$vts" == "running" && "$prov" == "running" && "$verif" == "running" && "$manage" == "running" ]]; then + if [[ "$vts" == "running" && "$prov" == "running" && "$verif" == "running" && \ + "$manage" == "running" && "$keycloak" == "running" ]]; then status="${_green}running${_reset}" fi @@ -32,6 +36,7 @@ function status() { echo -e "provisioning: $prov" echo -e "verification: $verif" echo -e " management: $manage" + echo -e " keycloak: $keycloak" fi } @@ -39,6 +44,7 @@ function start() { local what=$1 if [[ "x$what" == "x" ]]; then + start_keycloak start_vts sleep 0.5 # wait for vts to start before starting the services that depend on it. start_provisioning @@ -52,6 +58,8 @@ function start() { start_verification elif [[ "$what" == "management" || "$what" == "management-service" ]]; then start_management + elif [[ "$what" == "keycloak" || "$what" == "keycloak-service" ]]; then + start_keycloak else echo -e "$_error: unknown service: $what" exit 1 @@ -66,6 +74,7 @@ function stop() { stop_verification stop_provisioning stop_vts + stop_keycloak elif [[ "$what" == "vts" || "$what" == "vts-service" ]]; then stop_vts elif [[ "$what" == "provisioning" || "$what" == "provisioning-service" ]]; then @@ -74,6 +83,8 @@ function stop() { stop_verification elif [[ "$what" == "management" || "$what" == "management-service" ]]; then stop_management + elif [[ "$what" == "keycloak" || "$what" == "keycloak-service" ]]; then + stop_keycloak else echo -e "$_error: unknown service: $what" exit 1 @@ -91,6 +102,8 @@ function follow() { follow_verification elif [[ "$what" == "management" || "$what" == "management-service" ]]; then follow_management + elif [[ "$what" == "keycloak" || "$what" == "keycloak-service" ]]; then + follow_keycloak else echo -e "$_error: unknown service: $what" exit 1 @@ -145,6 +158,18 @@ function follow_management() { docker container logs --follow --timestamps management-service } +function start_keycloak() { + docker container start keycloak-service +} + +function stop_keycloak() { + docker container stop keycloak-service +} + +function follow_keycloak() { + docker container logs --follow --timestamps keycloak-service +} + function manager() { docker container run --rm -t \ --network veraison-net \ diff --git a/go.mod b/go.mod index d41d353c..eb723323 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/spf13/jwalterweatherman v1.1.0 github.com/spf13/viper v1.13.0 github.com/stretchr/testify v1.8.4 + github.com/tbaehler/gin-keycloak v1.5.0 github.com/veraison/ccatoken v1.1.0 github.com/veraison/cmw v0.1.0 github.com/veraison/corim v1.0.0 @@ -34,19 +35,24 @@ require ( github.com/veraison/parsec v0.1.0 github.com/veraison/psatoken v1.2.0 go.uber.org/zap v1.23.0 - golang.org/x/text v0.9.0 + golang.org/x/text v0.12.0 google.golang.org/grpc v1.53.0 google.golang.org/protobuf v1.30.0 + gopkg.in/square/go-jose.v2 v2.6.0 ) require ( github.com/bytedance/sonic v1.9.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/gabriel-vasile/mimetype v1.4.2 // indirect + github.com/golang/glog v1.0.0 // indirect github.com/klauspost/cpuid/v2 v2.2.4 // indirect + github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/segmentio/asm v1.2.0 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect golang.org/x/arch v0.3.0 // indirect + golang.org/x/oauth2 v0.4.0 // indirect + google.golang.org/appengine v1.6.7 // indirect ) require ( @@ -99,10 +105,10 @@ require ( github.com/yashtewari/glob-intersection v0.1.0 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.8.0 // indirect - golang.org/x/crypto v0.9.0 // indirect + golang.org/x/crypto v0.12.0 // indirect golang.org/x/net v0.10.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.8.0 // indirect + golang.org/x/sys v0.11.0 // indirect google.golang.org/genproto v0.0.0-20230110181048-76db0878b65f // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect diff --git a/go.sum b/go.sum index c30a0e2f..bd70ad09 100644 --- a/go.sum +++ b/go.sum @@ -422,6 +422,7 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= +github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U= github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= @@ -458,12 +459,19 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= +github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= +github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= +github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= +github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= +github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU= github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js= github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= @@ -681,6 +689,7 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= +github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -711,11 +720,14 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= +github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80= @@ -886,6 +898,8 @@ github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuh github.com/opencontainers/selinux v1.10.1/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.8.1/go.mod h1:T2/BmBdy8dvIRq1a/8aqjN41wvWlN4lrapLU/GW4pbc= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= @@ -899,6 +913,7 @@ github.com/petar-dambovaliev/aho-corasick v0.0.0-20211021192214-5ab2d9280aa9/go. github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterh/liner v0.0.0-20170211195444-bf27d3ba8e1d/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -958,7 +973,9 @@ github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0/go.mod h1:bCqn github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= +github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8= +github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= @@ -1057,6 +1074,8 @@ github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNG github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tbaehler/gin-keycloak v1.5.0 h1:ozzuIv5PNNxsNGFb7KCD40smoKs2EwTGAftcstwvWdI= +github.com/tbaehler/gin-keycloak v1.5.0/go.mod h1:2zAN7is0lTIBP6Ic9VSOH1RggdYtoUlorWxsmGqBr4Y= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= @@ -1065,7 +1084,11 @@ github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9 github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU= github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= @@ -1224,10 +1247,13 @@ golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5y golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1327,6 +1353,7 @@ golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= @@ -1348,6 +1375,9 @@ golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A= +golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= +golang.org/x/oauth2 v0.4.0 h1:NF0gk8LVPg1Ml7SSbGyySuoxdsXitj7TvgvuRxIMc/M= +golang.org/x/oauth2 v0.4.0/go.mod h1:RznEsdpjGAINPTOF0UH/t+xJ75L18YO3Ho6Pyn+uRec= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -1476,6 +1506,7 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220315194320-039c03cc5b86/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -1485,6 +1516,8 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -1504,6 +1537,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1622,6 +1657,7 @@ google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7 google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -1766,6 +1802,8 @@ gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= +gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/integration-tests/docker/bashrc b/integration-tests/docker/bashrc index 34e3d3c1..f4d1409b 100644 --- a/integration-tests/docker/bashrc +++ b/integration-tests/docker/bashrc @@ -3,6 +3,7 @@ export PYTHONPATH=$PYTHONPATH:/integration-testing/utils export PROVISIONING_HOST=provisioning-service export VERIFICATION_HOST=verification-service export MANAGEMENT_HOST=management-service +export KEYCLOAK_HOST=keycloak-service export PS1='\e[0;32m\u@debug-container \e[0;34m\w\n\e[0;32m$\e[0m ' alias ll='ls -lh --color=auto' diff --git a/integration-tests/tests/common.yaml b/integration-tests/tests/common.yaml index 75ad5ca5..958a0ceb 100644 --- a/integration-tests/tests/common.yaml +++ b/integration-tests/tests/common.yaml @@ -5,6 +5,7 @@ variables: provisioning-service: '{tavern.env_vars.PROVISIONING_HOST}.{tavern.env_vars.VERAISON_NETWORK}:{tavern.env_vars.PROVISIONING_PORT}' verification-service: '{tavern.env_vars.VERIFICATION_HOST}.{tavern.env_vars.VERAISON_NETWORK}:{tavern.env_vars.VERIFICATION_PORT}' management-service: '{tavern.env_vars.MANAGEMENT_HOST}.{tavern.env_vars.VERAISON_NETWORK}:{tavern.env_vars.MANAGEMENT_PORT}' + keycloak-service: '{tavern.env_vars.KEYCLOAK_HOST}.{tavern.env_vars.VERAISON_NETWORK}:{tavern.env_vars.KEYCLOAK_PORT}' good-nonce: QUp8F0FBs9DpodKK8xUg8NQimf6sQAfe2J1ormzZLxk= bad-nonce: Ppfdfe2JzZLOk= endorsements-content-types: @@ -29,3 +30,13 @@ variables: full: [full, ta, refval] mini: [mini, ta, refval] mini-bad: [mini, badta] + oauth2: + client-id: veraison-client + client-secret: YifmabB4cVSPPtFLAmHfq7wKaEHQn10Z + credentials: + provisioner: + username: veraison-provisioner + password: veraison + manager: + username: veraison-manager + password: veraison diff --git a/integration-tests/tests/test_enacttrust_badkey.tavern.yaml b/integration-tests/tests/test_enacttrust_badkey.tavern.yaml index 030b79d1..23c91aff 100644 --- a/integration-tests/tests/test_enacttrust_badkey.tavern.yaml +++ b/integration-tests/tests/test_enacttrust_badkey.tavern.yaml @@ -28,6 +28,7 @@ stages: url: http://{provisioning-service}/endorsement-provisioning/v1/submit headers: content-type: '{endorsements-content-type}' # set via hook + authorization: '{authorization}' # set via hook file_body: __generated__/endorsements/corim-{scheme}-{endorsements}.cbor response: status_code: 200 diff --git a/integration-tests/tests/test_enacttrust_badnode.tavern.yaml b/integration-tests/tests/test_enacttrust_badnode.tavern.yaml index 5d7f3892..ad09c251 100644 --- a/integration-tests/tests/test_enacttrust_badnode.tavern.yaml +++ b/integration-tests/tests/test_enacttrust_badnode.tavern.yaml @@ -33,6 +33,7 @@ stages: url: http://{provisioning-service}/endorsement-provisioning/v1/submit headers: content-type: '{endorsements-content-type}' # set via hook + authorization: '{authorization}' # set via hook file_body: __generated__/endorsements/corim-{scheme}-{endorsements}.cbor response: status_code: 200 diff --git a/integration-tests/tests/test_end_to_end.tavern.yaml b/integration-tests/tests/test_end_to_end.tavern.yaml index 6cf8241c..b183240b 100644 --- a/integration-tests/tests/test_end_to_end.tavern.yaml +++ b/integration-tests/tests/test_end_to_end.tavern.yaml @@ -40,6 +40,7 @@ stages: url: http://{provisioning-service}/endorsement-provisioning/v1/submit headers: content-type: '{endorsements-content-type}' # set via hook + authorization: '{authorization}' # set via hook file_body: __generated__/endorsements/corim-{scheme}-{endorsements}.cbor response: status_code: 200 diff --git a/integration-tests/tests/test_multinonce.tavern.yaml b/integration-tests/tests/test_multinonce.tavern.yaml index 2c97a023..34c7037d 100644 --- a/integration-tests/tests/test_multinonce.tavern.yaml +++ b/integration-tests/tests/test_multinonce.tavern.yaml @@ -33,6 +33,7 @@ stages: url: http://{provisioning-service}/endorsement-provisioning/v1/submit headers: content-type: '{endorsements-content-type}' # set via hook + authorization: '{authorization}' # set via hook file_body: __generated__/endorsements/corim-{scheme}-{endorsements}.cbor response: status_code: 200 diff --git a/integration-tests/tests/test_policy_management.tavern.yaml b/integration-tests/tests/test_policy_management.tavern.yaml index 16b388aa..3a03fd54 100644 --- a/integration-tests/tests/test_policy_management.tavern.yaml +++ b/integration-tests/tests/test_policy_management.tavern.yaml @@ -10,6 +10,7 @@ stages: url: http://{management-service}/management/v1/policy/PSA_IOT headers: accept: application/vnd.veraison.policy+json + authorization: '{authorization}' # set via hook response: status_code: 404 @@ -20,6 +21,7 @@ stages: headers: content-type: application/vnd.veraison.policy.opa accept: application/vnd.veraison.policy+json + authorization: '{authorization}' # set via hook file_body: data/policies/psa-short.rego response: status_code: 201 @@ -39,6 +41,7 @@ stages: url: http://{management-service}/management/v1/policy/PSA_IOT headers: accept: application/vnd.veraison.policy+json + authorization: '{authorization}' # set via hook response: status_code: 404 @@ -48,6 +51,7 @@ stages: url: http://{management-service}/management/v1/policy/PSA_IOT/{policy-uuid} headers: accept: application/vnd.veraison.policy+json + authorization: '{authorization}' # set via hook response: status_code: 200 verify_response_with: @@ -61,6 +65,8 @@ stages: request: method: POST url: http://{management-service}/management/v1/policy/PSA_IOT/{policy-uuid}/activate + headers: + authorization: '{authorization}' # set via hook response: status_code: 200 @@ -70,6 +76,7 @@ stages: url: http://{management-service}/management/v1/policy/PSA_IOT headers: accept: application/vnd.veraison.policy+json + authorization: '{authorization}' # set via hook response: status_code: 200 verify_response_with: @@ -85,6 +92,7 @@ stages: url: http://{management-service}/management/v1/policy/BAD headers: accept: application/vnd.veraison.policy+json + authorization: '{authorization}' # set via hook response: status_code: 400 json: @@ -98,6 +106,7 @@ stages: headers: content-type: application/vnd.veraison.policy.opa accept: application/vnd.veraison.policy+json + authorization: '{authorization}' # set via hook file_body: data/policies/psa.rego response: status_code: 201 @@ -117,6 +126,7 @@ stages: url: http://{management-service}/management/v1/policy/PSA_IOT headers: accept: application/vnd.veraison.policy+json + authorization: '{authorization}' # set via hook response: status_code: 200 verify_response_with: @@ -132,6 +142,7 @@ stages: url: http://{management-service}/management/v1/policies/PSA_IOT headers: accept: application/vnd.veraison.policies+json + authorization: '{authorization}' # set via hook response: status_code: 200 verify_response_with: @@ -143,6 +154,8 @@ stages: request: method: POST url: http://{management-service}/management/v1/policies/PSA_IOT/deactivate + headers: + authorization: '{authorization}' # set via hook response: status_code: 200 @@ -152,6 +165,7 @@ stages: url: http://{management-service}/management/v1/policies/PSA_IOT headers: accept: application/vnd.veraison.policies+json + authorization: '{authorization}' # set via hook response: status_code: 200 verify_response_with: diff --git a/integration-tests/tests/test_provisioning_empty_body.tavern.yaml b/integration-tests/tests/test_provisioning_empty_body.tavern.yaml index a1d1d9d2..b4bd1a68 100644 --- a/integration-tests/tests/test_provisioning_empty_body.tavern.yaml +++ b/integration-tests/tests/test_provisioning_empty_body.tavern.yaml @@ -10,6 +10,7 @@ stages: url: http://{provisioning-service}/endorsement-provisioning/v1/submit headers: content-type: "application/corim-unsigned+cbor; profile=http://arm.com/psa/iot/1" + authorization: '{authorization}' # set via hook response: status_code: 400 json: diff --git a/integration-tests/tests/test_provisioning_unauthorized.tavern.yaml b/integration-tests/tests/test_provisioning_unauthorized.tavern.yaml new file mode 100644 index 00000000..578bd03f --- /dev/null +++ b/integration-tests/tests/test_provisioning_unauthorized.tavern.yaml @@ -0,0 +1,23 @@ +test_name: unauthorized + +includes: + - !include common.yaml + +stages: + - name: submit post request to the provisioning service with no authorization + request: + method: POST + url: http://{provisioning-service}/endorsement-provisioning/v1/submit + headers: + content-type: "application/corim-unsigned+cbor; profile=http://arm.com/psa/iot/1" + response: + status_code: 401 + + - name: get active policy with no authorization + request: + method: GET + url: http://{management-service}/management/v1/policy/PSA_IOT + headers: + accept: application/vnd.veraison.policy+json + response: + status_code: 401 diff --git a/integration-tests/tests/test_verification_bad_session_attester.tavern.yaml b/integration-tests/tests/test_verification_bad_session_attester.tavern.yaml index e03a5aea..ffeb5e03 100644 --- a/integration-tests/tests/test_verification_bad_session_attester.tavern.yaml +++ b/integration-tests/tests/test_verification_bad_session_attester.tavern.yaml @@ -26,6 +26,7 @@ stages: url: http://{provisioning-service}/endorsement-provisioning/v1/submit headers: content-type: "application/corim-unsigned+cbor; profile=http://arm.com/psa/iot/1" + authorization: '{authorization}' # set via hook file_body: __generated__/endorsements/corim-{scheme}-{endorsements}.cbor response: status_code: 200 diff --git a/integration-tests/utils/conftest.py b/integration-tests/utils/conftest.py index 94959604..38f39ff0 100644 --- a/integration-tests/utils/conftest.py +++ b/integration-tests/utils/conftest.py @@ -24,6 +24,7 @@ def pytest_tavern_beta_before_every_test_run(test_dict, variables): test = TavernTest(test_dict) setup(test, variables) + def setup(test, variables): clear_stores() test_id = to_identifier(test.name) diff --git a/integration-tests/utils/hooks.py b/integration-tests/utils/hooks.py index a74a48b0..0bee37e2 100644 --- a/integration-tests/utils/hooks.py +++ b/integration-tests/utils/hooks.py @@ -3,39 +3,53 @@ import os from generators import * -from util import run_command +from util import run_command, get_access_token def setup_end_to_end(test, variables): _set_content_types(test, variables) + _set_authorization(test, variables, 'provisioner') generate_endorsements(test) generate_evidence_from_test(test) -def setup_bad_session(test, veriables): +def setup_bad_session(test, variables): + _set_authorization(test, variables, 'provisioner') generate_endorsements(test) -def setup_no_nonce(test, veriables): +def setup_no_nonce(test, variables): + _set_authorization(test, variables, 'provisioner') generate_evidence_from_test(test) def setup_multi_nonce(test, variables): _set_content_types(test, variables) + _set_authorization(test, variables, 'provisioner') generate_endorsements(test) generate_evidence_from_test_no_nonce(test) def setup_enacttrust_badnode(test, variables): + _set_authorization(test, variables, 'provisioner') _set_content_types(test, variables) generate_endorsements(test) generate_evidence_from_test(test) def setup_enacttrust_badkey(test, variables): + _set_authorization(test, variables, 'provisioner') _set_content_types(test, variables) generate_endorsements(test) +def setup_policy_management(test, variables): + _set_authorization(test, variables, 'manager') + + +def setup_provisioning_fail_empty_body(test, variables): + _set_authorization(test, variables, 'provisioner') + + def _set_content_types(test, variables): scheme = test.test_vars['scheme'] profile = test.test_vars['profile'] @@ -45,4 +59,8 @@ def _set_content_types(test, variables): variables['evidence-content-type'] = ev_content_types[f'{scheme}.{profile}'] +def _set_authorization(test, variables, role): + token = get_access_token(test, role) + variables['authorization'] = f'Bearer {token}' + diff --git a/integration-tests/utils/util.py b/integration-tests/utils/util.py index 7a8f46a4..87cdd372 100644 --- a/integration-tests/utils/util.py +++ b/integration-tests/utils/util.py @@ -1,8 +1,12 @@ # Copyright 2023 Contributors to the Veraison project. # SPDX-License-Identifier: Apache-2.0 import json +import os import re import subprocess +import time + +import requests def to_identifier(text): @@ -50,3 +54,36 @@ def clear_stores(): run_command(command, f'clear {prefix} store') +def get_access_token(test, role): + kc_host = os.getenv('KEYCLOAK_HOST') + kc_port = os.getenv('KEYCLOAK_PORT') + veraison_net = os.getenv('VERAISON_NETWORK') + + # Wait for Keycloak service to come online. This takes a short while, and + # if the integration tests are run immediately after spinning up the + # deployment, it may not be there yet. + for _ in range(10): + try: + requests.get(f'http://{kc_host}.{veraison_net}:{kc_port}/') + break + except requests.ConnectionError: + time.sleep(1) + else: + raise RuntimeError('Keycloak service does not appear to be online') + + credentials = test.common_vars['credentials'][role] + data = { + 'client_id': test.common_vars['oauth2']['client-id'], + 'client_secret': test.common_vars['oauth2']['client-secret'], + 'grant_type': 'password', + 'scope': 'openid', + 'username': credentials['username'], + 'password': credentials['password'], + + } + url = f'http://{kc_host}.{veraison_net}:{kc_port}/realms/veraison/protocol/openid-connect/token' + + r = requests.post(url, data=data) + resp = r.json() + + return resp['access_token'] diff --git a/management/api/router.go b/management/api/router.go index 9338e34c..0821b443 100644 --- a/management/api/router.go +++ b/management/api/router.go @@ -3,7 +3,10 @@ package api -import "github.com/gin-gonic/gin" +import ( + "github.com/gin-gonic/gin" + "github.com/veraison/services/auth" +) var publicApiMap = map[string]string{ "createPolicy": "/management/v1/policy/:scheme", @@ -14,11 +17,12 @@ var publicApiMap = map[string]string{ "getPolicies": "/management/v1/policies/:scheme", } -func NewRouter(handler Handler) *gin.Engine { +func NewRouter(handler Handler, authorizer auth.IAuthorizer) *gin.Engine { router := gin.New() router.Use(gin.Logger()) router.Use(gin.Recovery()) + router.Use(authorizer.GetGinHandler(auth.ManagerRole)) router.POST(publicApiMap["createPolicy"], handler.CreatePolicy) router.POST(publicApiMap["activatePolicy"], handler.Activate) diff --git a/management/cmd/management-service/README.md b/management/cmd/management-service/README.md new file mode 100644 index 00000000..ebdba8c1 --- /dev/null +++ b/management/cmd/management-service/README.md @@ -0,0 +1,39 @@ +## Configuration + +`management-service` is expecting to find the following top-level entries in +configuration: + +- `management`: management service configuration. See [below](#management-service-configuration). +- `po-store`: policy store configuration. See [kvstore config](/kvstore/README.md#Configuration). +- `po-agent` (optional): policy agent configuration. See [policy config](/policy/README.md#Configuration). +- `plugin`: plugin manager configuration. See [plugin config](/vts/pluginmanager/README.md#Configuration). +- `logging` (optional): Logging configuration. See [logging config](/vts/log/README.md#Configuration). +- `auth` (optional): API authentication and authorization mechanism + configuration. If this is not specified, the `passthrough` backend will be + used (i.e. no authentication will be performed). With other backends, + authorization is based on `manager` role. See [auth + config](/auth/README.md#Configuration). + +### Management service configuration + +- `listen-addr` (optional): the address, in the form `:` the + management server will be listening on. If not specified, this defaults to + `localhost:8088`. + +### Example + +```yaml +management: + listen-addr: 0.0.0.0:8088 +po-store: + backend: sql + sql: + driver: sqlite3 + datasource: po-store.sql +po-agent: + backend: opa +plugin: + backend: go-plugin + go-plugin: + folder: ../../plugins/bin/ +``` diff --git a/management/cmd/management-service/config.yaml b/management/cmd/management-service/config.yaml index f81f29a0..a80611b3 100644 --- a/management/cmd/management-service/config.yaml +++ b/management/cmd/management-service/config.yaml @@ -13,3 +13,8 @@ po-agent: backend: opa logging: level: debug +auth: + backend: keycloak + host: keycloak-service + port: 11111 + realm: veraison diff --git a/management/cmd/management-service/main.go b/management/cmd/management-service/main.go index ba498104..78bb809f 100644 --- a/management/cmd/management-service/main.go +++ b/management/cmd/management-service/main.go @@ -4,6 +4,7 @@ package main import ( _ "github.com/mattn/go-sqlite3" + "github.com/veraison/services/auth" "github.com/veraison/services/config" "github.com/veraison/services/log" "github.com/veraison/services/management" @@ -26,7 +27,7 @@ func main() { log.Fatalf("Could not read config: %v", err) } - subs, err := config.GetSubs(v, "*management", "*logging") + subs, err := config.GetSubs(v, "*management", "*logging", "*auth") if err != nil { log.Fatalf("Could not parse config: %v", err) } @@ -53,8 +54,19 @@ func main() { } log.Infow("initializing management API service", "address", cfg.ListenAddr) + authorizer, err := auth.NewAuthorizer(subs["auth"], log.Named("auth")) + if err != nil { + log.Fatalf("could not init authorizer: %v", err) + } + defer func() { + err := authorizer.Close() + if err != nil { + log.Errorf("Could not close authorizer: %v", err) + } + }() + handler := api.NewHandler(pm, log.Named("api")) - if err := api.NewRouter(handler).Run(cfg.ListenAddr); err != nil { - log.Fatalf("Gin engine failed: %v", err) + if err := api.NewRouter(handler, authorizer).Run(cfg.ListenAddr); err != nil { + log.Errorf("Gin engine failed: %v", err) } } diff --git a/provisioning/api/handler_test.go b/provisioning/api/handler_test.go index 4b18c58b..bee17eb6 100644 --- a/provisioning/api/handler_test.go +++ b/provisioning/api/handler_test.go @@ -16,6 +16,7 @@ import ( "github.com/golang/mock/gomock" "github.com/moogar0880/problems" "github.com/stretchr/testify/assert" + "github.com/veraison/services/auth" "github.com/veraison/services/capability" "github.com/veraison/services/log" "github.com/veraison/services/proto" @@ -265,7 +266,8 @@ func TestHandler_GetWellKnownProvisioningInfo_ok(t *testing.T) { g.Request, _ = http.NewRequest(http.MethodGet, "/.well-known/veraison/provisioning", http.NoBody) g.Request.Header.Add("Accept", expectedType) - NewRouter(h).ServeHTTP(w, g.Request) + u := auth.NewPassthroughAuthorizer(log.Named("auth")) + NewRouter(h, u).ServeHTTP(w, g.Request) var body capability.WellKnownInfo _ = json.Unmarshal(w.Body.Bytes(), &body) @@ -305,7 +307,8 @@ func TestHandler_GetWellKnownProvisioningInfo_GetRegisteredMediaTypes_empty(t *t g.Request, _ = http.NewRequest(http.MethodGet, "/.well-known/veraison/provisioning", http.NoBody) g.Request.Header.Add("Accept", expectedType) - NewRouter(h).ServeHTTP(w, g.Request) + u := auth.NewPassthroughAuthorizer(log.Named("auth")) + NewRouter(h, u).ServeHTTP(w, g.Request) var body capability.WellKnownInfo _ = json.Unmarshal(w.Body.Bytes(), &body) @@ -340,7 +343,8 @@ func TestHandler_GetWellKnownProvisioningInfo_GetServiceState_fail(t *testing.T) g.Request, _ = http.NewRequest(http.MethodGet, "/.well-known/veraison/provisioning", http.NoBody) - NewRouter(h).ServeHTTP(w, g.Request) + u := auth.NewPassthroughAuthorizer(log.Named("auth")) + NewRouter(h, u).ServeHTTP(w, g.Request) var body problems.DefaultProblem _ = json.Unmarshal(w.Body.Bytes(), &body) @@ -368,7 +372,8 @@ func TestHandler_GetWellKnownProvisioningInfo_UnsupportedAccept(t *testing.T) { g.Request, _ = http.NewRequest(http.MethodGet, "/.well-known/veraison/provisioning", http.NoBody) g.Request.Header.Add("Accept", "application/unsupported+ber") - NewRouter(h).ServeHTTP(w, g.Request) + u := auth.NewPassthroughAuthorizer(log.Named("auth")) + NewRouter(h, u).ServeHTTP(w, g.Request) var body problems.DefaultProblem _ = json.Unmarshal(w.Body.Bytes(), &body) diff --git a/provisioning/api/router.go b/provisioning/api/router.go index d712581b..7789289d 100644 --- a/provisioning/api/router.go +++ b/provisioning/api/router.go @@ -4,6 +4,7 @@ package api import ( "github.com/gin-gonic/gin" + "github.com/veraison/services/auth" ) var publicApiMap = make(map[string]string) @@ -13,11 +14,12 @@ const ( getWellKnownProvisioningInfoUrl = "/.well-known/veraison/provisioning" ) -func NewRouter(handler IHandler) *gin.Engine { +func NewRouter(handler IHandler, authorizer auth.IAuthorizer) *gin.Engine { router := gin.New() router.Use(gin.Logger()) router.Use(gin.Recovery()) + router.Use(authorizer.GetGinHandler(auth.ProvisionerRole)) router.POST(provisioningSubmitUrl, handler.Submit) publicApiMap["provisioningSubmit"] = provisioningSubmitUrl diff --git a/provisioning/cmd/provisioning-service/README.md b/provisioning/cmd/provisioning-service/README.md index b67959b1..d78fac1a 100644 --- a/provisioning/cmd/provisioning-service/README.md +++ b/provisioning/cmd/provisioning-service/README.md @@ -3,9 +3,14 @@ `provisioning-services` is expecting to find the following top-level entries in configuration: -- `provisoning`: provisioning service configuration. See [below](#provisioning-service-configuration). +- `provisioning`: provisioning service configuration. See [below](#provisioning-service-configuration). - `vts` (optional): Veraison Trusted Services backend configuration. See [trustedservices config](/vts/trustedservices/README.md#Configuration). - `logging` (optional): Logging configuration. See [logging config](/vts/log/README.md#Configuration). +- `auth` (optional): API authentication and authorization mechanism + configuration. If this is not specified, the `passthrough` backend will be + used (i.e. no authentication will be performed). With other backends, + authorization is based on `provisioner` role. See [auth + config](/auth/README.md#Configuration). ### Provisioning service configuration diff --git a/provisioning/cmd/provisioning-service/main.go b/provisioning/cmd/provisioning-service/main.go index 317d098d..3331f50f 100644 --- a/provisioning/cmd/provisioning-service/main.go +++ b/provisioning/cmd/provisioning-service/main.go @@ -9,6 +9,7 @@ import ( "os/signal" "syscall" + "github.com/veraison/services/auth" "github.com/veraison/services/config" "github.com/veraison/services/log" "github.com/veraison/services/provisioning/api" @@ -37,7 +38,7 @@ func main() { ListenAddr: DefaultListenAddr, } - subs, err := config.GetSubs(v, "provisioning", "vts", "*logging") + subs, err := config.GetSubs(v, "provisioning", "vts", "*logging", "*auth") if err != nil { log.Fatal(err) } @@ -73,8 +74,19 @@ func main() { provisioner := provisioner.New(vtsClient) log.Infow("initializing provisioning API service", "address", cfg.ListenAddr) + authorizer, err := auth.NewAuthorizer(subs["auth"], log.Named("auth")) + if err != nil { + log.Fatalf("could not init authorizer: %v", err) + } + defer func() { + err := authorizer.Close() + if err != nil { + log.Errorf("Could not close authorizer: %v", err) + } + }() + apiHandler := api.NewHandler(provisioner, log.Named("api")) - go apiServer(apiHandler, cfg.ListenAddr) + go apiServer(apiHandler, authorizer, cfg.ListenAddr) sigs := make(chan os.Signal, 1) signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM) @@ -95,8 +107,8 @@ func terminator( done <- true } -func apiServer(apiHandler api.IHandler, listenAddr string) { - if err := api.NewRouter(apiHandler).Run(listenAddr); err != nil { +func apiServer(apiHandler api.IHandler, authorizer auth.IAuthorizer, listenAddr string) { + if err := api.NewRouter(apiHandler, authorizer).Run(listenAddr); err != nil { log.Fatalf("Gin engine failed: %v", err) } }