diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9aaf6c4d40..7ddcd7ec7f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -101,6 +101,8 @@ jobs: - run: go get github.com/rakyll/statik - run: ./build/console/generate-static.sh - run: cat pkg/console/statik/statik.go + - run: ./build/login/generate-static.sh + - run: cat internal/login/statik/statik.go - run: CGO_ENABLED=0 GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }} go build -a -installsuffix cgo -ldflags '-extldflags "-static"' -o zitadel-${{ matrix.goos }}-${{ matrix.goarch }} cmd/zitadel/main.go - uses: actions/upload-artifact@v1 with: diff --git a/.gitignore b/.gitignore index 298e6e97ae..4228421518 100644 --- a/.gitignore +++ b/.gitignore @@ -32,4 +32,4 @@ cockroach-data/* #binaries cmd/zitadel/zitadel -zitadel +**/statik/statik.go diff --git a/build/console/generate-static.sh b/build/console/generate-static.sh index 756e9e964a..18632ab241 100755 --- a/build/console/generate-static.sh +++ b/build/console/generate-static.sh @@ -2,4 +2,4 @@ set -eux -go generate pkg/console/console.go \ No newline at end of file +go generate pkg/console/statik/generate.go \ No newline at end of file diff --git a/build/login/generate-static.sh b/build/login/generate-static.sh new file mode 100755 index 0000000000..9e59d27287 --- /dev/null +++ b/build/login/generate-static.sh @@ -0,0 +1,5 @@ +#! /bin/sh + +set -eux + +go generate internal/login/statik/generate.go \ No newline at end of file diff --git a/cmd/zitadel/authz.yaml b/cmd/zitadel/authz.yaml index ac5b8ebd72..979fdbe0ec 100644 --- a/cmd/zitadel/authz.yaml +++ b/cmd/zitadel/authz.yaml @@ -1,4 +1,4 @@ -AuthZ: +InternalAuthZ: RolePermissionMappings: - Role: 'IAM_OWNER' Permissions: diff --git a/cmd/zitadel/caos_local.sh b/cmd/zitadel/caos_local.sh old mode 100644 new mode 100755 index f5444ecd79..7b4451192b --- a/cmd/zitadel/caos_local.sh +++ b/cmd/zitadel/caos_local.sh @@ -1,7 +1,9 @@ BASEDIR=$(dirname "$0") +gopass sync --store zitadel-secrets + # Tracing -gopass citadel-secrets/citadel/developer/default/citadel-svc-account-eventstore-local | base64 -D > "$BASEDIR/local_svc-account-tracing.json" +gopass zitadel-secrets/zitadel/developer/default/zitadel-svc-account-eventstore-local | base64 -D > "$BASEDIR/local_svc-account-tracing.json" export GOOGLE_APPLICATION_CREDENTIALS="$BASEDIR/local_svc-account-tracing.json" export ZITADEL_TRACING_PROJECT_ID=caos-citadel-test @@ -15,24 +17,32 @@ export ZITADEL_EVENTSTORE_HOST=localhost export ZITADEL_EVENTSTORE_PORT=26257 # Keys -gopass citadel-secrets/citadel/developer/default/keys.yaml > "$BASEDIR/local_keys.yaml" +gopass zitadel-secrets/zitadel/developer/default/keys.yaml > "$BASEDIR/local_keys.yaml" export ZITADEL_KEY_PATH="$BASEDIR/local_keys.yaml" export ZITADEL_USER_VERIFICATION_KEY=UserVerificationKey_1 export ZITADEL_OTP_VERIFICATION_KEY=OTPVerificationKey_1 +export ZITADEL_OIDC_KEYS_ID=OIDCKey_1 +export ZITADEL_COOKIE_KEY=CookieKey_1 # Notifications export DEBUG_MODE=TRUE -export TWILIO_SERVICE_SID=$(gopass citadel-secrets/citadel/developer/default/twilio-sid) -export TWILIO_TOKEN=$(gopass citadel-secrets/citadel/developer/default/twilio-auth-token) +export TWILIO_SERVICE_SID=$(gopass zitadel-secrets/zitadel/dev/twilio-sid) +export TWILIO_TOKEN=$(gopass zitadel-secrets/zitadel/dev/twilio-auth-token) export TWILIO_SENDER_NAME=CAOS AG export SMTP_HOST=smtp.gmail.com:465 export SMTP_USER=zitadel@caos.ch -export SMTP_PASSWORD=$(gopass citadel-secrets/citadel/google/emailappkey) +export SMTP_PASSWORD=$(gopass zitadel-secrets/zitadel/google/emailappkey) export EMAIL_SENDER_ADDRESS=noreply@caos.ch export EMAIL_SENDER_NAME=CAOS AG export SMTP_TLS=TRUE -export CHAT_URL=$(gopass citadel-secrets/citadel/developer/default/google-chat-url | base64 -D) +export CHAT_URL=$(gopass zitadel-secrets/zitadel/dev/google-chat-url | base64 -D) -# Zitadel -export ZITADEL_ACCOUNTS=http://localhost:61121 +#OIDC +export ZITADEL_ISSUER=http://localhost:50022 +export ZITADEL_ACCOUNTS=http://localhost:50031 +export ZITADEL_AUTHORIZE=http://localhost:50022 +export ZITADEL_OAUTH=http://localhost:50022 +export ZITADEL_CONSOLE=http://localhost:4200 +export CAOS_OIDC_DEV=true +export ZITADEL_COOKIE_DOMAIN=localhost \ No newline at end of file diff --git a/cmd/zitadel/main.go b/cmd/zitadel/main.go index 76ac81cc06..ec8f83ee3a 100644 --- a/cmd/zitadel/main.go +++ b/cmd/zitadel/main.go @@ -3,18 +3,20 @@ package main import ( "context" "flag" + "github.com/caos/zitadel/internal/auth/repository/eventsourcing" + "github.com/caos/zitadel/internal/authz" sd "github.com/caos/zitadel/internal/config/systemdefaults" + "github.com/caos/zitadel/internal/login" "github.com/caos/logging" - authz "github.com/caos/zitadel/internal/api/auth" + internal_authz "github.com/caos/zitadel/internal/api/auth" "github.com/caos/zitadel/internal/config" "github.com/caos/zitadel/internal/notification" tracing "github.com/caos/zitadel/internal/tracing/config" "github.com/caos/zitadel/pkg/admin" "github.com/caos/zitadel/pkg/auth" "github.com/caos/zitadel/pkg/console" - "github.com/caos/zitadel/pkg/login" "github.com/caos/zitadel/pkg/management" ) @@ -22,13 +24,14 @@ type Config struct { Mgmt management.Config Auth auth.Config Login login.Config + AuthZ authz.Config Admin admin.Config Console console.Config Notification notification.Config Log logging.Config Tracing tracing.TracingConfig - AuthZ authz.Config + InternalAuthZ internal_authz.Config SystemDefaults sd.SystemDefaults } @@ -48,18 +51,25 @@ func main() { logging.Log("MAIN-FaF2r").OnError(err).Fatal("cannot read config") ctx := context.Background() + authZRepo, err := authz.Start(ctx, conf.AuthZ, conf.InternalAuthZ, conf.SystemDefaults) + logging.Log("MAIN-s9KOw").OnError(err).Fatal("error starting authz repo") + if *adminEnabled { - admin.Start(ctx, conf.Admin, conf.AuthZ, conf.SystemDefaults) + admin.Start(ctx, conf.Admin, authZRepo, conf.InternalAuthZ, conf.SystemDefaults) } if *managementEnabled { - management.Start(ctx, conf.Mgmt, conf.AuthZ, conf.SystemDefaults) + management.Start(ctx, conf.Mgmt, authZRepo, conf.InternalAuthZ, conf.SystemDefaults) + } + var authRepo *eventsourcing.EsRepository + if *authEnabled || *loginEnabled { + authRepo, err = eventsourcing.Start(conf.Auth.Repository, conf.InternalAuthZ, conf.SystemDefaults, authZRepo) + logging.Log("MAIN-9oRw6").OnError(err).Fatal("error starting auth repo") } if *authEnabled { - auth.Start(ctx, conf.Auth, conf.AuthZ, conf.SystemDefaults) + auth.Start(ctx, conf.Auth, authZRepo, conf.InternalAuthZ, conf.SystemDefaults, authRepo) } if *loginEnabled { - err = login.Start(ctx, conf.Login) - logging.Log("MAIN-53RF2").OnError(err).Fatal("error starting login ui") + login.Start(ctx, conf.Login, conf.SystemDefaults, authRepo) } if *notificationEnabled { notification.Start(ctx, conf.Notification, conf.SystemDefaults) diff --git a/cmd/zitadel/startup.yaml b/cmd/zitadel/startup.yaml index accf263ef1..318628acad 100644 --- a/cmd/zitadel/startup.yaml +++ b/cmd/zitadel/startup.yaml @@ -50,6 +50,37 @@ Auth: GatewayPort: 50021 CustomHeaders: - x-zitadel- + OIDC: + OPConfig: + Issuer: $ZITADEL_ISSUER + DefaultLogoutRedirectURI: $ZITADEL_ACCOUNTS/logout/done + Port: 50022 + StorageConfig: + DefaultLoginURL: $ZITADEL_ACCOUNTS/login?authRequestID= + DefaultAccessTokenLifetime: 12h + DefaultIdTokenLifetime: 12h + SigningKeyAlgorithm: RS256 + UserAgentCookieConfig: + Name: caos.zitadel.useragent + Domain: $ZITADEL_COOKIE_DOMAIN + Key: + EncryptionKeyID: $ZITADEL_COOKIE_KEY + Endpoints: + Auth: + Path: 'authorize' + URL: '$ZITADEL_AUTHORIZE/authorize' + Token: + Path: 'token' + URL: '$ZITADEL_OAUTH/token' + EndSession: + Path: 'endsession' + URL: '$ZITADEL_AUTHORIZE/endsession' + Userinfo: + Path: 'userinfo' + URL: '$ZITADEL_OAUTH/userinfo' + Keys: + Path: 'keys' + URL: '$ZITADEL_OAUTH/keys' Repository: SearchLimit: 100 Eventstore: @@ -66,11 +97,12 @@ Auth: Config: MaxCacheSizeInByte: 10485760 #10mb AuthRequest: - Host: $ZITADEL_EVENTSTORE_HOST - Port: $ZITADEL_EVENTSTORE_PORT - User: 'auth' - Database: 'auth' - SSLmode: disable + Connection: + Host: $ZITADEL_EVENTSTORE_HOST + Port: $ZITADEL_EVENTSTORE_PORT + User: 'auth' + Database: 'auth' + SSLmode: disable View: Host: $ZITADEL_EVENTSTORE_HOST Port: $ZITADEL_EVENTSTORE_PORT @@ -81,9 +113,48 @@ Auth: ConcurrentTasks: 4 BulkLimit: 100 FailureCountUntilSkip: 5 + KeyConfig: + Size: 2048 + PrivateKeyLifetime: 6h + PublicKeyLifetime: 30h + EncryptionConfig: + EncryptionKeyID: $ZITADEL_OIDC_KEYS_ID + SigningKeyRotation: 10s Login: -# will get port range 5003x + Handler: + Port: 50031 + OidcAuthCallbackURL: '$ZITADEL_AUTHORIZE/authorize/' + ZitadelURL: '$ZITADEL_CONSOLE' + LanguageCookieName: 'caos.zitadel.login.lang' + DefaultLanguage: 'de' + + +AuthZ: + Repository: + Eventstore: + ServiceName: 'AuthZ' + Repository: + SQL: + Host: $ZITADEL_EVENTSTORE_HOST + Port: $ZITADEL_EVENTSTORE_PORT + User: 'authz' + Database: 'eventstore' + SSLmode: disable + Cache: + Type: 'fastcache' + Config: + MaxCacheSizeInByte: 10485760 #10mb + View: + Host: $ZITADEL_EVENTSTORE_HOST + Port: $ZITADEL_EVENTSTORE_PORT + User: 'authz' + Database: 'authz' + SSLmode: disable + Spooler: + ConcurrentTasks: 1 + BulkLimit: 100 + FailureCountUntilSkip: 5 Admin: API: @@ -120,7 +191,6 @@ Admin: Console: Port: 50050 - StaticDir: /app/console/dist Notification: diff --git a/cmd/zitadel/system-defaults.yaml b/cmd/zitadel/system-defaults.yaml index 7bc5b2e2c0..21cbd99403 100644 --- a/cmd/zitadel/system-defaults.yaml +++ b/cmd/zitadel/system-defaults.yaml @@ -76,7 +76,7 @@ SystemDefaults: LastName: 'Administrator' UserName: 'zitadel-global-org-admin@caos.ch' Email: 'zitadel-global-org-admin@caos.ch' - Password: 'Password' + Password: 'Password1!' Owners: - 'zitadel-global-org-admin@caos.ch' - Name: 'CAOS AG' @@ -86,7 +86,7 @@ SystemDefaults: LastName: 'Administrator' UserName: 'zitadel-admin@caos.ch' Email: 'zitadel-admin@caos.ch' - Password: 'Password' + Password: 'Password1!' Owners: - 'zitadel-admin@caos.ch' Projects: @@ -97,9 +97,9 @@ SystemDefaults: - Name: 'Admin-API' - Name: 'Zitadel Console' RedirectUris: - - '$CITADEL_CONSOLE/auth/callback' + - '$ZITADEL_CONSOLE/auth/callback' PostLogoutRedirectUris: - - '$CITADEL_CONSOLE/signedout' + - '$ZITADEL_CONSOLE/signedout' ResponseTypes: - 'CODE' GrantTypes: @@ -133,9 +133,9 @@ SystemDefaults: From: $TWILIO_SENDER_NAME TemplateData: InitCode: - Title: 'Zitadel - User Initialisieren' - PreHeader: 'User Initialisieren' - Subject: 'User Initialisieren' + Title: 'Zitadel - User initialisieren' + PreHeader: 'User initialisieren' + Subject: 'User initialisieren' Greeting: 'Hallo {{.FirstName}} {{.LastName}},' Text: 'Dieser Benutzer wurde soeben im Zitadel erstellt. Du kannst den Button unten verwenden, um die Initialisierung abzuschliesen. Falls du dieses Mail nicht angefordert hast, kannst du es einfach ignorieren.' ButtonText: 'Initialisierung abschliessen' @@ -147,16 +147,16 @@ SystemDefaults: Text: 'Wir haben eine Anfrage für das Zurücksetzen deines Passwortes bekommen. Du kannst den untenstehenden Button verwenden, um dein Passwort zurückzusetzen. Falls du dieses Mail nicht angefordert hast, kannst du es ignorieren.' ButtonText: 'Passwort zurücksetzen' VerifyEmail: - Title: 'Zitadel - Email Verifizieren' + Title: 'Zitadel - Email verifizieren' PreHeader: 'Email verifizieren' Subject: 'Email verifizieren' Greeting: 'Hallo {{.FirstName}} {{.LastName}},' Text: 'Eine neue E-Mail Adresse wurde hinzugefügt. Bitte verwende den untenstehenden Button um diese zu verifizieren. Falls du deine E-Mail Adresse nicht selber hinzugefügt hast, kannst du dieses E-Mail ignorieren.' - ButtonText: 'Passwort zurücksetzen' + ButtonText: 'Email verifizieren' VerifyPhone: - Title: 'Zitadel - Telefonnummer Verifizieren' - PreHeader: 'Telefonnummer Verifizieren' - Subject: 'Telefonnummer Verifizieren' + Title: 'Zitadel - Telefonnummer verifizieren' + PreHeader: 'Telefonnummer verifizieren' + Subject: 'Telefonnummer verifizieren' Greeting: 'Hallo {{.FirstName}} {{.LastName}},' Text: 'Eine Telefonnummer wurde hinzugefügt. Bitte verifiziere diese in dem du folgenden Code eingibst: {{.Code}}' ButtonText: 'Telefon verifizieren' \ No newline at end of file diff --git a/go.mod b/go.mod index 1045c6d3b0..2da16f2b3d 100644 --- a/go.mod +++ b/go.mod @@ -11,16 +11,20 @@ require ( github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/sprig v2.22.0+incompatible github.com/VictoriaMetrics/fastcache v1.5.7 + github.com/aaronarduino/goqrsvg v0.0.0-20170617203649-603647895681 + github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca github.com/allegro/bigcache v1.2.1 github.com/aws/aws-sdk-go v1.30.25 // indirect - github.com/caos/logging v0.0.1 + github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc + github.com/caos/logging v0.0.2 + github.com/caos/oidc v0.6.2 github.com/cockroachdb/cockroach-go v0.0.0-20200504194139-73ffeee90b62 github.com/envoyproxy/protoc-gen-validate v0.1.0 github.com/ghodss/yaml v1.0.0 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/mock v1.4.3 github.com/golang/protobuf v1.4.1 - github.com/google/uuid v1.1.1 // indirect + github.com/gorilla/mux v1.7.4 github.com/gorilla/schema v1.1.0 github.com/gorilla/securecookie v1.1.1 github.com/grpc-ecosystem/go-grpc-middleware v1.2.0 @@ -41,7 +45,6 @@ require ( github.com/pquerna/otp v1.2.0 github.com/rakyll/statik v0.1.7 github.com/rs/cors v1.7.0 - github.com/sirupsen/logrus v1.6.0 // indirect github.com/sony/sonyflake v1.0.0 github.com/stretchr/testify v1.5.1 github.com/ttacon/builder v0.0.0-20170518171403-c099f663e1c2 // indirect @@ -49,12 +52,13 @@ require ( go.opencensus.io v0.22.3 golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 golang.org/x/net v0.0.0-20200506145744-7e3656a0809f // indirect - golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25 // indirect + golang.org/x/sys v0.0.0-20200523222454-059865788121 // indirect golang.org/x/text v0.3.2 golang.org/x/tools v0.0.0-20200512001501-aaeff5de670a google.golang.org/api v0.24.0 // indirect google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380 google.golang.org/grpc v1.29.1 google.golang.org/protobuf v1.22.0 + gopkg.in/square/go-jose.v2 v2.5.1 gopkg.in/yaml.v2 v2.2.8 // indirect ) diff --git a/go.sum b/go.sum index 7825e0a542..05a6fe13bd 100644 --- a/go.sum +++ b/go.sum @@ -45,6 +45,10 @@ github.com/Masterminds/sprig v2.22.0+incompatible h1:z4yfnGrZ7netVz+0EDJ0Wi+5VZC github.com/Masterminds/sprig v2.22.0+incompatible/go.mod h1:y6hNFY5UBTIWBxnzTeuNhlNS5hqE0NB0E6fgfo2Br3o= github.com/VictoriaMetrics/fastcache v1.5.7 h1:4y6y0G8PRzszQUYIQHHssv/jgPHAb5qQuuDNdCbyAgw= github.com/VictoriaMetrics/fastcache v1.5.7/go.mod h1:ptDBkNMQI4RtmVo8VS/XwRY6RoTu1dAWCbrk+6WsEM8= +github.com/aaronarduino/goqrsvg v0.0.0-20170617203649-603647895681 h1:eZrVcUgy0P6+B6Vu7SKPh3UZQS5nEuyjhbkFyfz7I2I= +github.com/aaronarduino/goqrsvg v0.0.0-20170617203649-603647895681/go.mod h1:dytw+5qs+pdi61fO/S4OmXR7AuEq/HvNCuG03KxQHT4= +github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca h1:kWzLcty5V2rzOqJM7Tp/MfSX0RMSI1x4IOLApEefYxA= +github.com/ajstarks/svgo v0.0.0-20200320125537-f189e35d30ca/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/allegro/bigcache v1.2.1 h1:hg1sY1raCwic3Vnsvje6TT7/pnZba83LeFck5NrFKSc= github.com/allegro/bigcache v1.2.1/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= @@ -56,10 +60,11 @@ github.com/aws/aws-sdk-go v1.30.25 h1:89NXJkfpjnMEnsxkP8MVX+LDsoiLCSqevraLb5y4Mj github.com/aws/aws-sdk-go v1.30.25/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI= github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= -github.com/caos/logging v0.0.1 h1:YSGtO2/+5OWdwilBCou50akoDHAT/OhkbrolkVlR6U0= -github.com/caos/logging v0.0.1 h1:YSGtO2/+5OWdwilBCou50akoDHAT/OhkbrolkVlR6U0= -github.com/caos/logging v0.0.1/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= -github.com/caos/logging v0.0.1/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= +github.com/caos/logging v0.0.0-20191210002624-b3260f690a6a/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= +github.com/caos/logging v0.0.2 h1:ebg5C/HN0ludYR+WkvnFjwSExF4wvyiWPyWGcKMYsoo= +github.com/caos/logging v0.0.2/go.mod h1:9LKiDE2ChuGv6CHYif/kiugrfEXu9AwDiFWSreX7Wp0= +github.com/caos/oidc v0.6.2 h1:ejp6uTepVSlgLoPhXIAqFe8SbCdoxqO4vZv1H4fF0Yk= +github.com/caos/oidc v0.6.2/go.mod h1:ozoi3b+aY33gzdvjz4w90VZShIHGsmDa0goruuV0arQ= github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -138,6 +143,10 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0= +github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github/v31 v31.0.0/go.mod h1:NQPZol8/1sMoWYGN2yaALIBytu17gAWfhbweiEed3pM= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= @@ -152,6 +161,10 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gorilla/handlers v1.4.2 h1:0QniY0USkHQ1RGCLfKxeNHK9bkDHGRYGNDFBCS+YARg= +github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= +github.com/gorilla/mux v1.7.4 h1:VuZ8uybHlWmqV03+zRzdwKL4tUnIp1MAQtp1mIFE1bc= +github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/schema v1.1.0 h1:CamqUDOFUBqzrvxuz2vEwo8+SUdwsluFh7IlzJh30LY= github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= @@ -273,6 +286,7 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191128160524-b544559bb6d1/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20191205180655-e7c4368fe9dd/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37 h1:cg5LA/zNPRzIXIWSCxQW10Rvpy94aQh3LT/ShoCpkHw= golang.org/x/crypto v0.0.0-20200510223506-06a226fb4e37/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -320,6 +334,7 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191002035440-2ec189313ef0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191126235420-ef20fe5d7933/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -333,6 +348,7 @@ golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191122200657-5d9234df094c/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw= golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -372,8 +388,8 @@ golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200331124033-c3d80250170d h1:nc5K6ox/4lTFbMVSL9WRR81ixkcwXThoiF6yf+R9scA= golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25 h1:OKbAoGs4fGM5cPLlVQLZGYkFC8OnOfgo6tt0Smf9XhM= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200523222454-059865788121 h1:rITEj+UZHYC927n8GT97eC3zrpzXdb/voyeOuVKS46o= +golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -498,6 +514,8 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/square/go-jose.v2 v2.5.1 h1:7odma5RETjNHWJnR32wx8t+Io4djHE1PqxCFx3iiZ2w= +gopkg.in/square/go-jose.v2 v2.5.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/internal/admin/auth/token_verifier.go b/internal/admin/auth/token_verifier.go index 84ba0abe38..a4026591d1 100644 --- a/internal/admin/auth/token_verifier.go +++ b/internal/admin/auth/token_verifier.go @@ -3,23 +3,34 @@ package auth import ( "context" "github.com/caos/zitadel/internal/api/auth" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" +) + +const ( + adminName = "Admin-API" ) type TokenVerifier struct { + adminID string + authZRepo *authz_repo.EsRepository } -func Start() (v *TokenVerifier) { - return new(TokenVerifier) +func Start(authZRepo *authz_repo.EsRepository) (v *TokenVerifier) { + return &TokenVerifier{authZRepo: authZRepo} } func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string) (string, string, string, error) { - return "", "", "", nil + userID, clientID, agentID, err := v.authZRepo.VerifyAccessToken(ctx, token, adminName, v.adminID) + if clientID != "" { + v.adminID = clientID + } + return userID, clientID, agentID, err } -func (v *TokenVerifier) ResolveGrants(ctx context.Context, userID, orgID string) ([]*auth.Grant, error) { - return nil, nil +func (v *TokenVerifier) ResolveGrant(ctx context.Context) (*auth.Grant, error) { + return v.authZRepo.ResolveGrants(ctx) } func (v *TokenVerifier) GetProjectIDByClientID(ctx context.Context, clientID string) (string, error) { - return "", nil + return v.authZRepo.ProjectIDByClientID(ctx, clientID) } diff --git a/internal/admin/repository/eventsourcing/eventstore/setup_model.go b/internal/admin/repository/eventsourcing/eventstore/setup_model.go index 98e27199e5..527b514781 100644 --- a/internal/admin/repository/eventsourcing/eventstore/setup_model.go +++ b/internal/admin/repository/eventsourcing/eventstore/setup_model.go @@ -3,13 +3,12 @@ package eventstore import ( admin_model "github.com/caos/zitadel/internal/admin/model" es_models "github.com/caos/zitadel/internal/eventstore/models" - org_model "github.com/caos/zitadel/internal/org/model" - org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" ) type Setup struct { - *org_es.Org + *model.Org *usr_es.User } @@ -17,7 +16,7 @@ func (s *Setup) AppendEvents(events ...*es_models.Event) error { for _, event := range events { var err error switch event.AggregateType { - case org_model.OrgAggregate: + case model.OrgAggregate: err = s.Org.AppendEvent(event) case usr_es.UserAggregate: err = s.User.AppendEvent(event) @@ -31,7 +30,7 @@ func (s *Setup) AppendEvents(events ...*es_models.Event) error { func SetupToModel(setup *Setup) *admin_model.SetupOrg { return &admin_model.SetupOrg{ - Org: org_es.OrgToModel(setup.Org), + Org: model.OrgToModel(setup.Org), User: usr_es.UserToModel(setup.User), } } diff --git a/internal/admin/repository/eventsourcing/handler/org.go b/internal/admin/repository/eventsourcing/handler/org.go index 5564e4eb94..1e7d90764f 100644 --- a/internal/admin/repository/eventsourcing/handler/org.go +++ b/internal/admin/repository/eventsourcing/handler/org.go @@ -1,12 +1,12 @@ package handler import ( + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "time" "github.com/caos/logging" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/spooler" - org_model "github.com/caos/zitadel/internal/org/model" "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/org/repository/view" ) @@ -37,9 +37,9 @@ func (o *Org) Process(event *es_models.Event) error { org := new(view.OrgView) switch event.Type { - case org_model.OrgAdded: + case model.OrgAdded: org.AppendEvent(event) - case org_model.OrgChanged: + case model.OrgChanged: err := org.SetData(event) if err != nil { return err diff --git a/internal/admin/repository/eventsourcing/setup/setup.go b/internal/admin/repository/eventsourcing/setup/setup.go index 631083c121..fd738c8958 100644 --- a/internal/admin/repository/eventsourcing/setup/setup.go +++ b/internal/admin/repository/eventsourcing/setup/setup.go @@ -125,7 +125,7 @@ func (s *Setup) Execute(ctx context.Context) error { err = setUp.setIamProject(ctx) if err != nil { - logging.Log("SETUP-kaWjq").WithError(err).Error("unable to set citadel project") + logging.Log("SETUP-kaWjq").WithError(err).Error("unable to set zitadel project") return err } diff --git a/internal/api/auth/context.go b/internal/api/auth/context.go index 3d176c31bf..220e647d4c 100644 --- a/internal/api/auth/context.go +++ b/internal/api/auth/context.go @@ -11,9 +11,9 @@ import ( type key int -var ( - permissionsKey key - dataKey key +const ( + permissionsKey key = 1 + dataKey key = 2 ) type CtxData struct { @@ -36,7 +36,7 @@ type Grant struct { type TokenVerifier interface { VerifyAccessToken(ctx context.Context, token string) (string, string, string, error) - ResolveGrants(ctx context.Context, sub, orgID string) ([]*Grant, error) + ResolveGrant(ctx context.Context) (*Grant, error) GetProjectIDByClientID(ctx context.Context, clientID string) (string, error) } diff --git a/internal/api/auth/permissions.go b/internal/api/auth/permissions.go index 04c6713915..c0e222c093 100644 --- a/internal/api/auth/permissions.go +++ b/internal/api/auth/permissions.go @@ -11,21 +11,20 @@ func getUserMethodPermissions(ctx context.Context, t TokenVerifier, requiredPerm if ctxData.IsZero() { return nil, nil, errors.ThrowUnauthenticated(nil, "AUTH-rKLWEH", "context missing") } - grants, err := t.ResolveGrants(ctx, ctxData.UserID, ctxData.OrgID) + grant, err := t.ResolveGrant(ctx) if err != nil { return nil, nil, err } - permissions := mapGrantsToPermissions(requiredPerm, grants, authConfig) + permissions := mapGrantToPermissions(requiredPerm, grant, authConfig) return context.WithValue(ctx, permissionsKey, permissions), permissions, nil } -func mapGrantsToPermissions(requiredPerm string, grants []*Grant, authConfig *Config) []string { +func mapGrantToPermissions(requiredPerm string, grant *Grant, authConfig *Config) []string { resolvedPermissions := make([]string, 0) - for _, grant := range grants { - for _, role := range grant.Roles { - resolvedPermissions = mapRoleToPerm(requiredPerm, role, authConfig, resolvedPermissions) - } + for _, role := range grant.Roles { + resolvedPermissions = mapRoleToPerm(requiredPerm, role, authConfig, resolvedPermissions) } + return resolvedPermissions } @@ -36,7 +35,7 @@ func mapRoleToPerm(requiredPerm, actualRole string, authConfig *Config, resolved for _, p := range perms { if p == requiredPerm { p = addRoleContextIDToPerm(p, roleContextID) - if !existsPerm(resolvedPermissions, p) { + if !ExistsPerm(resolvedPermissions, p) { resolvedPermissions = append(resolvedPermissions, p) } } @@ -51,7 +50,7 @@ func addRoleContextIDToPerm(perm, roleContextID string) string { return perm } -func existsPerm(existing []string, perm string) bool { +func ExistsPerm(existing []string, perm string) bool { for _, e := range existing { if e == perm { return true diff --git a/internal/api/auth/permissions_test.go b/internal/api/auth/permissions_test.go index fe48172bc7..d4ea7cfb3d 100644 --- a/internal/api/auth/permissions_test.go +++ b/internal/api/auth/permissions_test.go @@ -12,15 +12,15 @@ func getTestCtx(userID, orgID string) context.Context { } type testVerifier struct { - grants []*Grant + grant *Grant } func (v *testVerifier) VerifyAccessToken(ctx context.Context, token string) (string, string, string, error) { return "userID", "clientID", "agentID", nil } -func (v *testVerifier) ResolveGrants(ctx context.Context, sub, orgID string) ([]*Grant, error) { - return v.grants, nil +func (v *testVerifier) ResolveGrant(ctx context.Context) (*Grant, error) { + return v.grant, nil } func (v *testVerifier) GetProjectIDByClientID(ctx context.Context, clientID string) (string, error) { @@ -57,8 +57,8 @@ func Test_GetUserMethodPermissions(t *testing.T) { name: "Empty Context", args: args{ ctx: getTestCtx("", ""), - verifier: &testVerifier{grants: []*Grant{&Grant{ - Roles: []string{"ORG_OWNER"}}}}, + verifier: &testVerifier{grant: &Grant{ + Roles: []string{"ORG_OWNER"}}}, requiredPerm: "project.read", authConfig: &Config{ RolePermissionMappings: []RoleMapping{ @@ -81,7 +81,7 @@ func Test_GetUserMethodPermissions(t *testing.T) { name: "No Grants", args: args{ ctx: getTestCtx("", ""), - verifier: &testVerifier{grants: []*Grant{}}, + verifier: &testVerifier{grant: &Grant{}}, requiredPerm: "project.read", authConfig: &Config{ RolePermissionMappings: []RoleMapping{ @@ -102,8 +102,8 @@ func Test_GetUserMethodPermissions(t *testing.T) { name: "Get Permissions", args: args{ ctx: getTestCtx("userID", "orgID"), - verifier: &testVerifier{grants: []*Grant{&Grant{ - Roles: []string{"ORG_OWNER"}}}}, + verifier: &testVerifier{grant: &Grant{ + Roles: []string{"ORG_OWNER"}}}, requiredPerm: "project.read", authConfig: &Config{ RolePermissionMappings: []RoleMapping{ @@ -143,7 +143,7 @@ func Test_GetUserMethodPermissions(t *testing.T) { func Test_MapGrantsToPermissions(t *testing.T) { type args struct { requiredPerm string - grants []*Grant + grant *Grant authConfig *Config } tests := []struct { @@ -155,8 +155,7 @@ func Test_MapGrantsToPermissions(t *testing.T) { name: "One Role existing perm", args: args{ requiredPerm: "project.read", - grants: []*Grant{&Grant{ - Roles: []string{"ORG_OWNER"}}}, + grant: &Grant{Roles: []string{"ORG_OWNER"}}, authConfig: &Config{ RolePermissionMappings: []RoleMapping{ RoleMapping{ @@ -176,8 +175,7 @@ func Test_MapGrantsToPermissions(t *testing.T) { name: "One Role not existing perm", args: args{ requiredPerm: "project.write", - grants: []*Grant{&Grant{ - Roles: []string{"ORG_OWNER"}}}, + grant: &Grant{Roles: []string{"ORG_OWNER"}}, authConfig: &Config{ RolePermissionMappings: []RoleMapping{ RoleMapping{ @@ -197,8 +195,7 @@ func Test_MapGrantsToPermissions(t *testing.T) { name: "Multiple Roles one existing", args: args{ requiredPerm: "project.read", - grants: []*Grant{&Grant{ - Roles: []string{"ORG_OWNER", "IAM_OWNER"}}}, + grant: &Grant{Roles: []string{"ORG_OWNER", "IAM_OWNER"}}, authConfig: &Config{ RolePermissionMappings: []RoleMapping{ RoleMapping{ @@ -218,8 +215,7 @@ func Test_MapGrantsToPermissions(t *testing.T) { name: "Multiple Roles, global and specific", args: args{ requiredPerm: "project.read", - grants: []*Grant{&Grant{ - Roles: []string{"ORG_OWNER", "PROJECT_OWNER:1"}}}, + grant: &Grant{Roles: []string{"ORG_OWNER", "PROJECT_OWNER:1"}}, authConfig: &Config{ RolePermissionMappings: []RoleMapping{ RoleMapping{ @@ -238,7 +234,7 @@ func Test_MapGrantsToPermissions(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := mapGrantsToPermissions(tt.args.requiredPerm, tt.args.grants, tt.args.authConfig) + result := mapGrantToPermissions(tt.args.requiredPerm, tt.args.grant, tt.args.authConfig) if !equalStringArray(result, tt.result) { t.Errorf("got wrong result, expecting: %v, actual: %v ", tt.result, result) } @@ -419,7 +415,7 @@ func Test_ExistisPerm(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result := existsPerm(tt.args.existing, tt.args.perm) + result := ExistsPerm(tt.args.existing, tt.args.perm) if result != tt.result { t.Errorf("got wrong result, expecting: %v, actual: %v ", tt.result, result) } diff --git a/internal/api/header.go b/internal/api/header.go index bbafe8dd7a..4c2cc77db1 100644 --- a/internal/api/header.go +++ b/internal/api/header.go @@ -7,6 +7,8 @@ const ( ContentType = "content-type" Location = "location" Origin = "origin" + UserAgent = "user-agent" + ForwardedFor = "x-forwarded-for" ZitadelOrgID = "x-zitadel-orgid" //TODO: Remove as soon an authentification is implemented diff --git a/internal/api/http/header.go b/internal/api/http/header.go new file mode 100644 index 0000000000..9df38fce4a --- /dev/null +++ b/internal/api/http/header.go @@ -0,0 +1,71 @@ +package http + +import ( + "context" + "net" + "net/http" + "strings" + + "github.com/caos/zitadel/internal/api" +) + +type key int + +var ( + httpHeaders key + remoteAddr key +) + +func CopyHeadersToContext(h http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), httpHeaders, r.Header) + ctx = context.WithValue(ctx, remoteAddr, r.RemoteAddr) + r = r.WithContext(ctx) + h(w, r) + } +} + +func HeadersFromCtx(ctx context.Context) (http.Header, bool) { + headers, ok := ctx.Value(httpHeaders).(http.Header) + return headers, ok +} + +func RemoteIPFromCtx(ctx context.Context) string { + ctxHeaders, ok := HeadersFromCtx(ctx) + if !ok { + return RemoteAddrFromCtx(ctx) + } + forwarded, ok := ForwardedFor(ctxHeaders) + if ok { + return forwarded + } + return RemoteAddrFromCtx(ctx) +} + +func RemoteIPFromRequest(r *http.Request) net.IP { + return net.ParseIP(RemoteIPStringFromRequest(r)) +} + +func RemoteIPStringFromRequest(r *http.Request) string { + ip, ok := ForwardedFor(r.Header) + if ok { + return ip + } + return r.RemoteAddr +} + +func ForwardedFor(headers http.Header) (string, bool) { + forwarded, ok := headers[api.ForwardedFor] + if ok { + ip := strings.Split(forwarded[0], ", ")[0] + if ip != "" { + return ip, true + } + } + return "", false +} + +func RemoteAddrFromCtx(ctx context.Context) string { + ctxRemoteAddr, _ := ctx.Value(remoteAddr).(string) + return ctxRemoteAddr +} diff --git a/internal/api/http/user_agent_cookie.go b/internal/api/http/user_agent_cookie.go new file mode 100644 index 0000000000..fed230c1a0 --- /dev/null +++ b/internal/api/http/user_agent_cookie.go @@ -0,0 +1,68 @@ +package http + +import ( + "net/http" + + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/id" +) + +type UserAgent struct { + ID string +} + +type UserAgentHandler struct { + handler *CookieHandler + cookieName string + idGenerator id.Generator +} + +type UserAgentCookieConfig struct { + Name string + Domain string + Key *crypto.KeyConfig +} + +func NewUserAgentHandler(config *UserAgentCookieConfig, idGenerator id.Generator) (*UserAgentHandler, error) { + keys, _, err := crypto.LoadKeys(config.Key) + if err != nil { + return nil, err + } + cookieKey := []byte(keys[config.Key.EncryptionKeyID]) + handler := NewCookieHandler( + WithEncryption(cookieKey, cookieKey), + WithDomain(config.Domain), + WithUnsecure(), + ) + return &UserAgentHandler{ + cookieName: config.Name, + handler: handler, + idGenerator: idGenerator, + }, nil +} + +func (ua *UserAgentHandler) NewUserAgent() (*UserAgent, error) { + agentID, err := ua.idGenerator.Next() + if err != nil { + return nil, err + } + return &UserAgent{ID: agentID}, nil +} + +func (ua *UserAgentHandler) GetUserAgent(r *http.Request) (*UserAgent, error) { + userAgent := new(UserAgent) + err := ua.handler.GetEncryptedCookieValue(r, ua.cookieName, userAgent) + if err != nil { + return nil, errors.ThrowPermissionDenied(err, "HTTP-YULqH4", "cannot read user agent cookie") + } + return userAgent, nil +} + +func (ua *UserAgentHandler) SetUserAgent(w http.ResponseWriter, agent *UserAgent) error { + err := ua.handler.SetEncryptedCookie(w, ua.cookieName, agent) + if err != nil { + return errors.ThrowPermissionDenied(err, "HTTP-AqgqdA", "cannot set user agent cookie") + } + return nil +} diff --git a/internal/auth/auth/token_verifier.go b/internal/auth/auth/token_verifier.go index 84ba0abe38..10dd713abf 100644 --- a/internal/auth/auth/token_verifier.go +++ b/internal/auth/auth/token_verifier.go @@ -3,23 +3,34 @@ package auth import ( "context" "github.com/caos/zitadel/internal/api/auth" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" +) + +const ( + authName = "Auth-API" ) type TokenVerifier struct { + authID string + authZRepo *authz_repo.EsRepository } -func Start() (v *TokenVerifier) { - return new(TokenVerifier) +func Start(authZRepo *authz_repo.EsRepository) (v *TokenVerifier) { + return &TokenVerifier{authZRepo: authZRepo} } func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string) (string, string, string, error) { - return "", "", "", nil + userID, clientID, agentID, err := v.authZRepo.VerifyAccessToken(ctx, token, authName, v.authID) + if clientID != "" { + v.authID = clientID + } + return userID, clientID, agentID, err } -func (v *TokenVerifier) ResolveGrants(ctx context.Context, userID, orgID string) ([]*auth.Grant, error) { - return nil, nil +func (v *TokenVerifier) ResolveGrant(ctx context.Context) (*auth.Grant, error) { + return v.authZRepo.ResolveGrants(ctx) } func (v *TokenVerifier) GetProjectIDByClientID(ctx context.Context, clientID string) (string, error) { - return "", nil + return v.authZRepo.ProjectIDByClientID(ctx, clientID) } diff --git a/internal/auth/config.go b/internal/auth/config.go deleted file mode 100644 index bac255b177..0000000000 --- a/internal/auth/config.go +++ /dev/null @@ -1,4 +0,0 @@ -package auth - -type Config struct { -} diff --git a/internal/auth/repository/application.go b/internal/auth/repository/application.go new file mode 100644 index 0000000000..408976a355 --- /dev/null +++ b/internal/auth/repository/application.go @@ -0,0 +1,12 @@ +package repository + +import ( + "context" + + "github.com/caos/zitadel/internal/project/model" +) + +type ApplicationRepository interface { + ApplicationByClientID(ctx context.Context, clientID string) (*model.ApplicationView, error) + AuthorizeOIDCApplication(ctx context.Context, clientID, secret string) error +} diff --git a/internal/auth/repository/auth_request.go b/internal/auth/repository/auth_request.go index eebdad4cbe..b2e9715ab0 100644 --- a/internal/auth/repository/auth_request.go +++ b/internal/auth/repository/auth_request.go @@ -9,7 +9,12 @@ import ( type AuthRequestRepository interface { CreateAuthRequest(ctx context.Context, request *model.AuthRequest) (*model.AuthRequest, error) AuthRequestByID(ctx context.Context, id string) (*model.AuthRequest, error) + AuthRequestByIDCheckLoggedIn(ctx context.Context, id string) (*model.AuthRequest, error) + AuthRequestByCode(ctx context.Context, code string) (*model.AuthRequest, error) + SaveAuthCode(ctx context.Context, id, code string) error + DeleteAuthRequest(ctx context.Context, id string) error CheckUsername(ctx context.Context, id, username string) error + SelectUser(ctx context.Context, id, userID string) error VerifyPassword(ctx context.Context, id, userID, password string, info *model.BrowserInfo) error VerifyMfaOTP(ctx context.Context, agentID, authRequestID string, code string, info *model.BrowserInfo) error } diff --git a/internal/auth/repository/eventsourcing/eventstore/application.go b/internal/auth/repository/eventsourcing/eventstore/application.go new file mode 100644 index 0000000000..5d5bc76102 --- /dev/null +++ b/internal/auth/repository/eventsourcing/eventstore/application.go @@ -0,0 +1,31 @@ +package eventstore + +import ( + "context" + + "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" + "github.com/caos/zitadel/internal/project/model" + proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + proj_view_model "github.com/caos/zitadel/internal/project/repository/view/model" +) + +type ApplicationRepo struct { + View *view.View + ProjectEvents *proj_event.ProjectEventstore +} + +func (a *ApplicationRepo) ApplicationByClientID(ctx context.Context, clientID string) (*model.ApplicationView, error) { + app, err := a.View.ApplicationByClientID(ctx, clientID) + if err != nil { + return nil, err + } + return proj_view_model.ApplicationViewToModel(app), nil +} + +func (a *ApplicationRepo) AuthorizeOIDCApplication(ctx context.Context, clientID, secret string) error { + app, err := a.View.ApplicationByClientID(ctx, clientID) + if err != nil { + return err + } + return a.ProjectEvents.VerifyOIDCClientSecret(ctx, app.ProjectID, app.ID, secret) +} diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request.go b/internal/auth/repository/eventsourcing/eventstore/auth_request.go index 2cee067357..7063ab8563 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request.go @@ -4,23 +4,28 @@ import ( "context" "time" + "github.com/caos/logging" + "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" "github.com/caos/zitadel/internal/auth_request/model" - "github.com/caos/zitadel/internal/auth_request/repository/cache" + cache "github.com/caos/zitadel/internal/auth_request/repository" "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/id" user_model "github.com/caos/zitadel/internal/user/model" user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" + es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" view_model "github.com/caos/zitadel/internal/user/repository/view/model" ) type AuthRequestRepo struct { UserEvents *user_event.UserEventstore - AuthRequests *cache.AuthRequestCache + AuthRequests cache.AuthRequestCache View *view.View UserSessionViewProvider userSessionViewProvider UserViewProvider userViewProvider + UserEventProvider userEventProvider IdGenerator id.Generator @@ -38,6 +43,10 @@ type userViewProvider interface { UserByID(string) (*view_model.UserView, error) } +type userEventProvider interface { + UserEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) +} + func (repo *AuthRequestRepo) Health(ctx context.Context) error { if err := repo.UserEvents.Health(ctx); err != nil { return err @@ -51,6 +60,11 @@ func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *mod return nil, err } request.ID = reqID + ids, err := repo.View.AppIDsFromProjectByClientID(ctx, request.ApplicationID) + if err != nil { + return nil, err + } + request.Audience = ids err = repo.AuthRequests.SaveAuthRequest(ctx, request) if err != nil { return nil, err @@ -59,11 +73,28 @@ func (repo *AuthRequestRepo) CreateAuthRequest(ctx context.Context, request *mod } func (repo *AuthRequestRepo) AuthRequestByID(ctx context.Context, id string) (*model.AuthRequest, error) { + return repo.getAuthRequest(ctx, id, false) +} + +func (repo *AuthRequestRepo) AuthRequestByIDCheckLoggedIn(ctx context.Context, id string) (*model.AuthRequest, error) { + return repo.getAuthRequest(ctx, id, true) +} + +func (repo *AuthRequestRepo) SaveAuthCode(ctx context.Context, id, code string) error { request, err := repo.AuthRequests.GetAuthRequestByID(ctx, id) + if err != nil { + return err + } + request.Code = code + return repo.AuthRequests.UpdateAuthRequest(ctx, request) +} + +func (repo *AuthRequestRepo) AuthRequestByCode(ctx context.Context, code string) (*model.AuthRequest, error) { + request, err := repo.AuthRequests.GetAuthRequestByCode(ctx, code) if err != nil { return nil, err } - steps, err := repo.nextSteps(request) + steps, err := repo.nextSteps(ctx, request, true) if err != nil { return nil, err } @@ -71,6 +102,10 @@ func (repo *AuthRequestRepo) AuthRequestByID(ctx context.Context, id string) (*m return request, nil } +func (repo *AuthRequestRepo) DeleteAuthRequest(ctx context.Context, id string) error { + return repo.AuthRequests.DeleteAuthRequest(ctx, id) +} + func (repo *AuthRequestRepo) CheckUsername(ctx context.Context, id, username string) error { request, err := repo.AuthRequests.GetAuthRequestByID(ctx, id) if err != nil { @@ -80,8 +115,21 @@ func (repo *AuthRequestRepo) CheckUsername(ctx context.Context, id, username str if err != nil { return err } - request.UserID = user.ID - return repo.AuthRequests.SaveAuthRequest(ctx, request) + request.SetUserInfo(user.ID, user.UserName, user.ResourceOwner) + return repo.AuthRequests.UpdateAuthRequest(ctx, request) +} + +func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID string) error { + request, err := repo.AuthRequests.GetAuthRequestByID(ctx, id) + if err != nil { + return err + } + user, err := repo.View.UserByID(userID) + if err != nil { + return err + } + request.SetUserInfo(user.ID, user.UserName, user.ResourceOwner) + return repo.AuthRequests.UpdateAuthRequest(ctx, request) } func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, id, userID, password string, info *model.BrowserInfo) error { @@ -89,8 +137,8 @@ func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, id, userID, pas if err != nil { return err } - if request.UserID == userID { - return errors.ThrowPreconditionFailed(nil, "EVENT-ds35D", "user id does not match request id ") + if request.UserID != userID { + return errors.ThrowPreconditionFailed(nil, "EVENT-ds35D", "user id does not match request id") } return repo.UserEvents.CheckPassword(ctx, userID, password, request.WithCurrentInfo(info)) } @@ -106,15 +154,29 @@ func (repo *AuthRequestRepo) VerifyMfaOTP(ctx context.Context, authRequestID, us return repo.UserEvents.CheckMfaOTP(ctx, userID, code, request.WithCurrentInfo(info)) } -func (repo *AuthRequestRepo) nextSteps(request *model.AuthRequest) ([]model.NextStep, error) { +func (repo *AuthRequestRepo) getAuthRequest(ctx context.Context, id string, checkLoggedIn bool) (*model.AuthRequest, error) { + request, err := repo.AuthRequests.GetAuthRequestByID(ctx, id) + if err != nil { + return nil, err + } + steps, err := repo.nextSteps(ctx, request, checkLoggedIn) + if err != nil { + return nil, err + } + request.PossibleSteps = steps + return request, nil +} + +func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthRequest, checkLoggedIn bool) ([]model.NextStep, error) { if request == nil { return nil, errors.ThrowInvalidArgument(nil, "EVENT-ds27a", "request must not be nil") } steps := make([]model.NextStep, 0) + if !checkLoggedIn && request.Prompt == model.PromptNone { + return append(steps, &model.RedirectToCallbackStep{}), nil + } if request.UserID == "" { - if request.Prompt != model.PromptNone { - steps = append(steps, &model.LoginStep{}) - } + steps = append(steps, &model.LoginStep{}) if request.Prompt == model.PromptSelectAccount { users, err := repo.usersForUserSelection(request) if err != nil { @@ -124,15 +186,18 @@ func (repo *AuthRequestRepo) nextSteps(request *model.AuthRequest) ([]model.Next } return steps, nil } - userSession, err := userSessionByIDs(repo.UserSessionViewProvider, request.AgentID, request.UserID) + user, err := userByID(ctx, repo.UserViewProvider, repo.UserEventProvider, request.UserID) if err != nil { return nil, err } - user, err := userByID(repo.UserViewProvider, request.UserID) + userSession, err := userSessionByIDs(ctx, repo.UserSessionViewProvider, repo.UserEventProvider, request.AgentID, user) if err != nil { return nil, err } + if user.InitRequired { + return append(steps, &model.InitUserStep{PasswordSet: user.PasswordSet}), nil + } if !user.PasswordSet { return append(steps, &model.InitPasswordStep{}), nil } @@ -140,6 +205,8 @@ func (repo *AuthRequestRepo) nextSteps(request *model.AuthRequest) ([]model.Next if !checkVerificationTime(userSession.PasswordVerification, repo.PasswordCheckLifeTime) { return append(steps, &model.PasswordStep{}), nil } + request.PasswordVerified = true + request.AuthTime = userSession.PasswordVerification if step, ok := repo.mfaChecked(userSession, request, user); !ok { return append(steps, step), nil @@ -178,23 +245,32 @@ func (repo *AuthRequestRepo) usersForUserSelection(request *model.AuthRequest) ( func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *model.AuthRequest, user *user_model.UserView) (model.NextStep, bool) { mfaLevel := request.MfaLevel() - required := user.MfaMaxSetUp < mfaLevel - if required || !repo.mfaSkippedOrSetUp(user) { + promptRequired := user.MfaMaxSetUp < mfaLevel + if promptRequired || !repo.mfaSkippedOrSetUp(user) { return &model.MfaPromptStep{ - Required: required, + Required: promptRequired, MfaProviders: user.MfaTypesSetupPossible(mfaLevel), }, false } switch mfaLevel { default: fallthrough + case model.MfaLevelNotSetUp: + if user.MfaMaxSetUp == model.MfaLevelNotSetUp { + return nil, true + } + fallthrough case model.MfaLevelSoftware: if checkVerificationTime(userSession.MfaSoftwareVerification, repo.MfaSoftwareCheckLifeTime) { + request.MfasVerified = append(request.MfasVerified, userSession.MfaSoftwareVerificationType) + request.AuthTime = userSession.MfaSoftwareVerification return nil, true } fallthrough case model.MfaLevelHardware: if checkVerificationTime(userSession.MfaHardwareVerification, repo.MfaHardwareCheckLifeTime) { + request.MfasVerified = append(request.MfasVerified, userSession.MfaHardwareVerificationType) + request.AuthTime = userSession.MfaHardwareVerification return nil, true } } @@ -204,7 +280,7 @@ func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, } func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView) bool { - if user.MfaMaxSetUp >= 0 { + if user.MfaMaxSetUp > model.MfaLevelNotSetUp { return true } return checkVerificationTime(user.MfaInitSkipped, repo.MfaInitSkippedLifeTime) @@ -222,18 +298,55 @@ func userSessionsByUserAgentID(provider userSessionViewProvider, agentID string) return view_model.UserSessionsToModel(session), nil } -func userSessionByIDs(provider userSessionViewProvider, agentID, userID string) (*user_model.UserSessionView, error) { - session, err := provider.UserSessionByIDs(agentID, userID) +func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eventProvider userEventProvider, agentID string, user *user_model.UserView) (*user_model.UserSessionView, error) { + session, err := provider.UserSessionByIDs(agentID, user.ID) if err != nil { - return nil, err + if !errors.IsNotFound(err) { + return nil, err + } + session = &view_model.UserSessionView{} } - return view_model.UserSessionToModel(session), nil + events, err := eventProvider.UserEventsByID(ctx, user.ID, session.Sequence) + if err != nil { + logging.Log("EVENT-Hse6s").WithError(err).Debug("error retrieving new events") + return view_model.UserSessionToModel(session), nil + } + sessionCopy := *session + for _, event := range events { + switch event.Type { + case es_model.UserPasswordCheckSucceeded, + es_model.UserPasswordCheckFailed, + es_model.MfaOtpCheckSucceeded, + es_model.MfaOtpCheckFailed: + eventData, err := view_model.UserSessionFromEvent(event) + if err != nil { + logging.Log("EVENT-sdgT3").WithError(err).Debug("error getting event data") + return view_model.UserSessionToModel(session), nil + } + if eventData.UserAgentID != agentID { + continue + } + } + sessionCopy.AppendEvent(event) + } + return view_model.UserSessionToModel(&sessionCopy), nil } -func userByID(provider userViewProvider, userID string) (*user_model.UserView, error) { - user, err := provider.UserByID(userID) +func userByID(ctx context.Context, viewProvider userViewProvider, eventProvider userEventProvider, userID string) (*user_model.UserView, error) { + user, err := viewProvider.UserByID(userID) if err != nil { return nil, err } - return view_model.UserToModel(user), nil + events, err := eventProvider.UserEventsByID(ctx, userID, user.Sequence) + if err != nil { + logging.Log("EVENT-dfg42").WithError(err).Debug("error retrieving new events") + return view_model.UserToModel(user), nil + } + userCopy := *user + for _, event := range events { + if err := userCopy.AppendEvent(event); err != nil { + return view_model.UserToModel(user), nil + } + } + return view_model.UserToModel(&userCopy), nil } diff --git a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go index 9500118d07..a57f63df8e 100644 --- a/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go +++ b/internal/auth/repository/eventsourcing/eventstore/auth_request_test.go @@ -1,6 +1,8 @@ package eventstore import ( + "context" + "encoding/json" "testing" "time" @@ -10,8 +12,10 @@ import ( "github.com/caos/zitadel/internal/auth_request/model" "github.com/caos/zitadel/internal/auth_request/repository/cache" "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" user_model "github.com/caos/zitadel/internal/user/model" user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" + user_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" view_model "github.com/caos/zitadel/internal/user/repository/view/model" ) @@ -25,6 +29,16 @@ func (m *mockViewNoUserSession) UserSessionsByAgentID(string) ([]*view_model.Use return nil, errors.ThrowInternal(nil, "id", "internal error") } +type mockViewErrUserSession struct{} + +func (m *mockViewErrUserSession) UserSessionByIDs(string, string) (*view_model.UserSessionView, error) { + return nil, errors.ThrowInternal(nil, "id", "internal error") +} + +func (m *mockViewErrUserSession) UserSessionsByAgentID(string) ([]*view_model.UserSessionView, error) { + return nil, errors.ThrowInternal(nil, "id", "internal error") +} + type mockViewUserSession struct { PasswordVerification time.Time MfaSoftwareVerification time.Time @@ -60,7 +74,26 @@ func (m *mockViewNoUser) UserByID(string) (*view_model.UserView, error) { return nil, errors.ThrowNotFound(nil, "id", "user not found") } +type mockEventUser struct { + Event *es_models.Event +} + +func (m *mockEventUser) UserEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) { + events := make([]*es_models.Event, 0) + if m.Event != nil { + events = append(events, m.Event) + } + return events, nil +} + +type mockEventErrUser struct{} + +func (m *mockEventErrUser) UserEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) { + return nil, errors.ThrowInternal(nil, "id", "internal error") +} + type mockViewUser struct { + InitRequired bool PasswordSet bool PasswordChangeRequired bool IsEmailVerified bool @@ -71,6 +104,7 @@ type mockViewUser struct { func (m *mockViewUser) UserByID(string) (*view_model.UserView, error) { return &view_model.UserView{ + InitRequired: m.InitRequired, PasswordSet: m.PasswordSet, PasswordChangeRequired: m.PasswordChangeRequired, IsEmailVerified: m.IsEmailVerified, @@ -87,13 +121,15 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { View *view.View userSessionViewProvider userSessionViewProvider userViewProvider userViewProvider + userEventProvider userEventProvider PasswordCheckLifeTime time.Duration MfaInitSkippedLifeTime time.Duration MfaSoftwareCheckLifeTime time.Duration MfaHardwareCheckLifeTime time.Duration } type args struct { - request *model.AuthRequest + request *model.AuthRequest + checkLoggedIn bool } tests := []struct { name string @@ -105,22 +141,22 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { { "request nil, error", fields{}, - args{nil}, + args{nil, false}, nil, errors.IsErrorInvalidArgument, }, { - "user not set, login step", + "prompt none and checkLoggedIn false, callback step", fields{}, - args{&model.AuthRequest{}}, - []model.NextStep{&model.LoginStep{}}, + args{&model.AuthRequest{Prompt: model.PromptNone}, false}, + []model.NextStep{&model.RedirectToCallbackStep{}}, nil, }, { - "user not set and prompt none, no step", + "user not set, login step", fields{}, - args{&model.AuthRequest{Prompt: model.PromptNone}}, - []model.NextStep{}, + args{&model.AuthRequest{}, false}, + []model.NextStep{&model.LoginStep{}}, nil, }, { @@ -128,7 +164,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { fields{ userSessionViewProvider: &mockViewNoUserSession{}, }, - args{&model.AuthRequest{Prompt: model.PromptSelectAccount}}, + args{&model.AuthRequest{Prompt: model.PromptSelectAccount}, false}, nil, errors.IsInternal, }, @@ -147,8 +183,9 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { }, }, }, + userEventProvider: &mockEventUser{}, }, - args{&model.AuthRequest{Prompt: model.PromptSelectAccount}}, + args{&model.AuthRequest{Prompt: model.PromptSelectAccount}, false}, []model.NextStep{ &model.LoginStep{}, &model.SelectUserStep{ @@ -166,31 +203,63 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { nil, }, { - "usersession not found, not found error", + "user not not found, not found error", fields{ - userSessionViewProvider: &mockViewNoUserSession{}, + userViewProvider: &mockViewNoUser{}, + userEventProvider: &mockEventUser{}, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, nil, errors.IsNotFound, }, { - "user not not found, not found error", + "usersession not found, new user session, password step", + fields{ + userSessionViewProvider: &mockViewNoUserSession{}, + userViewProvider: &mockViewUser{ + PasswordSet: true, + }, + userEventProvider: &mockEventUser{}, + }, + args{&model.AuthRequest{UserID: "UserID"}, false}, + []model.NextStep{&model.PasswordStep{}}, + nil, + }, + { + "usersession error, internal error", + fields{ + userSessionViewProvider: &mockViewErrUserSession{}, + userViewProvider: &mockViewUser{}, + userEventProvider: &mockEventUser{}, + }, + args{&model.AuthRequest{UserID: "UserID"}, false}, + nil, + errors.IsInternal, + }, + { + "user not initialized, init user step", fields{ userSessionViewProvider: &mockViewUserSession{}, - userViewProvider: &mockViewNoUser{}, + userViewProvider: &mockViewUser{ + InitRequired: true, + PasswordSet: true, + }, + userEventProvider: &mockEventUser{}, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, + []model.NextStep{&model.InitUserStep{ + PasswordSet: true, + }}, nil, - errors.IsNotFound, }, { "password not set, init password step", fields{ userSessionViewProvider: &mockViewUserSession{}, userViewProvider: &mockViewUser{}, + userEventProvider: &mockEventUser{}, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, []model.NextStep{&model.InitPasswordStep{}}, nil, }, @@ -201,9 +270,10 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { userViewProvider: &mockViewUser{ PasswordSet: true, }, + userEventProvider: &mockEventUser{}, PasswordCheckLifeTime: 10 * 24 * time.Hour, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, []model.NextStep{&model.PasswordStep{}}, nil, }, @@ -218,10 +288,11 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { OTPState: int32(user_model.MFASTATE_READY), MfaMaxSetUp: int32(model.MfaLevelSoftware), }, + userEventProvider: &mockEventUser{}, PasswordCheckLifeTime: 10 * 24 * time.Hour, MfaSoftwareCheckLifeTime: 18 * time.Hour, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, []model.NextStep{&model.MfaVerificationStep{ MfaProviders: []model.MfaType{model.MfaTypeOTP}, }}, @@ -238,11 +309,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { PasswordSet: true, PasswordChangeRequired: true, IsEmailVerified: true, + MfaMaxSetUp: int32(model.MfaLevelSoftware), }, + userEventProvider: &mockEventUser{}, PasswordCheckLifeTime: 10 * 24 * time.Hour, MfaSoftwareCheckLifeTime: 18 * time.Hour, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, []model.NextStep{&model.ChangePasswordStep{}}, nil, }, @@ -255,11 +328,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { }, userViewProvider: &mockViewUser{ PasswordSet: true, + MfaMaxSetUp: int32(model.MfaLevelSoftware), }, + userEventProvider: &mockEventUser{}, PasswordCheckLifeTime: 10 * 24 * time.Hour, MfaSoftwareCheckLifeTime: 18 * time.Hour, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, []model.NextStep{&model.VerifyEMailStep{}}, nil, }, @@ -273,11 +348,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { userViewProvider: &mockViewUser{ PasswordSet: true, PasswordChangeRequired: true, + MfaMaxSetUp: int32(model.MfaLevelSoftware), }, + userEventProvider: &mockEventUser{}, PasswordCheckLifeTime: 10 * 24 * time.Hour, MfaSoftwareCheckLifeTime: 18 * time.Hour, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, []model.NextStep{&model.ChangePasswordStep{}, &model.VerifyEMailStep{}}, nil, }, @@ -291,11 +368,33 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { userViewProvider: &mockViewUser{ PasswordSet: true, IsEmailVerified: true, + MfaMaxSetUp: int32(model.MfaLevelSoftware), }, + userEventProvider: &mockEventUser{}, PasswordCheckLifeTime: 10 * 24 * time.Hour, MfaSoftwareCheckLifeTime: 18 * time.Hour, }, - args{&model.AuthRequest{UserID: "UserID"}}, + args{&model.AuthRequest{UserID: "UserID"}, false}, + []model.NextStep{&model.RedirectToCallbackStep{}}, + nil, + }, + { + "prompt none, checkLoggedIn true and authenticated, redirect to callback step", + fields{ + userSessionViewProvider: &mockViewUserSession{ + PasswordVerification: time.Now().UTC().Add(-5 * time.Minute), + MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Minute), + }, + userViewProvider: &mockViewUser{ + PasswordSet: true, + IsEmailVerified: true, + MfaMaxSetUp: int32(model.MfaLevelSoftware), + }, + userEventProvider: &mockEventUser{}, + PasswordCheckLifeTime: 10 * 24 * time.Hour, + MfaSoftwareCheckLifeTime: 18 * time.Hour, + }, + args{&model.AuthRequest{UserID: "UserID", Prompt: model.PromptNone}, true}, []model.NextStep{&model.RedirectToCallbackStep{}}, nil, }, @@ -308,12 +407,13 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) { View: tt.fields.View, UserSessionViewProvider: tt.fields.userSessionViewProvider, UserViewProvider: tt.fields.userViewProvider, + UserEventProvider: tt.fields.userEventProvider, PasswordCheckLifeTime: tt.fields.PasswordCheckLifeTime, MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime, MfaSoftwareCheckLifeTime: tt.fields.MfaSoftwareCheckLifeTime, MfaHardwareCheckLifeTime: tt.fields.MfaHardwareCheckLifeTime, } - got, err := repo.nextSteps(tt.args.request) + got, err := repo.nextSteps(context.Background(), tt.args.request, tt.args.checkLoggedIn) if (err != nil && tt.wantErr == nil) || (tt.wantErr != nil && !tt.wantErr(err)) { t.Errorf("nextSteps() wrong error = %v", err) return @@ -360,14 +460,31 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { args{ request: &model.AuthRequest{}, user: &user_model.UserView{ - MfaMaxSetUp: -1, + MfaMaxSetUp: model.MfaLevelNotSetUp, }, }, &model.MfaPromptStep{ - MfaProviders: []model.MfaType{}, + MfaProviders: []model.MfaType{ + model.MfaTypeOTP, + }, }, false, }, + { + "not set up and skipped, true", + fields{ + MfaInitSkippedLifeTime: 30 * 24 * time.Hour, + }, + args{ + request: &model.AuthRequest{}, + user: &user_model.UserView{ + MfaMaxSetUp: model.MfaLevelNotSetUp, + MfaInitSkipped: time.Now().UTC(), + }, + }, + nil, + true, + }, { "checked mfa software, true", fields{ @@ -376,7 +493,8 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { args{ request: &model.AuthRequest{}, user: &user_model.UserView{ - OTPState: user_model.MFASTATE_READY, + MfaMaxSetUp: model.MfaLevelSoftware, + OTPState: user_model.MFASTATE_READY, }, userSession: &user_model.UserSessionView{MfaSoftwareVerification: time.Now().UTC().Add(-5 * time.Hour)}, }, @@ -391,7 +509,8 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) { args{ request: &model.AuthRequest{}, user: &user_model.UserView{ - OTPState: user_model.MFASTATE_READY, + MfaMaxSetUp: model.MfaLevelSoftware, + OTPState: user_model.MFASTATE_READY, }, userSession: &user_model.UserSessionView{}, }, @@ -473,3 +592,235 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) { }) } } + +func Test_userSessionByIDs(t *testing.T) { + type args struct { + userProvider userSessionViewProvider + eventProvider userEventProvider + agentID string + user *user_model.UserView + } + tests := []struct { + name string + args args + want *user_model.UserSessionView + wantErr func(error) bool + }{ + { + "not found, new session", + args{ + userProvider: &mockViewNoUserSession{}, + eventProvider: &mockEventErrUser{}, + user: &user_model.UserView{ID: "id"}, + }, + &user_model.UserSessionView{}, + nil, + }, + { + "internal error, internal error", + args{ + userProvider: &mockViewErrUserSession{}, + user: &user_model.UserView{ID: "id"}, + }, + nil, + errors.IsInternal, + }, + { + "error user events, old view model state", + args{ + userProvider: &mockViewUserSession{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + }, + user: &user_model.UserView{ID: "id"}, + eventProvider: &mockEventErrUser{}, + }, + &user_model.UserSessionView{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + MfaSoftwareVerification: time.Time{}, + MfaHardwareVerification: time.Time{}, + }, + nil, + }, + { + "new user events but error, old view model state", + args{ + userProvider: &mockViewUserSession{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + }, + agentID: "agentID", + user: &user_model.UserView{ID: "id"}, + eventProvider: &mockEventUser{ + &es_models.Event{ + AggregateType: user_es_model.UserAggregate, + Type: user_es_model.MfaOtpCheckSucceeded, + CreationDate: time.Now().UTC().Round(1 * time.Second), + }, + }, + }, + &user_model.UserSessionView{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + MfaSoftwareVerification: time.Time{}, + MfaHardwareVerification: time.Time{}, + }, + nil, + }, + { + "new user events but other agentID, old view model state", + args{ + userProvider: &mockViewUserSession{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + }, + agentID: "agentID", + user: &user_model.UserView{ID: "id"}, + eventProvider: &mockEventUser{ + &es_models.Event{ + AggregateType: user_es_model.UserAggregate, + Type: user_es_model.MfaOtpCheckSucceeded, + CreationDate: time.Now().UTC().Round(1 * time.Second), + Data: func() []byte { + data, _ := json.Marshal(&user_es_model.AuthRequest{UserAgentID: "otherID"}) + return data + }(), + }, + }, + }, + &user_model.UserSessionView{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + MfaSoftwareVerification: time.Time{}, + MfaHardwareVerification: time.Time{}, + }, + nil, + }, + { + "new user events, new view model state", + args{ + userProvider: &mockViewUserSession{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + }, + agentID: "agentID", + user: &user_model.UserView{ID: "id"}, + eventProvider: &mockEventUser{ + &es_models.Event{ + AggregateType: user_es_model.UserAggregate, + Type: user_es_model.MfaOtpCheckSucceeded, + CreationDate: time.Now().UTC().Round(1 * time.Second), + Data: func() []byte { + data, _ := json.Marshal(&user_es_model.AuthRequest{UserAgentID: "agentID"}) + return data + }(), + }, + }, + }, + &user_model.UserSessionView{ + PasswordVerification: time.Now().UTC().Round(1 * time.Second), + MfaSoftwareVerification: time.Now().UTC().Round(1 * time.Second), + ChangeDate: time.Now().UTC().Round(1 * time.Second), + }, + nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := userSessionByIDs(context.Background(), tt.args.userProvider, tt.args.eventProvider, tt.args.agentID, tt.args.user) + if (err != nil && tt.wantErr == nil) || (tt.wantErr != nil && !tt.wantErr(err)) { + t.Errorf("nextSteps() wrong error = %v", err) + return + } + assert.Equal(t, tt.want, got) + }) + } +} + +func Test_userByID(t *testing.T) { + type args struct { + ctx context.Context + viewProvider userViewProvider + eventProvider userEventProvider + userID string + } + tests := []struct { + name string + args args + want *user_model.UserView + wantErr func(error) bool + }{ + + { + "not found, not found error", + args{ + viewProvider: &mockViewNoUser{}, + }, + nil, + errors.IsNotFound, + }, + { + "error user events, old view model state", + args{ + viewProvider: &mockViewUser{ + PasswordChangeRequired: true, + }, + eventProvider: &mockEventErrUser{}, + }, + &user_model.UserView{ + PasswordChangeRequired: true, + }, + nil, + }, + { + "new user events but error, old view model state", + args{ + viewProvider: &mockViewUser{ + PasswordChangeRequired: true, + }, + eventProvider: &mockEventUser{ + &es_models.Event{ + AggregateType: user_es_model.UserAggregate, + Type: user_es_model.UserPasswordChanged, + CreationDate: time.Now().UTC().Round(1 * time.Second), + Data: nil, + }, + }, + }, + &user_model.UserView{ + PasswordChangeRequired: true, + }, + nil, + }, + { + "new user events, new view model state", + args{ + viewProvider: &mockViewUser{ + PasswordChangeRequired: true, + }, + eventProvider: &mockEventUser{ + &es_models.Event{ + AggregateType: user_es_model.UserAggregate, + Type: user_es_model.UserPasswordChanged, + CreationDate: time.Now().UTC().Round(1 * time.Second), + Data: func() []byte { + data, _ := json.Marshal(user_es_model.Password{ChangeRequired: false}) + return data + }(), + }, + }, + }, + &user_model.UserView{ + PasswordChangeRequired: false, + ChangeDate: time.Now().UTC().Round(1 * time.Second), + State: user_model.USERSTATE_INITIAL, + PasswordChanged: time.Now().UTC().Round(1 * time.Second), + }, + nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := userByID(tt.args.ctx, tt.args.viewProvider, tt.args.eventProvider, tt.args.userID) + if (err != nil && tt.wantErr == nil) || (tt.wantErr != nil && !tt.wantErr(err)) { + t.Errorf("nextSteps() wrong error = %v", err) + return + } + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/internal/auth/repository/eventsourcing/eventstore/iam.go b/internal/auth/repository/eventsourcing/eventstore/iam.go new file mode 100644 index 0000000000..e27c6a92f4 --- /dev/null +++ b/internal/auth/repository/eventsourcing/eventstore/iam.go @@ -0,0 +1,16 @@ +package eventstore + +import ( + "context" + "github.com/caos/zitadel/internal/iam/model" + iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" +) + +type IamRepository struct { + IamID string + IamEvents *iam_event.IamEventstore +} + +func (repo *IamRepository) GetIam(ctx context.Context) (*model.Iam, error) { + return repo.IamEvents.IamByID(ctx, repo.IamID) +} diff --git a/internal/auth/repository/eventsourcing/eventstore/key.go b/internal/auth/repository/eventsourcing/eventstore/key.go new file mode 100644 index 0000000000..1372d56885 --- /dev/null +++ b/internal/auth/repository/eventsourcing/eventstore/key.go @@ -0,0 +1,75 @@ +package eventstore + +import ( + "context" + "time" + + "gopkg.in/square/go-jose.v2" + + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" + "github.com/caos/zitadel/internal/key/model" + key_event "github.com/caos/zitadel/internal/key/repository/eventsourcing" +) + +const ( + oidcUser = "OIDC" + iamOrg = "IAM" +) + +type KeyRepository struct { + KeyEvents *key_event.KeyEventstore + View *view.View + SigningKeyRotation time.Duration +} + +func (k *KeyRepository) GenerateSigningKeyPair(ctx context.Context, algorithm string) error { + ctx = setOIDCCtx(ctx) + _, err := k.KeyEvents.GenerateKeyPair(ctx, model.KeyUsageSigning, algorithm) + return err +} + +func (k *KeyRepository) GetSigningKey(ctx context.Context, keyCh chan<- jose.SigningKey, errCh chan<- error, renewTimer <-chan time.Time) { + go func() { + for { + select { + case <-ctx.Done(): + return + case <-renewTimer: + k.refreshSigningKey(keyCh, errCh) + renewTimer = time.After(k.SigningKeyRotation) + } + } + }() +} + +func (k *KeyRepository) GetKeySet(ctx context.Context) (*jose.JSONWebKeySet, error) { + keys, err := k.View.GetActiveKeySet() + if err != nil { + return nil, err + } + webKeys := make([]jose.JSONWebKey, len(keys)) + for i, key := range keys { + webKeys[i] = jose.JSONWebKey{KeyID: key.ID, Algorithm: key.Algorithm, Use: key.Usage.String(), Key: key.Key} + } + return &jose.JSONWebKeySet{Keys: webKeys}, nil +} + +func (k *KeyRepository) refreshSigningKey(keyCh chan<- jose.SigningKey, errCh chan<- error) { + key, err := k.View.GetSigningKey() + if err != nil { + errCh <- err + return + } + keyCh <- jose.SigningKey{ + Algorithm: jose.SignatureAlgorithm(key.Algorithm), + Key: jose.JSONWebKey{ + KeyID: key.ID, + Key: key.Key, + }, + } +} + +func setOIDCCtx(ctx context.Context) context.Context { + return auth.SetCtxData(ctx, auth.CtxData{UserID: oidcUser, OrgID: iamOrg}) +} diff --git a/internal/auth/repository/eventsourcing/eventstore/org.go b/internal/auth/repository/eventsourcing/eventstore/org.go new file mode 100644 index 0000000000..bcede6a500 --- /dev/null +++ b/internal/auth/repository/eventsourcing/eventstore/org.go @@ -0,0 +1,29 @@ +package eventstore + +import ( + "context" + auth_view "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" + org_model "github.com/caos/zitadel/internal/org/model" + org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" + "github.com/caos/zitadel/internal/org/repository/view" +) + +type OrgRepository struct { + SearchLimit uint64 + *org_es.OrgEventstore + View *auth_view.View +} + +func (repo *OrgRepository) SearchOrgs(ctx context.Context, request *org_model.OrgSearchRequest) (*org_model.OrgSearchResult, error) { + request.EnsureLimit(repo.SearchLimit) + members, count, err := repo.View.SearchOrgs(request) + if err != nil { + return nil, err + } + return &org_model.OrgSearchResult{ + Offset: request.Offset, + Limit: request.Limit, + TotalResult: uint64(count), + Result: view.OrgsToModel(members), + }, nil +} diff --git a/internal/auth/repository/eventsourcing/eventstore/token.go b/internal/auth/repository/eventsourcing/eventstore/token.go index bceae0a43c..0bc4339b93 100644 --- a/internal/auth/repository/eventsourcing/eventstore/token.go +++ b/internal/auth/repository/eventsourcing/eventstore/token.go @@ -13,8 +13,8 @@ type TokenRepo struct { View *view.View } -func (repo *TokenRepo) CreateToken(ctx context.Context, agentID, applicationID, userID string, lifetime time.Duration) (*token_model.Token, error) { - token, err := repo.View.CreateToken(agentID, applicationID, userID, lifetime) +func (repo *TokenRepo) CreateToken(ctx context.Context, agentID, applicationID, userID string, audience, scopes []string, lifetime time.Duration) (*token_model.Token, error) { + token, err := repo.View.CreateToken(agentID, applicationID, userID, audience, scopes, lifetime) if err != nil { return nil, err } @@ -24,3 +24,11 @@ func (repo *TokenRepo) CreateToken(ctx context.Context, agentID, applicationID, func (repo *TokenRepo) IsTokenValid(ctx context.Context, tokenID string) (bool, error) { return repo.View.IsTokenValid(tokenID) } + +func (repo *TokenRepo) TokenByID(ctx context.Context, tokenID string) (*token_model.Token, error) { + token, err := repo.View.TokenByID(tokenID) + if err != nil { + return nil, err + } + return token_view_model.TokenToModel(token), nil +} diff --git a/internal/auth/repository/eventsourcing/eventstore/user.go b/internal/auth/repository/eventsourcing/eventstore/user.go index 7ffa707318..05decdf900 100644 --- a/internal/auth/repository/eventsourcing/eventstore/user.go +++ b/internal/auth/repository/eventsourcing/eventstore/user.go @@ -56,10 +56,18 @@ func (repo *UserRepo) ChangeMyEmail(ctx context.Context, email *model.Email) (*m return repo.UserEvents.ChangeEmail(ctx, email) } +func (repo *UserRepo) VerifyEmail(ctx context.Context, userID, code string) error { + return repo.UserEvents.VerifyEmail(ctx, userID, code) +} + func (repo *UserRepo) VerifyMyEmail(ctx context.Context, code string) error { return repo.UserEvents.VerifyEmail(ctx, auth.GetCtxData(ctx).UserID, code) } +func (repo *UserRepo) ResendEmailVerificationMail(ctx context.Context, userID string) error { + return repo.UserEvents.CreateEmailVerificationCode(ctx, userID) +} + func (repo *UserRepo) ResendMyEmailVerificationMail(ctx context.Context) error { return repo.UserEvents.CreateEmailVerificationCode(ctx, auth.GetCtxData(ctx).UserID) } @@ -103,11 +111,28 @@ func (repo *UserRepo) ChangeMyPassword(ctx context.Context, old, new string) err return err } +func (repo *UserRepo) ChangePassword(ctx context.Context, userID, old, new string) error { + policy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, auth.GetCtxData(ctx).OrgID) + if err != nil { + return err + } + _, err = repo.UserEvents.ChangePassword(ctx, policy, userID, old, new) + return err +} + +func (repo *UserRepo) AddMfaOTP(ctx context.Context, userID string) (*model.OTP, error) { + return repo.UserEvents.AddOTP(ctx, userID) +} + func (repo *UserRepo) AddMyMfaOTP(ctx context.Context) (*model.OTP, error) { return repo.UserEvents.AddOTP(ctx, auth.GetCtxData(ctx).UserID) } -func (repo *UserRepo) VerifyMyMfaOTP(ctx context.Context, code string) error { +func (repo *UserRepo) VerifyMfaOTPSetup(ctx context.Context, userID, code string) error { + return repo.UserEvents.CheckMfaOTPSetup(ctx, userID, code) +} + +func (repo *UserRepo) VerifyMyMfaOTPSetup(ctx context.Context, code string) error { return repo.UserEvents.CheckMfaOTPSetup(ctx, auth.GetCtxData(ctx).UserID, code) } @@ -115,6 +140,19 @@ func (repo *UserRepo) RemoveMyMfaOTP(ctx context.Context) error { return repo.UserEvents.RemoveOTP(ctx, auth.GetCtxData(ctx).UserID) } +func (repo *UserRepo) ResendInitVerificationMail(ctx context.Context, userID string) error { + _, err := repo.UserEvents.CreateInitializeUserCodeByID(ctx, userID) + return err +} + +func (repo *UserRepo) VerifyInitCode(ctx context.Context, userID, code, password string) error { + policy, err := repo.PolicyEvents.GetPasswordComplexityPolicy(ctx, auth.GetCtxData(ctx).OrgID) + if err != nil { + return err + } + return repo.UserEvents.VerifyInitCode(ctx, policy, userID, code, password) +} + func (repo *UserRepo) SkipMfaInit(ctx context.Context, userID string) error { return repo.UserEvents.SkipMfaInit(ctx, userID) } @@ -139,6 +177,10 @@ func (repo *UserRepo) SignOut(ctx context.Context, agentID, userID string) error return repo.UserEvents.SignOut(ctx, agentID, userID) } +func (repo *UserRepo) UserByID(ctx context.Context, userID string) (*model.User, error) { + return repo.UserEvents.UserByID(ctx, userID) +} + func checkIDs(ctx context.Context, obj es_models.ObjectRoot) error { if obj.AggregateID != auth.GetCtxData(ctx).UserID { return errors.ThrowPermissionDenied(nil, "EVENT-kFi9w", "object does not belong to user") diff --git a/internal/auth/repository/eventsourcing/eventstore/user_grant.go b/internal/auth/repository/eventsourcing/eventstore/user_grant.go new file mode 100644 index 0000000000..cad53713c5 --- /dev/null +++ b/internal/auth/repository/eventsourcing/eventstore/user_grant.go @@ -0,0 +1,158 @@ +package eventstore + +import ( + "context" + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" + caos_errs "github.com/caos/zitadel/internal/errors" + global_model "github.com/caos/zitadel/internal/model" + org_model "github.com/caos/zitadel/internal/org/model" + org_view "github.com/caos/zitadel/internal/org/repository/view" + grant_model "github.com/caos/zitadel/internal/usergrant/model" + "github.com/caos/zitadel/internal/usergrant/repository/view/model" +) + +type UserGrantRepo struct { + SearchLimit uint64 + View *view.View + IamID string + Auth auth.Config + AuthZRepo *authz_repo.EsRepository +} + +func (repo *UserGrantRepo) SearchMyUserGrants(ctx context.Context, request *grant_model.UserGrantSearchRequest) (*grant_model.UserGrantSearchResponse, error) { + request.EnsureLimit(repo.SearchLimit) + request.Queries = append(request.Queries, &grant_model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_USER_ID, Method: global_model.SEARCHMETHOD_EQUALS, Value: auth.GetCtxData(ctx).UserID}) + grants, count, err := repo.View.SearchUserGrants(request) + if err != nil { + return nil, err + } + return &grant_model.UserGrantSearchResponse{ + Offset: request.Offset, + Limit: request.Limit, + TotalResult: uint64(count), + Result: model.UserGrantsToModel(grants), + }, nil +} + +func (repo *UserGrantRepo) SearchMyProjectOrgs(ctx context.Context, request *grant_model.UserGrantSearchRequest) (*grant_model.ProjectOrgSearchResponse, error) { + request.EnsureLimit(repo.SearchLimit) + ctxData := auth.GetCtxData(ctx) + if ctxData.ProjectID == "" { + return nil, caos_errs.ThrowPreconditionFailed(nil, "APP-7lqva", "Could not get ProjectID") + } + if ctxData.ProjectID == repo.AuthZRepo.IamProjectID { + isAdmin, err := repo.IsIamAdmin(ctx) + if err != nil { + return nil, err + } + if isAdmin { + return repo.SearchAdminOrgs(request) + } + } + request.Queries = append(request.Queries, &grant_model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_PROJECT_ID, Method: global_model.SEARCHMETHOD_EQUALS, Value: ctxData.ProjectID}) + + grants, err := repo.SearchMyUserGrants(ctx, request) + if err != nil { + return nil, err + } + return grantRespToOrgResp(grants), nil +} + +func (repo *UserGrantRepo) SearchMyZitadelPermissions(ctx context.Context) ([]string, error) { + grant, err := repo.AuthZRepo.ResolveGrants(ctx) + if err != nil { + return nil, err + } + permissions := &grant_model.Permissions{Permissions: []string{}} + for _, role := range grant.Roles { + roleName, ctxID := auth.SplitPermission(role) + for _, mapping := range repo.Auth.RolePermissionMappings { + if mapping.Role == roleName { + permissions.AppendPermissions(ctxID, mapping.Permissions...) + } + } + } + return permissions.Permissions, nil +} + +func (repo *UserGrantRepo) SearchAdminOrgs(request *grant_model.UserGrantSearchRequest) (*grant_model.ProjectOrgSearchResponse, error) { + searchRequest := &org_model.OrgSearchRequest{} + if len(request.Queries) > 0 { + for _, q := range request.Queries { + if q.Key == grant_model.USERGRANTSEARCHKEY_ORG_NAME { + searchRequest.Queries = append(searchRequest.Queries, &org_model.OrgSearchQuery{Key: org_model.ORGSEARCHKEY_ORG_NAME, Method: q.Method, Value: q.Value}) + } + } + } + orgs, count, err := repo.View.SearchOrgs(searchRequest) + if err != nil { + return nil, err + } + return orgRespToOrgResp(orgs, count), nil +} + +func (repo *UserGrantRepo) IsIamAdmin(ctx context.Context) (bool, error) { + grantSearch := &grant_model.UserGrantSearchRequest{ + Queries: []*grant_model.UserGrantSearchQuery{ + &grant_model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_RESOURCEOWNER, Method: global_model.SEARCHMETHOD_EQUALS, Value: repo.IamID}, + }} + result, err := repo.SearchMyUserGrants(ctx, grantSearch) + if err != nil { + return false, err + } + if result.TotalResult == 0 { + return false, nil + } + return true, nil +} + +func grantRespToOrgResp(grants *grant_model.UserGrantSearchResponse) *grant_model.ProjectOrgSearchResponse { + resp := &grant_model.ProjectOrgSearchResponse{ + TotalResult: grants.TotalResult, + } + resp.Result = make([]*grant_model.Org, len(grants.Result)) + for i, g := range grants.Result { + resp.Result[i] = &grant_model.Org{OrgID: g.ResourceOwner, OrgName: g.OrgName} + } + return resp +} + +func orgRespToOrgResp(orgs []*org_view.OrgView, count int) *grant_model.ProjectOrgSearchResponse { + resp := &grant_model.ProjectOrgSearchResponse{ + TotalResult: uint64(count), + } + resp.Result = make([]*grant_model.Org, len(orgs)) + for i, o := range orgs { + resp.Result[i] = &grant_model.Org{OrgID: o.ID, OrgName: o.Name} + } + return resp +} + +func mergeOrgAndAdminGrant(ctxData auth.CtxData, orgGrant, iamAdminGrant *model.UserGrantView) (grant *auth.Grant) { + if orgGrant != nil { + roles := orgGrant.RoleKeys + if iamAdminGrant != nil { + roles = addIamAdminRoles(roles, iamAdminGrant.RoleKeys) + } + grant = &auth.Grant{OrgID: orgGrant.ResourceOwner, Roles: roles} + } else if iamAdminGrant != nil { + grant = &auth.Grant{ + OrgID: ctxData.OrgID, + Roles: iamAdminGrant.RoleKeys, + } + } + return grant +} + +func addIamAdminRoles(orgRoles, iamAdminRoles []string) []string { + result := make([]string, 0) + result = append(result, iamAdminRoles...) + for _, role := range orgRoles { + if !auth.ExistsPerm(result, role) { + result = append(result, role) + } + } + return result +} diff --git a/internal/auth/repository/eventsourcing/eventstore/user_session.go b/internal/auth/repository/eventsourcing/eventstore/user_session.go new file mode 100644 index 0000000000..897d36fcd5 --- /dev/null +++ b/internal/auth/repository/eventsourcing/eventstore/user_session.go @@ -0,0 +1,21 @@ +package eventstore + +import ( + "context" + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" + usr_model "github.com/caos/zitadel/internal/user/model" + "github.com/caos/zitadel/internal/user/repository/view/model" +) + +type UserSessionRepo struct { + View *view.View +} + +func (repo *UserSessionRepo) GetMyUserSessions(ctx context.Context) ([]*usr_model.UserSessionView, error) { + userSessions, err := repo.View.UserSessionsByUserID(auth.GetCtxData(ctx).UserID) + if err != nil { + return nil, err + } + return model.UserSessionsToModel(userSessions), nil +} diff --git a/internal/auth/repository/eventsourcing/handler/application.go b/internal/auth/repository/eventsourcing/handler/application.go new file mode 100644 index 0000000000..43b7704340 --- /dev/null +++ b/internal/auth/repository/eventsourcing/handler/application.go @@ -0,0 +1,74 @@ +package handler + +import ( + "github.com/caos/logging" + "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/eventstore/spooler" + "github.com/caos/zitadel/internal/project/repository/eventsourcing" + proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + view_model "github.com/caos/zitadel/internal/project/repository/view/model" + "time" +) + +type Application struct { + handler + projectEvents *proj_event.ProjectEventstore +} + +const ( + applicationTable = "auth.applications" +) + +func (p *Application) MinimumCycleDuration() time.Duration { return p.cycleDuration } + +func (p *Application) ViewModel() string { + return applicationTable +} + +func (p *Application) EventQuery() (*models.SearchQuery, error) { + sequence, err := p.view.GetLatestApplicationSequence() + if err != nil { + return nil, err + } + return eventsourcing.ProjectQuery(sequence), nil +} + +func (p *Application) Process(event *models.Event) (err error) { + app := new(view_model.ApplicationView) + switch event.Type { + case es_model.ApplicationAdded: + app.AppendEvent(event) + case es_model.ApplicationChanged, + es_model.OIDCConfigAdded, + es_model.OIDCConfigChanged, + es_model.ApplicationDeactivated, + es_model.ApplicationReactivated: + err := app.SetData(event) + if err != nil { + return err + } + app, err = p.view.ApplicationByID(app.ID) + if err != nil { + return err + } + app.AppendEvent(event) + case es_model.ApplicationRemoved: + err := app.SetData(event) + if err != nil { + return err + } + return p.view.DeleteApplication(app.ID, event.Sequence) + default: + return p.view.ProcessedApplicationSequence(event.Sequence) + } + if err != nil { + return err + } + return p.view.PutApplication(app) +} + +func (p *Application) OnError(event *models.Event, spoolerError error) error { + logging.LogWithFields("SPOOL-ls9ew", "id", event.AggregateID).WithError(spoolerError).Warn("something went wrong in project app handler") + return spooler.HandleError(event, spoolerError, p.view.GetLatestApplicationFailedEvent, p.view.ProcessedApplicationFailedEvent, p.view.ProcessedApplicationSequence, p.errorCountUntilSkip) +} diff --git a/internal/auth/repository/eventsourcing/handler/handler.go b/internal/auth/repository/eventsourcing/handler/handler.go index 991bc97bd2..bf50a30dd6 100644 --- a/internal/auth/repository/eventsourcing/handler/handler.go +++ b/internal/auth/repository/eventsourcing/handler/handler.go @@ -1,9 +1,15 @@ package handler import ( + sd "github.com/caos/zitadel/internal/config/systemdefaults" + "github.com/caos/zitadel/internal/eventstore" + iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" + proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" "time" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" + "github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/eventstore/spooler" usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" ) @@ -11,7 +17,7 @@ import ( type Configs map[string]*Config type Config struct { - MinimumCycleDurationMillisecond int + MinimumCycleDuration types.Duration } type handler struct { @@ -22,14 +28,28 @@ type handler struct { } type EventstoreRepos struct { - UserEvents *usr_event.UserEventstore + UserEvents *usr_event.UserEventstore + ProjectEvents *proj_event.ProjectEventstore + OrgEvents *org_events.OrgEventstore + IamEvents *iam_events.IamEventstore } -func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, repos EventstoreRepos) []spooler.Handler { +func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, eventstore eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults) []spooler.Handler { return []spooler.Handler{ &User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount}}, &UserSession{handler: handler{view, bulkLimit, configs.cycleDuration("UserSession"), errorCount}, userEvents: repos.UserEvents}, &Token{handler: handler{view, bulkLimit, configs.cycleDuration("Token"), errorCount}}, + &Key{handler: handler{view, bulkLimit, configs.cycleDuration("Key"), errorCount}}, + &Application{handler: handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount}}, + &Org{handler: handler{view, bulkLimit, configs.cycleDuration("Org"), errorCount}}, + &UserGrant{ + handler: handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount}, + eventstore: eventstore, + userEvents: repos.UserEvents, + orgEvents: repos.OrgEvents, + projectEvents: repos.ProjectEvents, + iamEvents: repos.IamEvents, + iamID: systemDefaults.IamID}, } } @@ -38,5 +58,5 @@ func (configs Configs) cycleDuration(viewModel string) time.Duration { if !ok { return 1 * time.Second } - return time.Duration(c.MinimumCycleDurationMillisecond) * time.Millisecond + return c.MinimumCycleDuration.Duration } diff --git a/internal/auth/repository/eventsourcing/handler/key.go b/internal/auth/repository/eventsourcing/handler/key.go new file mode 100644 index 0000000000..46824e8438 --- /dev/null +++ b/internal/auth/repository/eventsourcing/handler/key.go @@ -0,0 +1,55 @@ +package handler + +import ( + "time" + + es_model "github.com/caos/zitadel/internal/key/repository/eventsourcing/model" + + "github.com/caos/logging" + + "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/eventstore/spooler" + "github.com/caos/zitadel/internal/key/repository/eventsourcing" + view_model "github.com/caos/zitadel/internal/key/repository/view/model" +) + +type Key struct { + handler +} + +const ( + keyTable = "auth.keys" +) + +func (k *Key) MinimumCycleDuration() time.Duration { return k.cycleDuration } + +func (k *Key) ViewModel() string { + return keyTable +} + +func (k *Key) EventQuery() (*models.SearchQuery, error) { + sequence, err := k.view.GetLatestKeySequence() + if err != nil { + return nil, err + } + return eventsourcing.KeyPairQuery(sequence), nil +} + +func (k *Key) Process(event *models.Event) error { + switch event.Type { + case es_model.KeyPairAdded: + privateKey, publicKey, err := view_model.KeysFromPairEvent(event) + if err != nil { + return err + } + return k.view.PutKeys(privateKey, publicKey, event.Sequence) + default: + return k.view.ProcessedKeySequence(event.Sequence) + } + return nil +} + +func (k *Key) OnError(event *models.Event, err error) error { + logging.LogWithFields("SPOOL-GHa3a", "id", event.AggregateID).WithError(err).Warn("something went wrong in key handler") + return spooler.HandleError(event, err, k.view.GetLatestKeyFailedEvent, k.view.ProcessedKeyFailedEvent, k.view.ProcessedKeySequence, k.errorCountUntilSkip) +} diff --git a/internal/auth/repository/eventsourcing/handler/org.go b/internal/auth/repository/eventsourcing/handler/org.go new file mode 100644 index 0000000000..b5b9df0fb6 --- /dev/null +++ b/internal/auth/repository/eventsourcing/handler/org.go @@ -0,0 +1,64 @@ +package handler + +import ( + "github.com/caos/logging" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/eventstore/spooler" + "github.com/caos/zitadel/internal/org/repository/eventsourcing" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + "github.com/caos/zitadel/internal/org/repository/view" + "time" +) + +type Org struct { + handler +} + +const ( + orgTable = "auth.orgs" +) + +func (o *Org) MinimumCycleDuration() time.Duration { return o.cycleDuration } + +func (o *Org) ViewModel() string { + return orgTable +} + +func (o *Org) EventQuery() (*es_models.SearchQuery, error) { + sequence, err := o.view.GetLatestOrgSequence() + if err != nil { + return nil, err + } + return eventsourcing.OrgQuery(sequence), nil +} + +func (o *Org) Process(event *es_models.Event) error { + org := new(view.OrgView) + + switch event.Type { + case model.OrgAdded: + org.AppendEvent(event) + case model.OrgChanged: + err := org.SetData(event) + if err != nil { + return err + } + org, err = o.view.OrgByID(org.ID) + if err != nil { + return err + } + err = org.AppendEvent(event) + if err != nil { + return err + } + default: + return o.view.ProcessedOrgSequence(event.Sequence) + } + + return o.view.PutOrg(org) +} + +func (o *Org) OnError(event *es_models.Event, spoolerErr error) error { + logging.LogWithFields("SPOOL-8siWS", "id", event.AggregateID).WithError(spoolerErr).Warn("something went wrong in org handler") + return spooler.HandleError(event, spoolerErr, o.view.GetLatestOrgFailedEvent, o.view.ProcessedOrgFailedEvent, o.view.ProcessedOrgSequence, o.errorCountUntilSkip) +} diff --git a/internal/auth/repository/eventsourcing/handler/user.go b/internal/auth/repository/eventsourcing/handler/user.go index aca0ab265e..8dc50d47d9 100644 --- a/internal/auth/repository/eventsourcing/handler/user.go +++ b/internal/auth/repository/eventsourcing/handler/user.go @@ -54,7 +54,9 @@ func (p *User) Process(event *models.Event) (err error) { es_model.UserUnlocked, es_model.MfaOtpAdded, es_model.MfaOtpVerified, - es_model.MfaOtpRemoved: + es_model.MfaOtpRemoved, + es_model.MfaInitSkipped, + es_model.UserPasswordChanged: user, err = p.view.UserByID(event.AggregateID) if err != nil { return err diff --git a/internal/auth/repository/eventsourcing/handler/user_grant.go b/internal/auth/repository/eventsourcing/handler/user_grant.go new file mode 100644 index 0000000000..9878c2392a --- /dev/null +++ b/internal/auth/repository/eventsourcing/handler/user_grant.go @@ -0,0 +1,344 @@ +package handler + +import ( + "context" + "github.com/caos/logging" + "github.com/caos/zitadel/internal/errors" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/eventstore/spooler" + iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + org_model "github.com/caos/zitadel/internal/org/model" + org_events "github.com/caos/zitadel/internal/org/repository/eventsourcing" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + proj_model "github.com/caos/zitadel/internal/project/model" + proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + usr_model "github.com/caos/zitadel/internal/user/model" + usr_events "github.com/caos/zitadel/internal/user/repository/eventsourcing" + usr_es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" + grant_es_model "github.com/caos/zitadel/internal/usergrant/repository/eventsourcing/model" + view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model" + "strings" + "time" +) + +type UserGrant struct { + handler + eventstore eventstore.Eventstore + projectEvents *proj_event.ProjectEventstore + userEvents *usr_events.UserEventstore + orgEvents *org_events.OrgEventstore + iamEvents *iam_events.IamEventstore + iamID string + iamProjectID string +} + +const ( + userGrantTable = "auth.user_grants" +) + +func (u *UserGrant) MinimumCycleDuration() time.Duration { return u.cycleDuration } + +func (u *UserGrant) ViewModel() string { + return userGrantTable +} + +func (u *UserGrant) EventQuery() (*models.SearchQuery, error) { + if u.iamProjectID == "" { + err := u.setIamProjectID() + if err != nil { + return nil, err + } + } + sequence, err := u.view.GetLatestUserGrantSequence() + if err != nil { + return nil, err + } + return es_models.NewSearchQuery(). + AggregateTypeFilter(grant_es_model.UserGrantAggregate, iam_es_model.IamAggregate, org_es_model.OrgAggregate, usr_es_model.UserAggregate, proj_es_model.ProjectAggregate). + LatestSequenceFilter(sequence), nil +} + +func (u *UserGrant) Process(event *models.Event) (err error) { + switch event.AggregateType { + case grant_es_model.UserGrantAggregate: + err = u.processUserGrant(event) + case usr_es_model.UserAggregate: + err = u.processUser(event) + case proj_es_model.ProjectAggregate: + err = u.processProject(event) + case iam_es_model.IamAggregate: + err = u.processIamMember(event, "IAM", false) + case org_es_model.OrgAggregate: + return u.processOrg(event) + } + return err +} + +func (u *UserGrant) processUserGrant(event *models.Event) (err error) { + grant := new(view_model.UserGrantView) + switch event.Type { + case grant_es_model.UserGrantAdded: + err = grant.AppendEvent(event) + if err != nil { + return err + } + err = u.fillData(grant, event.ResourceOwner) + case grant_es_model.UserGrantChanged, + grant_es_model.UserGrantDeactivated, + grant_es_model.UserGrantReactivated: + grant, err = u.view.UserGrantByID(event.AggregateID) + if err != nil { + return err + } + err = grant.AppendEvent(event) + case grant_es_model.UserGrantRemoved: + err = u.view.DeleteUserGrant(event.AggregateID, event.Sequence) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } + if err != nil { + return err + } + return u.view.PutUserGrant(grant, grant.Sequence) +} + +func (u *UserGrant) processUser(event *models.Event) (err error) { + switch event.Type { + case usr_es_model.UserProfileChanged, + usr_es_model.UserEmailChanged: + grants, err := u.view.UserGrantsByUserID(event.AggregateID) + if err != nil { + return err + } + user, err := u.userEvents.UserByID(context.Background(), event.AggregateID) + if err != nil { + return err + } + for _, grant := range grants { + u.fillUserData(grant, user) + err = u.view.PutUserGrant(grant, event.Sequence) + if err != nil { + return err + } + } + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } + return nil +} + +func (u *UserGrant) processProject(event *models.Event) (err error) { + switch event.Type { + case proj_es_model.ProjectChanged: + grants, err := u.view.UserGrantsByProjectID(event.AggregateID) + if err != nil { + return err + } + project, err := u.projectEvents.ProjectByID(context.Background(), event.AggregateID) + if err != nil { + return err + } + for _, grant := range grants { + u.fillProjectData(grant, project) + return u.view.PutUserGrant(grant, event.Sequence) + } + case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectMemberRemoved: + member := new(proj_es_model.ProjectMember) + member.SetData(event) + return u.processMember(event, "PROJECT", true, member.UserID, member.Roles) + case proj_es_model.ProjectGrantMemberAdded, proj_es_model.ProjectGrantMemberChanged, proj_es_model.ProjectGrantMemberRemoved: + member := new(proj_es_model.ProjectGrantMember) + member.SetData(event) + return u.processMember(event, "PROJECT_GRANT", true, member.UserID, member.Roles) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } + return nil +} + +func (u *UserGrant) processOrg(event *models.Event) (err error) { + switch event.Type { + case org_es_model.OrgMemberAdded, org_es_model.OrgMemberChanged, org_es_model.OrgMemberRemoved: + member := new(org_es_model.OrgMember) + member.SetData(event) + return u.processMember(event, "ORG", false, member.UserID, member.Roles) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } + return nil +} + +func (u *UserGrant) processIamMember(event *models.Event, rolePrefix string, suffix bool) error { + member := new(iam_es_model.IamMember) + + switch event.Type { + case iam_es_model.IamMemberAdded, iam_es_model.IamMemberChanged: + member.SetData(event) + + grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID) + if err != nil && !errors.IsNotFound(err) { + return err + } + if errors.IsNotFound(err) { + grant = &view_model.UserGrantView{ + ID: u.iamProjectID + member.UserID, + ResourceOwner: u.iamID, + OrgName: u.iamID, + OrgDomain: u.iamID, + ProjectID: u.iamProjectID, + UserID: member.UserID, + RoleKeys: member.Roles, + CreationDate: event.CreationDate, + } + if suffix { + grant.RoleKeys = suffixRoles(event.AggregateID, grant.RoleKeys) + } + } else { + newRoles := member.Roles + if grant.RoleKeys != nil { + grant.RoleKeys = mergeExistingRoles(rolePrefix, grant.RoleKeys, newRoles) + } else { + grant.RoleKeys = newRoles + } + + } + grant.Sequence = event.Sequence + grant.ChangeDate = event.CreationDate + return u.view.PutUserGrant(grant, grant.Sequence) + case iam_es_model.IamMemberRemoved: + member.SetData(event) + grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID) + if err != nil { + return err + } + return u.view.DeleteUserGrant(grant.ID, event.Sequence) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } +} + +func (u *UserGrant) processMember(event *models.Event, rolePrefix string, suffix bool, userID string, roleKeys []string) error { + switch event.Type { + case org_es_model.OrgMemberAdded, proj_es_model.ProjectMemberAdded, proj_es_model.ProjectGrantMemberAdded, + org_es_model.OrgMemberChanged, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectGrantMemberChanged: + + grant, err := u.view.UserGrantByIDs(event.ResourceOwner, u.iamProjectID, userID) + if err != nil && !errors.IsNotFound(err) { + return err + } + if suffix { + roleKeys = suffixRoles(event.AggregateID, roleKeys) + } + if errors.IsNotFound(err) { + grant = &view_model.UserGrantView{ + ID: u.iamProjectID + event.ResourceOwner + userID, + ResourceOwner: event.ResourceOwner, + ProjectID: u.iamProjectID, + UserID: userID, + RoleKeys: roleKeys, + CreationDate: event.CreationDate, + } + u.fillData(grant, event.ResourceOwner) + } else { + newRoles := roleKeys + if grant.RoleKeys != nil { + grant.RoleKeys = mergeExistingRoles(rolePrefix, grant.RoleKeys, newRoles) + } else { + grant.RoleKeys = newRoles + } + } + grant.Sequence = event.Sequence + grant.ChangeDate = event.CreationDate + return u.view.PutUserGrant(grant, event.Sequence) + case org_es_model.OrgMemberRemoved, + proj_es_model.ProjectMemberRemoved, + proj_es_model.ProjectGrantMemberRemoved: + + grant, err := u.view.UserGrantByIDs(event.ResourceOwner, u.iamProjectID, userID) + if err != nil { + return err + } + return u.view.DeleteUserGrant(grant.ID, event.Sequence) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } +} + +func suffixRoles(suffix string, roles []string) []string { + suffixedRoles := make([]string, len(roles)) + for i := 0; i < len(roles); i++ { + suffixedRoles[i] = roles[i] + ":" + suffix + } + return suffixedRoles +} + +func mergeExistingRoles(rolePrefix string, existingRoles, newRoles []string) []string { + mergedRoles := make([]string, 0) + for _, existing := range existingRoles { + if !strings.HasPrefix(existing, rolePrefix) { + mergedRoles = append(mergedRoles, existing) + } + } + return append(mergedRoles, newRoles...) +} + +func (u *UserGrant) setIamProjectID() error { + if u.iamProjectID != "" { + return nil + } + iam, err := u.iamEvents.IamByID(context.Background(), u.iamID) + if err != nil { + return err + } + if !iam.SetUpDone { + return caos_errs.ThrowPreconditionFailed(nil, "HANDL-s5DTs", "Setup not done") + } + u.iamProjectID = iam.IamProjectID + return nil +} + +func (u *UserGrant) fillData(grant *view_model.UserGrantView, resourceOwner string) (err error) { + user, err := u.userEvents.UserByID(context.Background(), grant.UserID) + if err != nil { + return err + } + u.fillUserData(grant, user) + project, err := u.projectEvents.ProjectByID(context.Background(), grant.ProjectID) + if err != nil { + return err + } + u.fillProjectData(grant, project) + + org, err := u.orgEvents.OrgByID(context.TODO(), org_model.NewOrg(resourceOwner)) + if err != nil { + return err + } + u.fillOrgData(grant, org) + return nil +} + +func (u *UserGrant) fillUserData(grant *view_model.UserGrantView, user *usr_model.User) { + grant.UserName = user.UserName + grant.FirstName = user.FirstName + grant.LastName = user.LastName + grant.Email = user.EmailAddress +} + +func (u *UserGrant) fillProjectData(grant *view_model.UserGrantView, project *proj_model.Project) { + grant.ProjectName = project.Name +} + +func (u *UserGrant) fillOrgData(grant *view_model.UserGrantView, org *org_model.Org) { + grant.OrgDomain = org.Domain + grant.OrgName = org.Name +} + +func (u *UserGrant) OnError(event *models.Event, err error) error { + logging.LogWithFields("SPOOL-8is4s", "id", event.AggregateID).WithError(err).Warn("something went wrong in user handler") + return spooler.HandleError(event, err, u.view.GetLatestUserGrantFailedEvent, u.view.ProcessedUserGrantFailedEvent, u.view.ProcessedUserGrantSequence, u.errorCountUntilSkip) +} diff --git a/internal/auth/repository/eventsourcing/handler/user_session.go b/internal/auth/repository/eventsourcing/handler/user_session.go index 7581e66365..1c4e698eae 100644 --- a/internal/auth/repository/eventsourcing/handler/user_session.go +++ b/internal/auth/repository/eventsourcing/handler/user_session.go @@ -45,10 +45,8 @@ func (u *UserSession) Process(event *models.Event) (err error) { switch event.Type { case es_model.UserPasswordCheckSucceeded, es_model.UserPasswordCheckFailed, - es_model.UserPasswordChanged, es_model.MfaOtpCheckSucceeded, - es_model.MfaOtpCheckFailed, - es_model.MfaOtpRemoved: + es_model.MfaOtpCheckFailed: eventData, err := view_model.UserSessionFromEvent(event) if err != nil { return err @@ -66,14 +64,22 @@ func (u *UserSession) Process(event *models.Event) (err error) { State: int32(req_model.UserSessionStateActive), } } - session.AppendEvent(event) + return u.updateSession(session, event) + case es_model.UserPasswordChanged, + es_model.MfaOtpRemoved: + sessions, err := u.view.UserSessionsByUserID(event.AggregateID) + if err != nil { + return err + } + for _, session := range sessions { + if err := u.updateSession(session, event); err != nil { + return err + } + } + return nil default: return u.view.ProcessedUserSessionSequence(event.Sequence) } - if err := u.FillUserInfo(session, event.AggregateID); err != nil { - return err - } - return u.view.PutUserSession(session) } func (u *UserSession) OnError(event *models.Event, err error) error { @@ -81,7 +87,18 @@ func (u *UserSession) OnError(event *models.Event, err error) error { return spooler.HandleError(event, err, u.view.GetLatestUserSessionFailedEvent, u.view.ProcessedUserSessionFailedEvent, u.view.ProcessedUserSessionSequence, u.errorCountUntilSkip) } -func (u *UserSession) FillUserInfo(session *view_model.UserSessionView, id string) error { +func (u *UserSession) updateSession(session *view_model.UserSessionView, event *models.Event) error { + session.Sequence = event.Sequence + session.AppendEvent(event) + if session.UserName == "" { + if err := u.fillUserInfo(session, event.AggregateID); err != nil { + return err + } + } + return u.view.PutUserSession(session) +} + +func (u *UserSession) fillUserInfo(session *view_model.UserSessionView, id string) error { user, err := u.userEvents.UserByID(context.Background(), id) if err != nil { return err diff --git a/internal/auth/repository/eventsourcing/repository.go b/internal/auth/repository/eventsourcing/repository.go index c988f492db..d1088d9398 100644 --- a/internal/auth/repository/eventsourcing/repository.go +++ b/internal/auth/repository/eventsourcing/repository.go @@ -2,6 +2,10 @@ package eventsourcing import ( "context" + "github.com/caos/zitadel/internal/api/auth" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" + es_iam "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + es_org "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/eventstore" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/handler" @@ -10,18 +14,23 @@ import ( "github.com/caos/zitadel/internal/auth_request/repository/cache" sd "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/config/types" + "github.com/caos/zitadel/internal/crypto" es_int "github.com/caos/zitadel/internal/eventstore" es_spol "github.com/caos/zitadel/internal/eventstore/spooler" "github.com/caos/zitadel/internal/id" + es_key "github.com/caos/zitadel/internal/key/repository/eventsourcing" es_policy "github.com/caos/zitadel/internal/policy/repository/eventsourcing" + es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing" es_user "github.com/caos/zitadel/internal/user/repository/eventsourcing" ) type Config struct { + SearchLimit uint64 Eventstore es_int.Config AuthRequest cache.Config View types.SQL Spooler spooler.SpoolerConfig + KeyConfig es_key.KeyConfig } type EsRepository struct { @@ -29,9 +38,15 @@ type EsRepository struct { eventstore.UserRepo eventstore.AuthRequestRepo eventstore.TokenRepo + eventstore.KeyRepository + eventstore.ApplicationRepo + eventstore.UserSessionRepo + eventstore.UserGrantRepo + eventstore.OrgRepository + eventstore.IamRepository } -func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) { +func Start(conf Config, authZ auth.Config, systemDefaults sd.SystemDefaults, authZRepo *authz_repo.EsRepository) (*EsRepository, error) { es, err := es_int.Start(conf.Eventstore) if err != nil { return nil, err @@ -41,7 +56,14 @@ func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) if err != nil { return nil, err } - view, err := auth_view.StartView(sqlClient) + + keyAlgorithm, err := crypto.NewAESCrypto(conf.KeyConfig.EncryptionConfig) + if err != nil { + return nil, err + } + idGenerator := id.SonyFlakeGenerator + + view, err := auth_view.StartView(sqlClient, keyAlgorithm, idGenerator) if err != nil { return nil, err } @@ -70,8 +92,35 @@ func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) return nil, err } - repos := handler.EventstoreRepos{UserEvents: user} - spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, repos) + key, err := es_key.StartKey(es, conf.KeyConfig, keyAlgorithm, idGenerator) + if err != nil { + return nil, err + } + + project, err := es_proj.StartProject( + es_proj.ProjectConfig{ + Cache: conf.Eventstore.Cache, + Eventstore: es, + }, + systemDefaults, + ) + if err != nil { + return nil, err + } + iam, err := es_iam.StartIam( + es_iam.IamConfig{ + Eventstore: es, + Cache: conf.Eventstore.Cache, + }, + systemDefaults, + ) + if err != nil { + return nil, err + } + org := es_org.StartOrg(es_org.OrgConfig{Eventstore: es}) + + repos := handler.EventstoreRepos{UserEvents: user, ProjectEvents: project, OrgEvents: org, IamEvents: iam} + spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, repos, systemDefaults) return &EsRepository{ spool, @@ -86,13 +135,41 @@ func Start(conf Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) View: view, UserSessionViewProvider: view, UserViewProvider: view, - IdGenerator: id.SonyFlakeGenerator, + UserEventProvider: user, + IdGenerator: idGenerator, PasswordCheckLifeTime: systemDefaults.VerificationLifetimes.PasswordCheck.Duration, MfaInitSkippedLifeTime: systemDefaults.VerificationLifetimes.MfaInitSkip.Duration, MfaSoftwareCheckLifeTime: systemDefaults.VerificationLifetimes.MfaSoftwareCheck.Duration, MfaHardwareCheckLifeTime: systemDefaults.VerificationLifetimes.MfaHardwareCheck.Duration, }, eventstore.TokenRepo{View: view}, + eventstore.KeyRepository{ + KeyEvents: key, + View: view, + SigningKeyRotation: conf.KeyConfig.SigningKeyRotation.Duration, + }, + eventstore.ApplicationRepo{ + View: view, + ProjectEvents: project, + }, + eventstore.UserSessionRepo{ + View: view, + }, + eventstore.UserGrantRepo{ + SearchLimit: conf.SearchLimit, + View: view, + IamID: systemDefaults.IamID, + Auth: authZ, + AuthZRepo: authZRepo, + }, + eventstore.OrgRepository{ + SearchLimit: conf.SearchLimit, + View: view, + }, + eventstore.IamRepository{ + IamEvents: iam, + IamID: systemDefaults.IamID, + }, }, nil } diff --git a/internal/auth/repository/eventsourcing/spooler/spooler.go b/internal/auth/repository/eventsourcing/spooler/spooler.go index 913b96237c..9d5c323a75 100644 --- a/internal/auth/repository/eventsourcing/spooler/spooler.go +++ b/internal/auth/repository/eventsourcing/spooler/spooler.go @@ -2,6 +2,7 @@ package spooler import ( "database/sql" + sd "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/handler" "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" @@ -17,12 +18,12 @@ type SpoolerConfig struct { Handlers handler.Configs } -func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, repos handler.EventstoreRepos) *spooler.Spooler { +func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, repos handler.EventstoreRepos, systemDefaults sd.SystemDefaults) *spooler.Spooler { spoolerConfig := spooler.Config{ Eventstore: es, Locker: &locker{dbClient: sql}, ConcurrentTasks: c.ConcurrentTasks, - ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, repos), + ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, repos, systemDefaults), } spool := spoolerConfig.New() spool.Start() diff --git a/internal/auth/repository/eventsourcing/view/application.go b/internal/auth/repository/eventsourcing/view/application.go new file mode 100644 index 0000000000..60b7f89570 --- /dev/null +++ b/internal/auth/repository/eventsourcing/view/application.go @@ -0,0 +1,105 @@ +package view + +import ( + "context" + + "github.com/caos/zitadel/internal/errors" + global_model "github.com/caos/zitadel/internal/model" + proj_model "github.com/caos/zitadel/internal/project/model" + "github.com/caos/zitadel/internal/project/repository/view" + "github.com/caos/zitadel/internal/project/repository/view/model" + global_view "github.com/caos/zitadel/internal/view" +) + +const ( + applicationTable = "auth.applications" +) + +func (v *View) ApplicationByID(appID string) (*model.ApplicationView, error) { + return view.ApplicationByID(v.Db, applicationTable, appID) +} + +func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest) ([]*model.ApplicationView, int, error) { + return view.SearchApplications(v.Db, applicationTable, request) +} + +func (v *View) PutApplication(project *model.ApplicationView) error { + err := view.PutApplication(v.Db, applicationTable, project) + if err != nil { + return err + } + return v.ProcessedApplicationSequence(project.Sequence) +} + +func (v *View) DeleteApplication(appID string, eventSequence uint64) error { + err := view.DeleteApplication(v.Db, applicationTable, appID) + if err != nil { + return nil + } + return v.ProcessedApplicationSequence(eventSequence) +} + +func (v *View) GetLatestApplicationSequence() (uint64, error) { + return v.latestSequence(applicationTable) +} + +func (v *View) ProcessedApplicationSequence(eventSequence uint64) error { + return v.saveCurrentSequence(applicationTable, eventSequence) +} + +func (v *View) GetLatestApplicationFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { + return v.latestFailedEvent(applicationTable, sequence) +} + +func (v *View) ProcessedApplicationFailedEvent(failedEvent *global_view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} + +func (v *View) ApplicationByClientID(_ context.Context, clientID string) (*model.ApplicationView, error) { + req := &proj_model.ApplicationSearchRequest{ + Limit: 1, + Queries: []*proj_model.ApplicationSearchQuery{ + { + Key: proj_model.APPLICATIONSEARCHKEY_OIDC_CLIENT_ID, + Method: global_model.SEARCHMETHOD_EQUALS, + Value: clientID, + }, + }, + } + apps, count, err := view.SearchApplications(v.Db, applicationTable, req) + if err != nil { + return nil, errors.ThrowPreconditionFailed(err, "VIEW-sd6JQ", "cannot find client") + } + if count != 1 { + return nil, errors.ThrowPreconditionFailed(nil, "VIEW-dfw3as", "cannot find client") + } + return apps[0], nil +} + +func (v *View) AppIDsFromProjectByClientID(ctx context.Context, clientID string) ([]string, error) { + app, err := v.ApplicationByClientID(ctx, clientID) + if err != nil { + return nil, err + } + req := &proj_model.ApplicationSearchRequest{ + Queries: []*proj_model.ApplicationSearchQuery{ + { + Key: proj_model.APPLICATIONSEARCHKEY_PROJECT_ID, + Method: global_model.SEARCHMETHOD_EQUALS, + Value: app.ProjectID, + }, + }, + } + apps, _, err := view.SearchApplications(v.Db, applicationTable, req) + if err != nil { + return nil, errors.ThrowPreconditionFailed(err, "VIEW-Gd24q", "cannot find applications") + } + ids := make([]string, 0, len(apps)) + for _, app := range apps { + if !app.IsOIDC { + continue + } + ids = append(ids, app.OIDCClientID) + } + return ids, nil +} diff --git a/internal/auth/repository/eventsourcing/view/key.go b/internal/auth/repository/eventsourcing/view/key.go new file mode 100644 index 0000000000..a5b07ff62a --- /dev/null +++ b/internal/auth/repository/eventsourcing/view/key.go @@ -0,0 +1,72 @@ +package view + +import ( + key_model "github.com/caos/zitadel/internal/key/model" + "github.com/caos/zitadel/internal/key/repository/view" + "github.com/caos/zitadel/internal/key/repository/view/model" + global_view "github.com/caos/zitadel/internal/view" +) + +const ( + keyTable = "auth.keys" +) + +func (v *View) KeyByIDAndType(keyID string, private bool) (*model.KeyView, error) { + return view.KeyByIDAndType(v.Db, keyTable, keyID, private) +} + +func (v *View) GetSigningKey() (*key_model.SigningKey, error) { + key, err := view.GetSigningKey(v.Db, keyTable) + if err != nil { + return nil, err + } + return key_model.SigningKeyFromKeyView(model.KeyViewToModel(key), v.keyAlgorithm) +} + +func (v *View) GetActiveKeySet() ([]*key_model.PublicKey, error) { + keys, err := view.GetActivePublicKeys(v.Db, keyTable) + if err != nil { + return nil, err + } + return key_model.PublicKeysFromKeyView(model.KeyViewsToModel(keys), v.keyAlgorithm) +} + +func (v *View) PutKeys(privateKey, publicKey *model.KeyView, eventSequence uint64) error { + err := view.PutKeys(v.Db, keyTable, privateKey, publicKey) + if err != nil { + return err + } + return v.ProcessedKeySequence(eventSequence) +} + +func (v *View) DeleteKey(keyID string, private bool, eventSequence uint64) error { + err := view.DeleteKey(v.Db, keyTable, keyID, private) + if err != nil { + return nil + } + return v.ProcessedKeySequence(eventSequence) +} + +func (v *View) DeleteKeyPair(keyID string, eventSequence uint64) error { + err := view.DeleteKeyPair(v.Db, keyTable, keyID) + if err != nil { + return nil + } + return v.ProcessedKeySequence(eventSequence) +} + +func (v *View) GetLatestKeySequence() (uint64, error) { + return v.latestSequence(keyTable) +} + +func (v *View) ProcessedKeySequence(eventSequence uint64) error { + return v.saveCurrentSequence(keyTable, eventSequence) +} + +func (v *View) GetLatestKeyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { + return v.latestFailedEvent(keyTable, sequence) +} + +func (v *View) ProcessedKeyFailedEvent(failedEvent *global_view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} diff --git a/internal/auth/repository/eventsourcing/view/org.go b/internal/auth/repository/eventsourcing/view/org.go new file mode 100644 index 0000000000..e7d7488760 --- /dev/null +++ b/internal/auth/repository/eventsourcing/view/org.go @@ -0,0 +1,43 @@ +package view + +import ( + "github.com/caos/zitadel/internal/org/model" + org_view "github.com/caos/zitadel/internal/org/repository/view" + "github.com/caos/zitadel/internal/view" +) + +const ( + orgTable = "auth.orgs" +) + +func (v *View) OrgByID(orgID string) (*org_view.OrgView, error) { + return org_view.OrgByID(v.Db, orgTable, orgID) +} + +func (v *View) SearchOrgs(req *model.OrgSearchRequest) ([]*org_view.OrgView, int, error) { + return org_view.SearchOrgs(v.Db, orgTable, req) +} + +func (v *View) PutOrg(org *org_view.OrgView) error { + err := org_view.PutOrg(v.Db, orgTable, org) + if err != nil { + return err + } + return v.ProcessedOrgSequence(org.Sequence) +} + +func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*view.FailedEvent, error) { + return v.latestFailedEvent(orgTable, sequence) +} + +func (v *View) ProcessedOrgFailedEvent(failedEvent *view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} + +func (v *View) GetLatestOrgSequence() (uint64, error) { + return v.latestSequence(orgTable) +} + +func (v *View) ProcessedOrgSequence(eventSequence uint64) error { + return v.saveCurrentSequence(orgTable, eventSequence) +} diff --git a/internal/auth/repository/eventsourcing/view/token.go b/internal/auth/repository/eventsourcing/view/token.go index adae0900e1..36602d4c98 100644 --- a/internal/auth/repository/eventsourcing/view/token.go +++ b/internal/auth/repository/eventsourcing/view/token.go @@ -20,17 +20,23 @@ func (v *View) IsTokenValid(tokenID string) (bool, error) { return view.IsTokenValid(v.Db, tokenTable, tokenID) } -func (v *View) CreateToken(agentID, applicationID, userID string, lifetime time.Duration) (*model.Token, error) { +func (v *View) CreateToken(agentID, applicationID, userID string, audience, scopes []string, lifetime time.Duration) (*model.Token, error) { + id, err := v.idGenerator.Next() + if err != nil { + return nil, err + } now := time.Now().UTC() token := &model.Token{ + ID: id, CreationDate: now, UserID: userID, ApplicationID: applicationID, UserAgentID: agentID, + Scopes: scopes, + Audience: audience, Expiration: now.Add(lifetime), } - err := view.PutToken(v.Db, tokenTable, token) - if err != nil { + if err := view.PutToken(v.Db, tokenTable, token); err != nil { return nil, err } return token, nil diff --git a/internal/auth/repository/eventsourcing/view/user_grant.go b/internal/auth/repository/eventsourcing/view/user_grant.go new file mode 100644 index 0000000000..d4f8dd1573 --- /dev/null +++ b/internal/auth/repository/eventsourcing/view/user_grant.go @@ -0,0 +1,64 @@ +package view + +import ( + grant_model "github.com/caos/zitadel/internal/usergrant/model" + "github.com/caos/zitadel/internal/usergrant/repository/view" + "github.com/caos/zitadel/internal/usergrant/repository/view/model" + global_view "github.com/caos/zitadel/internal/view" +) + +const ( + userGrantTable = "auth.user_grants" +) + +func (v *View) UserGrantByID(grantID string) (*model.UserGrantView, error) { + return view.UserGrantByID(v.Db, userGrantTable, grantID) +} + +func (v *View) UserGrantByIDs(resourceOwnerID, projectID, userID string) (*model.UserGrantView, error) { + return view.UserGrantByIDs(v.Db, userGrantTable, resourceOwnerID, projectID, userID) +} + +func (v *View) UserGrantsByUserID(userID string) ([]*model.UserGrantView, error) { + return view.UserGrantsByUserID(v.Db, userGrantTable, userID) +} + +func (v *View) UserGrantsByProjectID(projectID string) ([]*model.UserGrantView, error) { + return view.UserGrantsByProjectID(v.Db, userGrantTable, projectID) +} + +func (v *View) SearchUserGrants(request *grant_model.UserGrantSearchRequest) ([]*model.UserGrantView, int, error) { + return view.SearchUserGrants(v.Db, userGrantTable, request) +} + +func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64) error { + err := view.PutUserGrant(v.Db, userGrantTable, grant) + if err != nil { + return err + } + return v.ProcessedUserGrantSequence(sequence) +} + +func (v *View) DeleteUserGrant(grantID string, eventSequence uint64) error { + err := view.DeleteUserGrant(v.Db, userGrantTable, grantID) + if err != nil { + return nil + } + return v.ProcessedUserGrantSequence(eventSequence) +} + +func (v *View) GetLatestUserGrantSequence() (uint64, error) { + return v.latestSequence(userGrantTable) +} + +func (v *View) ProcessedUserGrantSequence(eventSequence uint64) error { + return v.saveCurrentSequence(userGrantTable, eventSequence) +} + +func (v *View) GetLatestUserGrantFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { + return v.latestFailedEvent(userGrantTable, sequence) +} + +func (v *View) ProcessedUserGrantFailedEvent(failedEvent *global_view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} diff --git a/internal/auth/repository/eventsourcing/view/user_session.go b/internal/auth/repository/eventsourcing/view/user_session.go index dbbd2d83c6..6882c68464 100644 --- a/internal/auth/repository/eventsourcing/view/user_session.go +++ b/internal/auth/repository/eventsourcing/view/user_session.go @@ -10,14 +10,14 @@ const ( userSessionTable = "auth.user_sessions" ) -func (v *View) UserSessionByID(sessionID string) (*model.UserSessionView, error) { - return view.UserSessionByID(v.Db, userSessionTable, sessionID) -} - func (v *View) UserSessionByIDs(agentID, userID string) (*model.UserSessionView, error) { return view.UserSessionByIDs(v.Db, userSessionTable, agentID, userID) } +func (v *View) UserSessionsByUserID(userID string) ([]*model.UserSessionView, error) { + return view.UserSessionsByUserID(v.Db, userSessionTable, userID) +} + func (v *View) UserSessionsByAgentID(agentID string) ([]*model.UserSessionView, error) { return view.UserSessionsByAgentID(v.Db, userSessionTable, agentID) } diff --git a/internal/auth/repository/eventsourcing/view/view.go b/internal/auth/repository/eventsourcing/view/view.go index 4b8c52392d..fc33fccddf 100644 --- a/internal/auth/repository/eventsourcing/view/view.go +++ b/internal/auth/repository/eventsourcing/view/view.go @@ -4,19 +4,26 @@ import ( "database/sql" "github.com/jinzhu/gorm" + + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/id" ) type View struct { - Db *gorm.DB + Db *gorm.DB + keyAlgorithm crypto.EncryptionAlgorithm + idGenerator id.Generator } -func StartView(sqlClient *sql.DB) (*View, error) { +func StartView(sqlClient *sql.DB, keyAlgorithm crypto.EncryptionAlgorithm, idGenerator id.Generator) (*View, error) { gorm, err := gorm.Open("postgres", sqlClient) if err != nil { return nil, err } return &View{ - Db: gorm, + Db: gorm, + keyAlgorithm: keyAlgorithm, + idGenerator: idGenerator, }, nil } diff --git a/internal/auth/repository/iam.go b/internal/auth/repository/iam.go new file mode 100644 index 0000000000..3e17aa0971 --- /dev/null +++ b/internal/auth/repository/iam.go @@ -0,0 +1,11 @@ +package repository + +import ( + "context" + + "github.com/caos/zitadel/internal/iam/model" +) + +type IamRepository interface { + GetIam(ctx context.Context) (*model.Iam, error) +} diff --git a/internal/auth/repository/key.go b/internal/auth/repository/key.go new file mode 100644 index 0000000000..17623be806 --- /dev/null +++ b/internal/auth/repository/key.go @@ -0,0 +1,14 @@ +package repository + +import ( + "context" + "time" + + "gopkg.in/square/go-jose.v2" +) + +type KeyRepository interface { + GenerateSigningKeyPair(ctx context.Context, algorithm string) error + GetSigningKey(ctx context.Context, keyCh chan<- jose.SigningKey, errCh chan<- error, timer <-chan time.Time) + GetKeySet(ctx context.Context) (*jose.JSONWebKeySet, error) +} diff --git a/internal/auth/repository/repository.go b/internal/auth/repository/repository.go index 461fce0c92..6e20219fb4 100644 --- a/internal/auth/repository/repository.go +++ b/internal/auth/repository/repository.go @@ -9,4 +9,8 @@ type Repository interface { UserRepository AuthRequestRepository TokenRepository + ApplicationRepository + KeyRepository + UserSessionRepository + UserGrantRepository } diff --git a/internal/auth/repository/token.go b/internal/auth/repository/token.go index 1de051447d..17db69118e 100644 --- a/internal/auth/repository/token.go +++ b/internal/auth/repository/token.go @@ -8,6 +8,7 @@ import ( ) type TokenRepository interface { - CreateToken(ctx context.Context, agentID, applicationID, userID string, lifetime time.Duration) (*model.Token, error) + CreateToken(ctx context.Context, agentID, applicationID, userID string, audience, scopes []string, lifetime time.Duration) (*model.Token, error) IsTokenValid(ctx context.Context, tokenID string) (bool, error) + TokenByID(ctx context.Context, tokenID string) (*model.Token, error) } diff --git a/internal/auth/repository/user.go b/internal/auth/repository/user.go index 7fb0b62615..83d9718553 100644 --- a/internal/auth/repository/user.go +++ b/internal/auth/repository/user.go @@ -11,10 +11,20 @@ type UserRepository interface { myUserRepo SkipMfaInit(ctx context.Context, userID string) error + RequestPasswordReset(ctx context.Context, username string) error SetPassword(ctx context.Context, userID, code, password string) error + ChangePassword(ctx context.Context, userID, old, new string) error + + VerifyEmail(ctx context.Context, userID, code string) error + ResendEmailVerificationMail(ctx context.Context, userID string) error + + AddMfaOTP(ctx context.Context, userID string) (*model.OTP, error) + VerifyMfaOTPSetup(ctx context.Context, userID, code string) error SignOut(ctx context.Context, agentID, userID string) error + + UserByID(ctx context.Context, userID string) (*model.User, error) } type myUserRepo interface { @@ -37,6 +47,6 @@ type myUserRepo interface { ChangeMyPassword(ctx context.Context, old, new string) error AddMyMfaOTP(ctx context.Context) (*model.OTP, error) - VerifyMyMfaOTP(ctx context.Context, code string) error + VerifyMyMfaOTPSetup(ctx context.Context, code string) error RemoveMyMfaOTP(ctx context.Context) error } diff --git a/internal/auth/repository/user_grant.go b/internal/auth/repository/user_grant.go new file mode 100644 index 0000000000..f3db22e330 --- /dev/null +++ b/internal/auth/repository/user_grant.go @@ -0,0 +1,12 @@ +package repository + +import ( + "context" + "github.com/caos/zitadel/internal/usergrant/model" +) + +type UserGrantRepository interface { + SearchMyUserGrants(ctx context.Context, request *model.UserGrantSearchRequest) (*model.UserGrantSearchResponse, error) + SearchMyProjectOrgs(ctx context.Context, request *model.UserGrantSearchRequest) (*model.ProjectOrgSearchResponse, error) + SearchMyZitadelPermissions(ctx context.Context) ([]string, error) +} diff --git a/internal/auth/repository/user_session.go b/internal/auth/repository/user_session.go new file mode 100644 index 0000000000..98e8751d07 --- /dev/null +++ b/internal/auth/repository/user_session.go @@ -0,0 +1,10 @@ +package repository + +import ( + "context" + "github.com/caos/zitadel/internal/user/model" +) + +type UserSessionRepository interface { + GetMyUserSessions(ctx context.Context) ([]*model.UserSessionView, error) +} diff --git a/internal/auth_request/model/auth_request.go b/internal/auth_request/model/auth_request.go index ba95313b87..f76daf2b0f 100644 --- a/internal/auth_request/model/auth_request.go +++ b/internal/auth_request/model/auth_request.go @@ -2,29 +2,36 @@ package model import ( "time" + + "github.com/caos/zitadel/internal/errors" ) type AuthRequest struct { - ID string - AgentID string - CreationDate time.Time - ChangeDate time.Time - BrowserInfo *BrowserInfo - ApplicationID string - CallbackURI string - TransferState string - Prompt Prompt - PossibleLOAs []LevelOfAssurance - UiLocales []string - LoginHint string - PreselectedUserID string - MaxAuthAge uint32 - Request Request + ID string + AgentID string + CreationDate time.Time + ChangeDate time.Time + BrowserInfo *BrowserInfo + ApplicationID string + CallbackURI string + TransferState string + Prompt Prompt + PossibleLOAs []LevelOfAssurance + UiLocales []string + LoginHint string + MaxAuthAge uint32 + Request Request - levelOfAssurance LevelOfAssurance - projectApplicationIDs []string - UserID string - PossibleSteps []NextStep + levelOfAssurance LevelOfAssurance + UserID string + UserName string + UserOrgID string + PossibleSteps []NextStep + PasswordVerified bool + MfasVerified []MfaType + Audience []string + AuthTime time.Time + Code string } type Prompt int32 @@ -46,22 +53,30 @@ const ( func NewAuthRequest(id, agentID string, info *BrowserInfo, applicationID, callbackURI, transferState string, prompt Prompt, possibleLOAs []LevelOfAssurance, uiLocales []string, loginHint, preselectedUserID string, maxAuthAge uint32, request Request) *AuthRequest { return &AuthRequest{ - ID: id, - AgentID: agentID, - BrowserInfo: info, - ApplicationID: applicationID, - CallbackURI: callbackURI, - TransferState: transferState, - Prompt: prompt, - PossibleLOAs: possibleLOAs, - UiLocales: uiLocales, - LoginHint: loginHint, - PreselectedUserID: preselectedUserID, - MaxAuthAge: maxAuthAge, - Request: request, + ID: id, + AgentID: agentID, + BrowserInfo: info, + ApplicationID: applicationID, + CallbackURI: callbackURI, + TransferState: transferState, + Prompt: prompt, + PossibleLOAs: possibleLOAs, + UiLocales: uiLocales, + LoginHint: loginHint, + UserID: preselectedUserID, + MaxAuthAge: maxAuthAge, + Request: request, } } +func NewAuthRequestFromType(requestType AuthRequestType) (*AuthRequest, error) { + request, ok := authRequestTypeMapping[requestType] + if !ok { + return nil, errors.ThrowInvalidArgument(nil, "MODEL-ds2kl", "invalid request type") + } + return &AuthRequest{Request: request}, nil +} + func (a *AuthRequest) IsValid() bool { return a.ID != "" && a.AgentID != "" && @@ -80,3 +95,9 @@ func (a *AuthRequest) WithCurrentInfo(info *BrowserInfo) *AuthRequest { a.BrowserInfo = info return a } + +func (a *AuthRequest) SetUserInfo(userID string, userName string, userOrgID string) { + a.UserID = userID + a.UserName = userName + a.UserOrgID = userOrgID +} diff --git a/internal/auth_request/model/browser_info.go b/internal/auth_request/model/browser_info.go index 2812b88583..abfbe696f0 100644 --- a/internal/auth_request/model/browser_info.go +++ b/internal/auth_request/model/browser_info.go @@ -1,6 +1,12 @@ package model -import "net" +import ( + "net" + "net/http" + + "github.com/caos/zitadel/internal/api" + http_util "github.com/caos/zitadel/internal/api/http" +) type BrowserInfo struct { UserAgent string @@ -8,6 +14,14 @@ type BrowserInfo struct { RemoteIP net.IP } +func BrowserInfoFromRequest(r *http.Request) *BrowserInfo { + return &BrowserInfo{ + UserAgent: r.Header.Get(api.UserAgent), + AcceptLanguage: r.Header.Get(api.AcceptLanguage), + RemoteIP: http_util.RemoteIPFromRequest(r), + } +} + func (i *BrowserInfo) IsValid() bool { return i.UserAgent != "" && i.AcceptLanguage != "" && diff --git a/internal/auth_request/model/next_step.go b/internal/auth_request/model/next_step.go index 68a9beb7ab..4c60900faa 100644 --- a/internal/auth_request/model/next_step.go +++ b/internal/auth_request/model/next_step.go @@ -10,6 +10,7 @@ const ( NextStepUnspecified NextStepType = iota NextStepLogin NextStepUserSelection + NextStepInitUser NextStepPassword NextStepChangePassword NextStepInitPassword @@ -26,9 +27,7 @@ const ( UserSessionStateTerminated ) -type LoginStep struct { - NotFound bool -} +type LoginStep struct{} func (s *LoginStep) Type() NextStepType { return NextStepLogin @@ -48,30 +47,33 @@ type UserSelection struct { UserSessionState UserSessionState } -type PasswordStep struct { - FailureCount uint16 +type InitUserStep struct { + PasswordSet bool } +func (s *InitUserStep) Type() NextStepType { + return NextStepInitUser +} + +type PasswordStep struct{} + func (s *PasswordStep) Type() NextStepType { return NextStepPassword } -type ChangePasswordStep struct { -} +type ChangePasswordStep struct{} func (s *ChangePasswordStep) Type() NextStepType { return NextStepChangePassword } -type InitPasswordStep struct { -} +type InitPasswordStep struct{} func (s *InitPasswordStep) Type() NextStepType { return NextStepInitPassword } -type VerifyEMailStep struct { -} +type VerifyEMailStep struct{} func (s *VerifyEMailStep) Type() NextStepType { return NextStepVerifyEmail @@ -87,7 +89,6 @@ func (s *MfaPromptStep) Type() NextStepType { } type MfaVerificationStep struct { - FailureCount uint16 MfaProviders []MfaType } @@ -95,8 +96,7 @@ func (s *MfaVerificationStep) Type() NextStepType { return NextStepMfaVerify } -type RedirectToCallbackStep struct { -} +type RedirectToCallbackStep struct{} func (s *RedirectToCallbackStep) Type() NextStepType { return NextStepRedirectToCallback @@ -111,7 +111,8 @@ const ( type MfaLevel int const ( - MfaLevelSoftware MfaLevel = iota + MfaLevelNotSetUp MfaLevel = iota + MfaLevelSoftware MfaLevelHardware MfaLevelHardwareCertified ) diff --git a/internal/auth_request/model/request.go b/internal/auth_request/model/request.go index c90cd52682..1f579d29b7 100644 --- a/internal/auth_request/model/request.go +++ b/internal/auth_request/model/request.go @@ -7,6 +7,12 @@ type Request interface { type AuthRequestType int32 +var ( + authRequestTypeMapping = map[AuthRequestType]Request{ + AuthRequestTypeOIDC: &AuthRequestOIDC{}, + } +) + const ( AuthRequestTypeOIDC AuthRequestType = iota AuthRequestTypeSAML diff --git a/internal/auth_request/repository/cache/cache.go b/internal/auth_request/repository/cache/cache.go index 7f510bfccf..dc930e6d36 100644 --- a/internal/auth_request/repository/cache/cache.go +++ b/internal/auth_request/repository/cache/cache.go @@ -5,6 +5,7 @@ import ( "database/sql" "encoding/json" "errors" + "fmt" "github.com/caos/zitadel/internal/auth_request/model" "github.com/caos/zitadel/internal/config/types" @@ -34,34 +35,62 @@ func (c *AuthRequestCache) Health(ctx context.Context) error { } func (c *AuthRequestCache) GetAuthRequestByID(_ context.Context, id string) (*model.AuthRequest, error) { + return c.getAuthRequest("id", id) +} + +func (c *AuthRequestCache) GetAuthRequestByCode(_ context.Context, code string) (*model.AuthRequest, error) { + return c.getAuthRequest("code", code) +} + +func (c *AuthRequestCache) SaveAuthRequest(_ context.Context, request *model.AuthRequest) error { + return c.saveAuthRequest(request, "INSERT INTO auth.auth_requests (id, request, request_type) VALUES($1, $2, $3)", request.Request.Type()) +} + +func (c *AuthRequestCache) UpdateAuthRequest(_ context.Context, request *model.AuthRequest) error { + return c.saveAuthRequest(request, "UPDATE auth.auth_requests SET request = $2, code = $3 WHERE id = $1", request.Code) +} + +func (c *AuthRequestCache) DeleteAuthRequest(_ context.Context, id string) error { + _, err := c.client.Exec("DELETE FROM auth.auth_requests WHERE id = $1", id) + if err != nil { + return caos_errs.ThrowInternal(err, "CACHE-dsHw3", "unable to delete auth request") + } + return nil +} + +func (c *AuthRequestCache) getAuthRequest(key, value string) (*model.AuthRequest, error) { var b []byte - err := c.client.QueryRow("SELECT request FROM auth.authrequests WHERE id = ?", id).Scan(&b) + var requestType model.AuthRequestType + query := fmt.Sprintf("SELECT request, request_type FROM auth.auth_requests WHERE %s = $1", key) + err := c.client.QueryRow(query, value).Scan(&b, &requestType) if err != nil { if errors.Is(err, sql.ErrNoRows) { return nil, caos_errs.ThrowNotFound(err, "CACHE-d24aD", "auth request not found") } return nil, caos_errs.ThrowInternal(err, "CACHE-as3kj", "unable to get auth request from database") } - request := new(model.AuthRequest) - err = json.Unmarshal(b, &request) + request, err := model.NewAuthRequestFromType(requestType) + if err == nil { + err = json.Unmarshal(b, request) + } if err != nil { return nil, caos_errs.ThrowInternal(err, "CACHE-2wshg", "unable to unmarshal auth request") } return request, nil } -func (c *AuthRequestCache) SaveAuthRequest(_ context.Context, request *model.AuthRequest) error { +func (c *AuthRequestCache) saveAuthRequest(request *model.AuthRequest, query string, param interface{}) error { b, err := json.Marshal(request) if err != nil { - return caos_errs.ThrowInternal(err, "CACHE-32FH9", "unable to marshal auth request") + return caos_errs.ThrowInternal(err, "CACHE-os0GH", "unable to marshal auth request") } - stmt, err := c.client.Prepare("INSERT INTO auth.authrequests (id, request) VALUES($1, $2)") + stmt, err := c.client.Prepare(query) if err != nil { - return caos_errs.ThrowInternal(err, "CACHE-dswfF", "sql prepare failed") + return caos_errs.ThrowInternal(err, "CACHE-su3GK", "sql prepare failed") } - _, err = stmt.Exec(request.ID, b) + _, err = stmt.Exec(request.ID, b, param) if err != nil { - return caos_errs.ThrowInternal(err, "CACHE-sw4af", "unable to save auth request") + return caos_errs.ThrowInternal(err, "CACHE-sj8iS", "unable to save auth request") } return nil } diff --git a/internal/auth_request/repository/gen_mock.go b/internal/auth_request/repository/gen_mock.go index 1a7097ae95..c904aec4d6 100644 --- a/internal/auth_request/repository/gen_mock.go +++ b/internal/auth_request/repository/gen_mock.go @@ -1,3 +1,3 @@ package repository -//go:generate mockgen -package mock -destination ./mock/repository.mock.go github.com/caos/zitadel/internal/auth_request/repository Repository +//go:generate mockgen -package mock -destination ./mock/repository.mock.go github.com/caos/zitadel/internal/auth_request/repository AuthRequestCache diff --git a/internal/auth_request/repository/mock/repository.go b/internal/auth_request/repository/mock/repository.go deleted file mode 100644 index 0eef6e337e..0000000000 --- a/internal/auth_request/repository/mock/repository.go +++ /dev/null @@ -1,12 +0,0 @@ -package mock - -import ( - "github.com/golang/mock/gomock" - - "github.com/caos/zitadel/internal/auth_request/repository" -) - -func NewMockAuthRequestRepository(ctrl *gomock.Controller) repository.Repository { - repo := NewMockRepository(ctrl) - return repo -} diff --git a/internal/auth_request/repository/mock/repository.mock.go b/internal/auth_request/repository/mock/repository.mock.go index 8ffbf9d4a3..9d23f6e35f 100644 --- a/internal/auth_request/repository/mock/repository.mock.go +++ b/internal/auth_request/repository/mock/repository.mock.go @@ -1,5 +1,5 @@ // Code generated by MockGen. DO NOT EDIT. -// Source: github.com/caos/zitadel/internal/auth_request/repository (interfaces: Repository) +// Source: github.com/caos/zitadel/internal/auth_request/repository (interfaces: AuthRequestCache) // Package mock is a generated GoMock package. package mock @@ -11,31 +11,60 @@ import ( reflect "reflect" ) -// MockRepository is a mock of Repository interface -type MockRepository struct { +// MockAuthRequestCache is a mock of AuthRequestCache interface +type MockAuthRequestCache struct { ctrl *gomock.Controller - recorder *MockRepositoryMockRecorder + recorder *MockAuthRequestCacheMockRecorder } -// MockRepositoryMockRecorder is the mock recorder for MockRepository -type MockRepositoryMockRecorder struct { - mock *MockRepository +// MockAuthRequestCacheMockRecorder is the mock recorder for MockAuthRequestCache +type MockAuthRequestCacheMockRecorder struct { + mock *MockAuthRequestCache } -// NewMockRepository creates a new mock instance -func NewMockRepository(ctrl *gomock.Controller) *MockRepository { - mock := &MockRepository{ctrl: ctrl} - mock.recorder = &MockRepositoryMockRecorder{mock} +// NewMockAuthRequestCache creates a new mock instance +func NewMockAuthRequestCache(ctrl *gomock.Controller) *MockAuthRequestCache { + mock := &MockAuthRequestCache{ctrl: ctrl} + mock.recorder = &MockAuthRequestCacheMockRecorder{mock} return mock } // EXPECT returns an object that allows the caller to indicate expected use -func (m *MockRepository) EXPECT() *MockRepositoryMockRecorder { +func (m *MockAuthRequestCache) EXPECT() *MockAuthRequestCacheMockRecorder { return m.recorder } +// DeleteAuthRequest mocks base method +func (m *MockAuthRequestCache) DeleteAuthRequest(arg0 context.Context, arg1 string) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "DeleteAuthRequest", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// DeleteAuthRequest indicates an expected call of DeleteAuthRequest +func (mr *MockAuthRequestCacheMockRecorder) DeleteAuthRequest(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAuthRequest", reflect.TypeOf((*MockAuthRequestCache)(nil).DeleteAuthRequest), arg0, arg1) +} + +// GetAuthRequestByCode mocks base method +func (m *MockAuthRequestCache) GetAuthRequestByCode(arg0 context.Context, arg1 string) (*model.AuthRequest, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetAuthRequestByCode", arg0, arg1) + ret0, _ := ret[0].(*model.AuthRequest) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetAuthRequestByCode indicates an expected call of GetAuthRequestByCode +func (mr *MockAuthRequestCacheMockRecorder) GetAuthRequestByCode(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthRequestByCode", reflect.TypeOf((*MockAuthRequestCache)(nil).GetAuthRequestByCode), arg0, arg1) +} + // GetAuthRequestByID mocks base method -func (m *MockRepository) GetAuthRequestByID(arg0 context.Context, arg1 string) (*model.AuthRequest, error) { +func (m *MockAuthRequestCache) GetAuthRequestByID(arg0 context.Context, arg1 string) (*model.AuthRequest, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetAuthRequestByID", arg0, arg1) ret0, _ := ret[0].(*model.AuthRequest) @@ -44,13 +73,13 @@ func (m *MockRepository) GetAuthRequestByID(arg0 context.Context, arg1 string) ( } // GetAuthRequestByID indicates an expected call of GetAuthRequestByID -func (mr *MockRepositoryMockRecorder) GetAuthRequestByID(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAuthRequestCacheMockRecorder) GetAuthRequestByID(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthRequestByID", reflect.TypeOf((*MockRepository)(nil).GetAuthRequestByID), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAuthRequestByID", reflect.TypeOf((*MockAuthRequestCache)(nil).GetAuthRequestByID), arg0, arg1) } // Health mocks base method -func (m *MockRepository) Health(arg0 context.Context) error { +func (m *MockAuthRequestCache) Health(arg0 context.Context) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "Health", arg0) ret0, _ := ret[0].(error) @@ -58,22 +87,35 @@ func (m *MockRepository) Health(arg0 context.Context) error { } // Health indicates an expected call of Health -func (mr *MockRepositoryMockRecorder) Health(arg0 interface{}) *gomock.Call { +func (mr *MockAuthRequestCacheMockRecorder) Health(arg0 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Health", reflect.TypeOf((*MockRepository)(nil).Health), arg0) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Health", reflect.TypeOf((*MockAuthRequestCache)(nil).Health), arg0) } // SaveAuthRequest mocks base method -func (m *MockRepository) SaveAuthRequest(arg0 context.Context, arg1 string) (*model.AuthRequest, error) { +func (m *MockAuthRequestCache) SaveAuthRequest(arg0 context.Context, arg1 *model.AuthRequest) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SaveAuthRequest", arg0, arg1) - ret0, _ := ret[0].(*model.AuthRequest) - ret1, _ := ret[1].(error) - return ret0, ret1 + ret0, _ := ret[0].(error) + return ret0 } // SaveAuthRequest indicates an expected call of SaveAuthRequest -func (mr *MockRepositoryMockRecorder) SaveAuthRequest(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAuthRequestCacheMockRecorder) SaveAuthRequest(arg0, arg1 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveAuthRequest", reflect.TypeOf((*MockRepository)(nil).SaveAuthRequest), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SaveAuthRequest", reflect.TypeOf((*MockAuthRequestCache)(nil).SaveAuthRequest), arg0, arg1) +} + +// UpdateAuthRequest mocks base method +func (m *MockAuthRequestCache) UpdateAuthRequest(arg0 context.Context, arg1 *model.AuthRequest) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateAuthRequest", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateAuthRequest indicates an expected call of UpdateAuthRequest +func (mr *MockAuthRequestCacheMockRecorder) UpdateAuthRequest(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateAuthRequest", reflect.TypeOf((*MockAuthRequestCache)(nil).UpdateAuthRequest), arg0, arg1) } diff --git a/internal/auth_request/repository/repository.go b/internal/auth_request/repository/repository.go index 34e4963f13..f72d2c8fda 100644 --- a/internal/auth_request/repository/repository.go +++ b/internal/auth_request/repository/repository.go @@ -6,9 +6,12 @@ import ( "github.com/caos/zitadel/internal/auth_request/model" ) -type Repository interface { +type AuthRequestCache interface { Health(ctx context.Context) error GetAuthRequestByID(ctx context.Context, id string) (*model.AuthRequest, error) - SaveAuthRequest(ctx context.Context, id string) (*model.AuthRequest, error) + GetAuthRequestByCode(ctx context.Context, code string) (*model.AuthRequest, error) + SaveAuthRequest(ctx context.Context, request *model.AuthRequest) error + UpdateAuthRequest(ctx context.Context, request *model.AuthRequest) error + DeleteAuthRequest(ctx context.Context, id string) error } diff --git a/internal/authz/authz.go b/internal/authz/authz.go new file mode 100644 index 0000000000..9f2c42da91 --- /dev/null +++ b/internal/authz/authz.go @@ -0,0 +1,16 @@ +package authz + +import ( + "context" + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing" + sd "github.com/caos/zitadel/internal/config/systemdefaults" +) + +type Config struct { + Repository eventsourcing.Config +} + +func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) (*eventsourcing.EsRepository, error) { + return eventsourcing.Start(config.Repository, authZ, systemDefaults) +} diff --git a/internal/authz/repository/eventsourcing/eventstore/iam.go b/internal/authz/repository/eventsourcing/eventstore/iam.go new file mode 100644 index 0000000000..d0fee2efb3 --- /dev/null +++ b/internal/authz/repository/eventsourcing/eventstore/iam.go @@ -0,0 +1,20 @@ +package eventstore + +import ( + "context" + "github.com/caos/zitadel/internal/iam/model" + iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" +) + +type IamRepo struct { + IamID string + IamEvents *iam_event.IamEventstore +} + +func (repo *IamRepo) Health(ctx context.Context) error { + return repo.IamEvents.Health(ctx) +} + +func (repo *IamRepo) IamByID(ctx context.Context) (*model.Iam, error) { + return repo.IamEvents.IamByID(ctx, repo.IamID) +} diff --git a/internal/authz/repository/eventsourcing/eventstore/token_verifier.go b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go new file mode 100644 index 0000000000..d350070ecc --- /dev/null +++ b/internal/authz/repository/eventsourcing/eventstore/token_verifier.go @@ -0,0 +1,68 @@ +package eventstore + +import ( + "context" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" + "github.com/caos/zitadel/internal/crypto" + caos_errs "github.com/caos/zitadel/internal/errors" + iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" + "time" +) + +type TokenVerifierRepo struct { + TokenVerificationKey [32]byte + IamID string + IamEvents *iam_event.IamEventstore + ProjectEvents *proj_event.ProjectEventstore + View *view.View +} + +func (repo *TokenVerifierRepo) VerifyAccessToken(ctx context.Context, tokenString, appName, appID string) (userID string, clientID string, agentID string, err error) { + clientID, err = repo.verifierClientID(ctx, appName, appID) + if err != nil { + return "", "", "", caos_errs.ThrowPermissionDenied(nil, "APP-ptTIF2", "invalid token") + } + //TODO: use real key + tokenID, err := crypto.DecryptAESString(tokenString, string(repo.TokenVerificationKey[:32])) + if err != nil { + return "", "", "", caos_errs.ThrowPermissionDenied(nil, "APP-8EF0zZ", "invalid token") + } + token, err := repo.View.TokenByID(tokenID) + if err != nil { + return "", "", "", caos_errs.ThrowPermissionDenied(err, "APP-BxUSiL", "invalid token") + } + if !token.Expiration.After(time.Now().UTC()) { + return "", "", "", caos_errs.ThrowPermissionDenied(err, "APP-k9KS0", "invalid token") + } + + for _, aud := range token.Audience { + if clientID == aud { + return token.UserID, clientID, token.UserAgentID, nil + } + } + return "", "", "", caos_errs.ThrowPermissionDenied(nil, "APP-Zxfako", "invalid audience") +} + +func (repo *TokenVerifierRepo) ProjectIDByClientID(ctx context.Context, clientID string) (projectID string, err error) { + app, err := repo.View.ApplicationByOIDCClientID(clientID) + if err != nil { + return "", err + } + return app.ID, nil +} + +func (repo *TokenVerifierRepo) verifierClientID(ctx context.Context, appName, appClientID string) (string, error) { + if appClientID != "" { + return appClientID, nil + } + iam, err := repo.IamEvents.IamByID(ctx, repo.IamID) + if err != nil { + return "", err + } + app, err := repo.View.ApplicationByProjecIDAndAppName(iam.IamProjectID, appName) + if err != nil { + return "", err + } + return app.OIDCClientID, nil +} diff --git a/internal/authz/repository/eventsourcing/eventstore/user_grant.go b/internal/authz/repository/eventsourcing/eventstore/user_grant.go new file mode 100644 index 0000000000..08a170885c --- /dev/null +++ b/internal/authz/repository/eventsourcing/eventstore/user_grant.go @@ -0,0 +1,102 @@ +package eventstore + +import ( + "context" + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" + caos_errs "github.com/caos/zitadel/internal/errors" + iam_event "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + grant_model "github.com/caos/zitadel/internal/usergrant/model" + "github.com/caos/zitadel/internal/usergrant/repository/view/model" +) + +type UserGrantRepo struct { + View *view.View + IamID string + IamProjectID string + Auth auth.Config + IamEvents *iam_event.IamEventstore +} + +func (repo *UserGrantRepo) Health() error { + return repo.View.Health() +} + +func (repo *UserGrantRepo) ResolveGrants(ctx context.Context) (*auth.Grant, error) { + err := repo.fillIamProjectID(ctx) + if err != nil { + return nil, err + } + ctxData := auth.GetCtxData(ctx) + + orgGrant, err := repo.View.UserGrantByIDs(ctxData.OrgID, repo.IamProjectID, ctxData.UserID) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + iamAdminGrant, err := repo.View.UserGrantByIDs(repo.IamID, repo.IamProjectID, ctxData.UserID) + if err != nil && !caos_errs.IsNotFound(err) { + return nil, err + } + + return mergeOrgAndAdminGrant(ctxData, orgGrant, iamAdminGrant), nil +} + +func (repo *UserGrantRepo) SearchMyZitadelPermissions(ctx context.Context) ([]string, error) { + grant, err := repo.ResolveGrants(ctx) + if err != nil { + return nil, err + } + + permissions := &grant_model.Permissions{Permissions: []string{}} + for _, role := range grant.Roles { + roleName, ctxID := auth.SplitPermission(role) + for _, mapping := range repo.Auth.RolePermissionMappings { + if mapping.Role == roleName { + permissions.AppendPermissions(ctxID, mapping.Permissions...) + } + } + } + return permissions.Permissions, nil +} + +func (repo *UserGrantRepo) fillIamProjectID(ctx context.Context) error { + if repo.IamProjectID != "" { + return nil + } + iam, err := repo.IamEvents.IamByID(ctx, repo.IamID) + if err != nil { + return err + } + if !iam.SetUpDone { + return caos_errs.ThrowPreconditionFailed(nil, "EVENT-skiwS", "Setup not done") + } + repo.IamProjectID = iam.IamProjectID + return nil +} + +func mergeOrgAndAdminGrant(ctxData auth.CtxData, orgGrant, iamAdminGrant *model.UserGrantView) (grant *auth.Grant) { + if orgGrant != nil { + roles := orgGrant.RoleKeys + if iamAdminGrant != nil { + roles = addIamAdminRoles(roles, iamAdminGrant.RoleKeys) + } + grant = &auth.Grant{OrgID: orgGrant.ResourceOwner, Roles: roles} + } else if iamAdminGrant != nil { + grant = &auth.Grant{ + OrgID: ctxData.OrgID, + Roles: iamAdminGrant.RoleKeys, + } + } + return grant +} + +func addIamAdminRoles(orgRoles, iamAdminRoles []string) []string { + result := make([]string, 0) + result = append(result, iamAdminRoles...) + for _, role := range orgRoles { + if !auth.ExistsPerm(result, role) { + result = append(result, role) + } + } + return result +} diff --git a/internal/authz/repository/eventsourcing/handler/application.go b/internal/authz/repository/eventsourcing/handler/application.go new file mode 100644 index 0000000000..ea8708b9ef --- /dev/null +++ b/internal/authz/repository/eventsourcing/handler/application.go @@ -0,0 +1,72 @@ +package handler + +import ( + "github.com/caos/logging" + "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/eventstore/spooler" + "github.com/caos/zitadel/internal/project/repository/eventsourcing" + es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + view_model "github.com/caos/zitadel/internal/project/repository/view/model" + "time" +) + +type Application struct { + handler +} + +const ( + applicationTable = "authz.applications" +) + +func (p *Application) MinimumCycleDuration() time.Duration { return p.cycleDuration } + +func (p *Application) ViewModel() string { + return applicationTable +} + +func (p *Application) EventQuery() (*models.SearchQuery, error) { + sequence, err := p.view.GetLatestApplicationSequence() + if err != nil { + return nil, err + } + return eventsourcing.ProjectQuery(sequence), nil +} + +func (p *Application) Process(event *models.Event) (err error) { + app := new(view_model.ApplicationView) + switch event.Type { + case es_model.ApplicationAdded: + app.AppendEvent(event) + case es_model.ApplicationChanged, + es_model.OIDCConfigAdded, + es_model.OIDCConfigChanged, + es_model.ApplicationDeactivated, + es_model.ApplicationReactivated: + err := app.SetData(event) + if err != nil { + return err + } + app, err = p.view.ApplicationByID(app.ID) + if err != nil { + return err + } + app.AppendEvent(event) + case es_model.ApplicationRemoved: + err := app.SetData(event) + if err != nil { + return err + } + return p.view.DeleteApplication(app.ID, event.Sequence) + default: + return p.view.ProcessedApplicationSequence(event.Sequence) + } + if err != nil { + return err + } + return p.view.PutApplication(app) +} + +func (p *Application) OnError(event *models.Event, spoolerError error) error { + logging.LogWithFields("SPOOL-sjZw", "id", event.AggregateID).WithError(spoolerError).Warn("something went wrong in project app handler") + return spooler.HandleError(event, spoolerError, p.view.GetLatestApplicationFailedEvent, p.view.ProcessedApplicationFailedEvent, p.view.ProcessedApplicationSequence, p.errorCountUntilSkip) +} diff --git a/internal/authz/repository/eventsourcing/handler/handler.go b/internal/authz/repository/eventsourcing/handler/handler.go new file mode 100644 index 0000000000..d5904f0435 --- /dev/null +++ b/internal/authz/repository/eventsourcing/handler/handler.go @@ -0,0 +1,49 @@ +package handler + +import ( + sd "github.com/caos/zitadel/internal/config/systemdefaults" + "github.com/caos/zitadel/internal/eventstore" + iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + "time" + + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" + "github.com/caos/zitadel/internal/config/types" + "github.com/caos/zitadel/internal/eventstore/spooler" +) + +type Configs map[string]*Config + +type Config struct { + MinimumCycleDuration types.Duration +} + +type handler struct { + view *view.View + bulkLimit uint64 + cycleDuration time.Duration + errorCountUntilSkip uint64 +} + +type EventstoreRepos struct { + IamEvents *iam_events.IamEventstore +} + +func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, eventstore eventstore.Eventstore, repos EventstoreRepos, systemDefaults sd.SystemDefaults) []spooler.Handler { + return []spooler.Handler{ + &UserGrant{ + handler: handler{view, bulkLimit, configs.cycleDuration("UserGrant"), errorCount}, + eventstore: eventstore, + iamID: systemDefaults.IamID, + iamEvents: repos.IamEvents, + }, + &Application{handler: handler{view, bulkLimit, configs.cycleDuration("Application"), errorCount}}, + } +} + +func (configs Configs) cycleDuration(viewModel string) time.Duration { + c, ok := configs[viewModel] + if !ok { + return 1 * time.Second + } + return c.MinimumCycleDuration.Duration +} diff --git a/internal/authz/repository/eventsourcing/handler/user_grant.go b/internal/authz/repository/eventsourcing/handler/user_grant.go new file mode 100644 index 0000000000..33990cbf96 --- /dev/null +++ b/internal/authz/repository/eventsourcing/handler/user_grant.go @@ -0,0 +1,226 @@ +package handler + +import ( + "context" + "github.com/caos/logging" + "github.com/caos/zitadel/internal/errors" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/eventstore/spooler" + iam_events "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + iam_es_model "github.com/caos/zitadel/internal/iam/repository/eventsourcing/model" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" + proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + view_model "github.com/caos/zitadel/internal/usergrant/repository/view/model" + "strings" + "time" +) + +type UserGrant struct { + handler + eventstore eventstore.Eventstore + iamEvents *iam_events.IamEventstore + iamID string + iamProjectID string +} + +const ( + userGrantTable = "authz.user_grants" +) + +func (u *UserGrant) MinimumCycleDuration() time.Duration { return u.cycleDuration } + +func (u *UserGrant) ViewModel() string { + return userGrantTable +} + +func (u *UserGrant) EventQuery() (*models.SearchQuery, error) { + if u.iamProjectID == "" { + err := u.setIamProjectID() + if err != nil { + return nil, err + } + } + sequence, err := u.view.GetLatestUserGrantSequence() + if err != nil { + return nil, err + } + return es_models.NewSearchQuery(). + AggregateTypeFilter(iam_es_model.IamAggregate, org_es_model.OrgAggregate, proj_es_model.ProjectAggregate). + LatestSequenceFilter(sequence), nil +} + +func (u *UserGrant) Process(event *models.Event) (err error) { + switch event.AggregateType { + case proj_es_model.ProjectAggregate: + err = u.processProject(event) + case iam_es_model.IamAggregate: + err = u.processIamMember(event, "IAM", false) + case org_es_model.OrgAggregate: + return u.processOrg(event) + } + return err +} + +func (u *UserGrant) processProject(event *models.Event) (err error) { + switch event.Type { + case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectMemberRemoved: + member := new(proj_es_model.ProjectMember) + member.SetData(event) + return u.processMember(event, "PROJECT", true, member.UserID, member.Roles) + case proj_es_model.ProjectGrantMemberAdded, proj_es_model.ProjectGrantMemberChanged, proj_es_model.ProjectGrantMemberRemoved: + member := new(proj_es_model.ProjectGrantMember) + member.SetData(event) + return u.processMember(event, "PROJECT_GRANT", true, member.UserID, member.Roles) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } + return nil +} + +func (u *UserGrant) processOrg(event *models.Event) (err error) { + switch event.Type { + case org_es_model.OrgMemberAdded, org_es_model.OrgMemberChanged, org_es_model.OrgMemberRemoved: + member := new(org_es_model.OrgMember) + member.SetData(event) + return u.processMember(event, "ORG", false, member.UserID, member.Roles) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } + return nil +} + +func (u *UserGrant) processIamMember(event *models.Event, rolePrefix string, suffix bool) error { + member := new(iam_es_model.IamMember) + + switch event.Type { + case iam_es_model.IamMemberAdded, iam_es_model.IamMemberChanged: + member.SetData(event) + + grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID) + if err != nil && !errors.IsNotFound(err) { + return err + } + if errors.IsNotFound(err) { + grant = &view_model.UserGrantView{ + ID: u.iamProjectID + member.UserID, + ResourceOwner: u.iamID, + OrgName: u.iamID, + OrgDomain: u.iamID, + ProjectID: u.iamProjectID, + UserID: member.UserID, + RoleKeys: member.Roles, + CreationDate: event.CreationDate, + } + if suffix { + grant.RoleKeys = suffixRoles(event.AggregateID, grant.RoleKeys) + } + } else { + newRoles := member.Roles + if grant.RoleKeys != nil { + grant.RoleKeys = mergeExistingRoles(rolePrefix, grant.RoleKeys, newRoles) + } else { + grant.RoleKeys = newRoles + } + + } + grant.Sequence = event.Sequence + grant.ChangeDate = event.CreationDate + return u.view.PutUserGrant(grant, grant.Sequence) + case iam_es_model.IamMemberRemoved: + member.SetData(event) + grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID) + if err != nil { + return err + } + return u.view.DeleteUserGrant(grant.ID, event.Sequence) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } +} + +func (u *UserGrant) processMember(event *models.Event, rolePrefix string, suffix bool, userID string, roleKeys []string) error { + switch event.Type { + case org_es_model.OrgMemberAdded, proj_es_model.ProjectMemberAdded, proj_es_model.ProjectGrantMemberAdded, + org_es_model.OrgMemberChanged, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectGrantMemberChanged: + + grant, err := u.view.UserGrantByIDs(event.ResourceOwner, u.iamProjectID, userID) + if err != nil && !errors.IsNotFound(err) { + return err + } + if suffix { + roleKeys = suffixRoles(event.AggregateID, roleKeys) + } + if errors.IsNotFound(err) { + grant = &view_model.UserGrantView{ + ID: u.iamProjectID + event.ResourceOwner + userID, + ResourceOwner: event.ResourceOwner, + ProjectID: u.iamProjectID, + UserID: userID, + RoleKeys: roleKeys, + CreationDate: event.CreationDate, + } + } else { + newRoles := roleKeys + if grant.RoleKeys != nil { + grant.RoleKeys = mergeExistingRoles(rolePrefix, grant.RoleKeys, newRoles) + } else { + grant.RoleKeys = newRoles + } + } + grant.Sequence = event.Sequence + grant.ChangeDate = event.CreationDate + return u.view.PutUserGrant(grant, event.Sequence) + case org_es_model.OrgMemberRemoved, + proj_es_model.ProjectMemberRemoved, + proj_es_model.ProjectGrantMemberRemoved: + + grant, err := u.view.UserGrantByIDs(event.ResourceOwner, u.iamProjectID, userID) + if err != nil { + return err + } + return u.view.DeleteUserGrant(grant.ID, event.Sequence) + default: + return u.view.ProcessedUserGrantSequence(event.Sequence) + } +} + +func suffixRoles(suffix string, roles []string) []string { + suffixedRoles := make([]string, len(roles)) + for i := 0; i < len(roles); i++ { + suffixedRoles[i] = roles[i] + ":" + suffix + } + return suffixedRoles +} + +func mergeExistingRoles(rolePrefix string, existingRoles, newRoles []string) []string { + mergedRoles := make([]string, 0) + for _, existing := range existingRoles { + if !strings.HasPrefix(existing, rolePrefix) { + mergedRoles = append(mergedRoles, existing) + } + } + return append(mergedRoles, newRoles...) +} + +func (u *UserGrant) setIamProjectID() error { + if u.iamProjectID != "" { + return nil + } + iam, err := u.iamEvents.IamByID(context.Background(), u.iamID) + if err != nil { + return err + } + if !iam.SetUpDone { + return caos_errs.ThrowPreconditionFailed(nil, "HANDL-s5DTs", "Setup not done") + } + u.iamProjectID = iam.IamProjectID + return nil +} + +func (u *UserGrant) OnError(event *models.Event, err error) error { + logging.LogWithFields("SPOOL-8is4s", "id", event.AggregateID).WithError(err).Warn("something went wrong in user handler") + return spooler.HandleError(event, err, u.view.GetLatestUserGrantFailedEvent, u.view.ProcessedUserGrantFailedEvent, u.view.ProcessedUserGrantSequence, u.errorCountUntilSkip) +} diff --git a/internal/authz/repository/eventsourcing/repository.go b/internal/authz/repository/eventsourcing/repository.go new file mode 100644 index 0000000000..29772e4667 --- /dev/null +++ b/internal/authz/repository/eventsourcing/repository.go @@ -0,0 +1,98 @@ +package eventsourcing + +import ( + "context" + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/handler" + es_iam "github.com/caos/zitadel/internal/iam/repository/eventsourcing" + "github.com/caos/zitadel/internal/id" + es_proj "github.com/caos/zitadel/internal/project/repository/eventsourcing" + + "github.com/caos/zitadel/internal/auth_request/repository/cache" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/eventstore" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/spooler" + authz_view "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" + sd "github.com/caos/zitadel/internal/config/systemdefaults" + "github.com/caos/zitadel/internal/config/types" + es_int "github.com/caos/zitadel/internal/eventstore" + es_spol "github.com/caos/zitadel/internal/eventstore/spooler" + es_key "github.com/caos/zitadel/internal/key/repository/eventsourcing" +) + +type Config struct { + Eventstore es_int.Config + AuthRequest cache.Config + View types.SQL + Spooler spooler.SpoolerConfig + KeyConfig es_key.KeyConfig +} + +type EsRepository struct { + spooler *es_spol.Spooler + eventstore.UserGrantRepo + eventstore.IamRepo + eventstore.TokenVerifierRepo +} + +func Start(conf Config, authZ auth.Config, systemDefaults sd.SystemDefaults) (*EsRepository, error) { + es, err := es_int.Start(conf.Eventstore) + if err != nil { + return nil, err + } + + sqlClient, err := conf.View.Start() + if err != nil { + return nil, err + } + + idGenerator := id.SonyFlakeGenerator + view, err := authz_view.StartView(sqlClient, idGenerator) + if err != nil { + return nil, err + } + + iam, err := es_iam.StartIam(es_iam.IamConfig{ + Eventstore: es, + Cache: conf.Eventstore.Cache, + }, systemDefaults) + if err != nil { + return nil, err + } + project, err := es_proj.StartProject(es_proj.ProjectConfig{ + Eventstore: es, + Cache: conf.Eventstore.Cache, + }, systemDefaults) + if err != nil { + return nil, err + } + repos := handler.EventstoreRepos{IamEvents: iam} + spool := spooler.StartSpooler(conf.Spooler, es, view, sqlClient, repos, systemDefaults) + + return &EsRepository{ + spool, + eventstore.UserGrantRepo{ + View: view, + IamID: systemDefaults.IamID, + Auth: authZ, + IamEvents: iam, + }, + eventstore.IamRepo{ + IamID: systemDefaults.IamID, + IamEvents: iam, + }, + eventstore.TokenVerifierRepo{ + //TODO: Add Token Verification Key + IamID: systemDefaults.IamID, + IamEvents: iam, + ProjectEvents: project, + View: view, + }, + }, nil +} + +func (repo *EsRepository) Health(ctx context.Context) error { + if err := repo.UserGrantRepo.Health(); err != nil { + return err + } + return nil +} diff --git a/internal/authz/repository/eventsourcing/spooler/lock.go b/internal/authz/repository/eventsourcing/spooler/lock.go new file mode 100644 index 0000000000..6100f470d3 --- /dev/null +++ b/internal/authz/repository/eventsourcing/spooler/lock.go @@ -0,0 +1,19 @@ +package spooler + +import ( + "database/sql" + es_locker "github.com/caos/zitadel/internal/eventstore/locker" + "time" +) + +const ( + lockTable = "authz.locks" +) + +type locker struct { + dbClient *sql.DB +} + +func (l *locker) Renew(lockerID, viewModel string, waitTime time.Duration) error { + return es_locker.Renew(l.dbClient, lockTable, lockerID, viewModel, waitTime) +} diff --git a/internal/authz/repository/eventsourcing/spooler/lock_test.go b/internal/authz/repository/eventsourcing/spooler/lock_test.go new file mode 100644 index 0000000000..904d0b9838 --- /dev/null +++ b/internal/authz/repository/eventsourcing/spooler/lock_test.go @@ -0,0 +1,127 @@ +package spooler + +import ( + "database/sql" + "testing" + "time" + + "github.com/DATA-DOG/go-sqlmock" +) + +type dbMock struct { + db *sql.DB + mock sqlmock.Sqlmock +} + +func mockDB(t *testing.T) *dbMock { + mockDB := dbMock{} + var err error + mockDB.db, mockDB.mock, err = sqlmock.New() + if err != nil { + t.Fatalf("error occured while creating stub db %v", err) + } + + mockDB.mock.MatchExpectationsInOrder(true) + + return &mockDB +} + +func (db *dbMock) expectCommit() *dbMock { + db.mock.ExpectCommit() + + return db +} + +func (db *dbMock) expectRollback() *dbMock { + db.mock.ExpectRollback() + + return db +} + +func (db *dbMock) expectBegin() *dbMock { + db.mock.ExpectBegin() + + return db +} + +func (db *dbMock) expectSavepoint() *dbMock { + db.mock.ExpectExec("SAVEPOINT").WillReturnResult(sqlmock.NewResult(1, 1)) + return db +} + +func (db *dbMock) expectReleaseSavepoint() *dbMock { + db.mock.ExpectExec("RELEASE SAVEPOINT").WillReturnResult(sqlmock.NewResult(1, 1)) + + return db +} + +func (db *dbMock) expectRenew(lockerID, view string, affectedRows int64) *dbMock { + query := db.mock. + ExpectExec(`INSERT INTO authz\.locks \(object_type, locker_id, locked_until\) VALUES \(\$1, \$2, now\(\)\+\$3\) ON CONFLICT \(object_type\) DO UPDATE SET locked_until = now\(\)\+\$4, locker_id = \$5 WHERE \(locks\.locked_until < now\(\) OR locks\.locker_id = \$6\) AND locks\.object_type = \$7`). + WithArgs(view, lockerID, sqlmock.AnyArg(), sqlmock.AnyArg(), lockerID, lockerID, view). + WillReturnResult(sqlmock.NewResult(1, 1)) + + if affectedRows == 0 { + query.WillReturnResult(sqlmock.NewResult(0, 0)) + } else { + query.WillReturnResult(sqlmock.NewResult(1, affectedRows)) + } + + return db +} + +func Test_locker_Renew(t *testing.T) { + type fields struct { + db *dbMock + } + type args struct { + lockerID string + viewModel string + waitTime time.Duration + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "renew succeeded", + fields: fields{ + db: mockDB(t). + expectBegin(). + expectSavepoint(). + expectRenew("locker", "view", 1). + expectReleaseSavepoint(). + expectCommit(), + }, + args: args{lockerID: "locker", viewModel: "view", waitTime: 1 * time.Second}, + wantErr: false, + }, + { + name: "renew now rows updated", + fields: fields{ + db: mockDB(t). + expectBegin(). + expectSavepoint(). + expectRenew("locker", "view", 0). + expectRollback(), + }, + args: args{lockerID: "locker", viewModel: "view", waitTime: 1 * time.Second}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + l := &locker{ + dbClient: tt.fields.db.db, + } + if err := l.Renew(tt.args.lockerID, tt.args.viewModel, tt.args.waitTime); (err != nil) != tt.wantErr { + t.Errorf("locker.Renew() error = %v, wantErr %v", err, tt.wantErr) + } + if err := tt.fields.db.mock.ExpectationsWereMet(); err != nil { + t.Errorf("not all database expectations met: %v", err) + } + }) + } +} diff --git a/internal/authz/repository/eventsourcing/spooler/spooler.go b/internal/authz/repository/eventsourcing/spooler/spooler.go new file mode 100644 index 0000000000..656721ed55 --- /dev/null +++ b/internal/authz/repository/eventsourcing/spooler/spooler.go @@ -0,0 +1,31 @@ +package spooler + +import ( + "database/sql" + sd "github.com/caos/zitadel/internal/config/systemdefaults" + + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/handler" + "github.com/caos/zitadel/internal/authz/repository/eventsourcing/view" + + "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/spooler" +) + +type SpoolerConfig struct { + BulkLimit uint64 + FailureCountUntilSkip uint64 + ConcurrentTasks int + Handlers handler.Configs +} + +func StartSpooler(c SpoolerConfig, es eventstore.Eventstore, view *view.View, sql *sql.DB, repos handler.EventstoreRepos, systemDefaults sd.SystemDefaults) *spooler.Spooler { + spoolerConfig := spooler.Config{ + Eventstore: es, + Locker: &locker{dbClient: sql}, + ConcurrentTasks: c.ConcurrentTasks, + ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, repos, systemDefaults), + } + spool := spoolerConfig.New() + spool.Start() + return spool +} diff --git a/internal/authz/repository/eventsourcing/view/application.go b/internal/authz/repository/eventsourcing/view/application.go new file mode 100644 index 0000000000..e99a01950f --- /dev/null +++ b/internal/authz/repository/eventsourcing/view/application.go @@ -0,0 +1,60 @@ +package view + +import ( + proj_model "github.com/caos/zitadel/internal/project/model" + "github.com/caos/zitadel/internal/project/repository/view" + "github.com/caos/zitadel/internal/project/repository/view/model" + global_view "github.com/caos/zitadel/internal/view" +) + +const ( + applicationTable = "authz.applications" +) + +func (v *View) ApplicationByID(appID string) (*model.ApplicationView, error) { + return view.ApplicationByID(v.Db, applicationTable, appID) +} + +func (v *View) ApplicationByOIDCClientID(clientID string) (*model.ApplicationView, error) { + return view.ApplicationByOIDCClientID(v.Db, applicationTable, clientID) +} + +func (v *View) ApplicationByProjecIDAndAppName(projectID, appName string) (*model.ApplicationView, error) { + return view.ApplicationByProjectIDAndAppName(v.Db, applicationTable, projectID, appName) +} + +func (v *View) SearchApplications(request *proj_model.ApplicationSearchRequest) ([]*model.ApplicationView, int, error) { + return view.SearchApplications(v.Db, applicationTable, request) +} + +func (v *View) PutApplication(project *model.ApplicationView) error { + err := view.PutApplication(v.Db, applicationTable, project) + if err != nil { + return err + } + return v.ProcessedApplicationSequence(project.Sequence) +} + +func (v *View) DeleteApplication(appID string, eventSequence uint64) error { + err := view.DeleteApplication(v.Db, applicationTable, appID) + if err != nil { + return nil + } + return v.ProcessedApplicationSequence(eventSequence) +} + +func (v *View) GetLatestApplicationSequence() (uint64, error) { + return v.latestSequence(applicationTable) +} + +func (v *View) ProcessedApplicationSequence(eventSequence uint64) error { + return v.saveCurrentSequence(applicationTable, eventSequence) +} + +func (v *View) GetLatestApplicationFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { + return v.latestFailedEvent(applicationTable, sequence) +} + +func (v *View) ProcessedApplicationFailedEvent(failedEvent *global_view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} diff --git a/internal/authz/repository/eventsourcing/view/error_event.go b/internal/authz/repository/eventsourcing/view/error_event.go new file mode 100644 index 0000000000..a6e8bb9927 --- /dev/null +++ b/internal/authz/repository/eventsourcing/view/error_event.go @@ -0,0 +1,17 @@ +package view + +import ( + "github.com/caos/zitadel/internal/view" +) + +const ( + errTable = "authz.failed_event" +) + +func (v *View) saveFailedEvent(failedEvent *view.FailedEvent) error { + return view.SaveFailedEvent(v.Db, errTable, failedEvent) +} + +func (v *View) latestFailedEvent(viewName string, sequence uint64) (*view.FailedEvent, error) { + return view.LatestFailedEvent(v.Db, errTable, viewName, sequence) +} diff --git a/internal/authz/repository/eventsourcing/view/sequence.go b/internal/authz/repository/eventsourcing/view/sequence.go new file mode 100644 index 0000000000..ddcfafbf62 --- /dev/null +++ b/internal/authz/repository/eventsourcing/view/sequence.go @@ -0,0 +1,17 @@ +package view + +import ( + "github.com/caos/zitadel/internal/view" +) + +const ( + sequencesTable = "authz.current_sequences" +) + +func (v *View) saveCurrentSequence(viewName string, sequence uint64) error { + return view.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence) +} + +func (v *View) latestSequence(viewName string) (uint64, error) { + return view.LatestSequence(v.Db, sequencesTable, viewName) +} diff --git a/internal/authz/repository/eventsourcing/view/token.go b/internal/authz/repository/eventsourcing/view/token.go new file mode 100644 index 0000000000..3bbc834b4e --- /dev/null +++ b/internal/authz/repository/eventsourcing/view/token.go @@ -0,0 +1,59 @@ +package view + +import ( + "github.com/caos/zitadel/internal/token/repository/view" + "github.com/caos/zitadel/internal/token/repository/view/model" + global_view "github.com/caos/zitadel/internal/view" +) + +const ( + tokenTable = "auth.tokens" +) + +func (v *View) TokenByID(tokenID string) (*model.Token, error) { + return view.TokenByID(v.Db, tokenTable, tokenID) +} + +func (v *View) IsTokenValid(tokenID string) (bool, error) { + return view.IsTokenValid(v.Db, tokenTable, tokenID) +} + +func (v *View) PutToken(token *model.Token) error { + err := view.PutToken(v.Db, tokenTable, token) + if err != nil { + return err + } + return v.ProcessedTokenSequence(token.Sequence) +} + +func (v *View) DeleteToken(tokenID string, eventSequence uint64) error { + err := view.DeleteToken(v.Db, tokenTable, tokenID) + if err != nil { + return nil + } + return v.ProcessedTokenSequence(eventSequence) +} + +func (v *View) DeleteSessionTokens(agentID, userID string, eventSequence uint64) error { + err := view.DeleteTokens(v.Db, tokenTable, agentID, userID) + if err != nil { + return nil + } + return v.ProcessedTokenSequence(eventSequence) +} + +func (v *View) GetLatestTokenSequence() (uint64, error) { + return v.latestSequence(tokenTable) +} + +func (v *View) ProcessedTokenSequence(eventSequence uint64) error { + return v.saveCurrentSequence(tokenTable, eventSequence) +} + +func (v *View) GetLatestTokenFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { + return v.latestFailedEvent(tokenTable, sequence) +} + +func (v *View) ProcessedTokenFailedEvent(failedEvent *global_view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} diff --git a/internal/authz/repository/eventsourcing/view/user_grant.go b/internal/authz/repository/eventsourcing/view/user_grant.go new file mode 100644 index 0000000000..f4b01adfd8 --- /dev/null +++ b/internal/authz/repository/eventsourcing/view/user_grant.go @@ -0,0 +1,64 @@ +package view + +import ( + grant_model "github.com/caos/zitadel/internal/usergrant/model" + "github.com/caos/zitadel/internal/usergrant/repository/view" + "github.com/caos/zitadel/internal/usergrant/repository/view/model" + global_view "github.com/caos/zitadel/internal/view" +) + +const ( + userGrantTable = "authz.user_grants" +) + +func (v *View) UserGrantByID(grantID string) (*model.UserGrantView, error) { + return view.UserGrantByID(v.Db, userGrantTable, grantID) +} + +func (v *View) UserGrantByIDs(resourceOwnerID, projectID, userID string) (*model.UserGrantView, error) { + return view.UserGrantByIDs(v.Db, userGrantTable, resourceOwnerID, projectID, userID) +} + +func (v *View) UserGrantsByUserID(userID string) ([]*model.UserGrantView, error) { + return view.UserGrantsByUserID(v.Db, userGrantTable, userID) +} + +func (v *View) UserGrantsByProjectID(projectID string) ([]*model.UserGrantView, error) { + return view.UserGrantsByProjectID(v.Db, userGrantTable, projectID) +} + +func (v *View) SearchUserGrants(request *grant_model.UserGrantSearchRequest) ([]*model.UserGrantView, int, error) { + return view.SearchUserGrants(v.Db, userGrantTable, request) +} + +func (v *View) PutUserGrant(grant *model.UserGrantView, sequence uint64) error { + err := view.PutUserGrant(v.Db, userGrantTable, grant) + if err != nil { + return err + } + return v.ProcessedUserGrantSequence(sequence) +} + +func (v *View) DeleteUserGrant(grantID string, eventSequence uint64) error { + err := view.DeleteUserGrant(v.Db, userGrantTable, grantID) + if err != nil { + return nil + } + return v.ProcessedUserGrantSequence(eventSequence) +} + +func (v *View) GetLatestUserGrantSequence() (uint64, error) { + return v.latestSequence(userGrantTable) +} + +func (v *View) ProcessedUserGrantSequence(eventSequence uint64) error { + return v.saveCurrentSequence(userGrantTable, eventSequence) +} + +func (v *View) GetLatestUserGrantFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { + return v.latestFailedEvent(userGrantTable, sequence) +} + +func (v *View) ProcessedUserGrantFailedEvent(failedEvent *global_view.FailedEvent) error { + return v.saveFailedEvent(failedEvent) +} diff --git a/internal/authz/repository/eventsourcing/view/view.go b/internal/authz/repository/eventsourcing/view/view.go new file mode 100644 index 0000000000..61799ad360 --- /dev/null +++ b/internal/authz/repository/eventsourcing/view/view.go @@ -0,0 +1,28 @@ +package view + +import ( + "database/sql" + "github.com/caos/zitadel/internal/id" + + "github.com/jinzhu/gorm" +) + +type View struct { + Db *gorm.DB + idGenerator id.Generator +} + +func StartView(sqlClient *sql.DB, idGenerator id.Generator) (*View, error) { + gorm, err := gorm.Open("postgres", sqlClient) + if err != nil { + return nil, err + } + return &View{ + Db: gorm, + idGenerator: idGenerator, + }, nil +} + +func (v *View) Health() (err error) { + return v.Db.DB().Ping() +} diff --git a/internal/authz/repository/iam.go b/internal/authz/repository/iam.go new file mode 100644 index 0000000000..0197c163c7 --- /dev/null +++ b/internal/authz/repository/iam.go @@ -0,0 +1,11 @@ +package repository + +import ( + "context" + "github.com/caos/zitadel/internal/iam/model" +) + +type IamRepository interface { + Health(ctx context.Context) error + IamByID(ctx context.Context, id string) (*model.Iam, error) +} diff --git a/internal/authz/repository/repository.go b/internal/authz/repository/repository.go new file mode 100644 index 0000000000..4b54764fd8 --- /dev/null +++ b/internal/authz/repository/repository.go @@ -0,0 +1,11 @@ +package repository + +import ( + "context" +) + +type Repository interface { + Health(context.Context) error + UserGrantRepository + IamRepository +} diff --git a/internal/authz/repository/token_verifier.go b/internal/authz/repository/token_verifier.go new file mode 100644 index 0000000000..e856178233 --- /dev/null +++ b/internal/authz/repository/token_verifier.go @@ -0,0 +1,10 @@ +package repository + +import ( + "context" +) + +type TokenVerifierRepository interface { + VerifyAccessToken(ctx context.Context, appName string) (string, string, string, error) + ProjectIDByClientID(ctx context.Context, clientID string) (string, error) +} diff --git a/internal/authz/repository/user_grant.go b/internal/authz/repository/user_grant.go new file mode 100644 index 0000000000..6a6619855b --- /dev/null +++ b/internal/authz/repository/user_grant.go @@ -0,0 +1,11 @@ +package repository + +import ( + "context" + "github.com/caos/zitadel/internal/api/auth" +) + +type UserGrantRepository interface { + ResolveGrants(ctx context.Context) (*auth.Grant, error) + SearchMyZitadelPermissions(ctx context.Context) ([]string, error) +} diff --git a/internal/crypto/crypto.go b/internal/crypto/crypto.go index 4dec2ecd09..e82ad6d039 100644 --- a/internal/crypto/crypto.go +++ b/internal/crypto/crypto.go @@ -1,6 +1,9 @@ package crypto import ( + "database/sql/driver" + "encoding/json" + "github.com/caos/zitadel/internal/errors" ) @@ -35,6 +38,23 @@ type CryptoValue struct { Crypted []byte } +func (c *CryptoValue) Value() (driver.Value, error) { + if c == nil { + return nil, nil + } + return json.Marshal(c) +} + +func (c *CryptoValue) Scan(src interface{}) error { + if b, ok := src.([]byte); ok { + return json.Unmarshal(b, c) + } + if s, ok := src.(string); ok { + return json.Unmarshal([]byte(s), c) + } + return nil +} + type CryptoType int func Crypt(value []byte, c Crypto) (*CryptoValue, error) { diff --git a/internal/crypto/rsa.go b/internal/crypto/rsa.go new file mode 100644 index 0000000000..b8295fbb29 --- /dev/null +++ b/internal/crypto/rsa.go @@ -0,0 +1,103 @@ +package crypto + +import ( + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "encoding/pem" +) + +func GenerateKeyPair(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) { + privkey, err := rsa.GenerateKey(rand.Reader, bits) + if err != nil { + return nil, nil, err + } + return privkey, &privkey.PublicKey, nil +} + +func GenerateEncryptedKeyPair(bits int, alg EncryptionAlgorithm) (*CryptoValue, *CryptoValue, error) { + privateKey, publicKey, err := GenerateKeyPair(bits) + if err != nil { + return nil, nil, err + } + return EncryptKeys(privateKey, publicKey, alg) +} + +func PrivateKeyToBytes(priv *rsa.PrivateKey) []byte { + return pem.EncodeToMemory( + &pem.Block{ + Type: "RSA PRIVATE KEY", + Bytes: x509.MarshalPKCS1PrivateKey(priv), + }, + ) +} + +func PublicKeyToBytes(pub *rsa.PublicKey) ([]byte, error) { + pubASN1, err := x509.MarshalPKIXPublicKey(pub) + if err != nil { + return nil, err + } + + pubBytes := pem.EncodeToMemory(&pem.Block{ + Type: "RSA PUBLIC KEY", + Bytes: pubASN1, + }) + + return pubBytes, nil +} + +func BytesToPrivateKey(priv []byte) (*rsa.PrivateKey, error) { + block, _ := pem.Decode(priv) + enc := x509.IsEncryptedPEMBlock(block) + b := block.Bytes + var err error + if enc { + b, err = x509.DecryptPEMBlock(block, nil) + if err != nil { + return nil, err + } + } + key, err := x509.ParsePKCS1PrivateKey(b) + if err != nil { + return nil, err + } + return key, nil +} + +func BytesToPublicKey(pub []byte) (*rsa.PublicKey, error) { + block, _ := pem.Decode(pub) + enc := x509.IsEncryptedPEMBlock(block) + b := block.Bytes + var err error + if enc { + b, err = x509.DecryptPEMBlock(block, nil) + if err != nil { + return nil, err + } + } + ifc, err := x509.ParsePKIXPublicKey(b) + if err != nil { + return nil, err + } + key, ok := ifc.(*rsa.PublicKey) + if !ok { + return nil, err + } + return key, nil +} + +func EncryptKeys(privateKey *rsa.PrivateKey, publicKey *rsa.PublicKey, alg EncryptionAlgorithm) (*CryptoValue, *CryptoValue, error) { + encryptedPrivateKey, err := Encrypt(PrivateKeyToBytes(privateKey), alg) + if err != nil { + return nil, nil, err + } + pubKey, err := PublicKeyToBytes(publicKey) + if err != nil { + return nil, nil, err + } + encryptedPublicKey, err := Encrypt(pubKey, alg) + if err != nil { + return nil, nil, err + } + return encryptedPrivateKey, encryptedPublicKey, nil +} diff --git a/internal/form/parser.go b/internal/form/parser.go new file mode 100644 index 0000000000..e0b4406bb1 --- /dev/null +++ b/internal/form/parser.go @@ -0,0 +1,27 @@ +package form + +import ( + "github.com/caos/zitadel/internal/errors" + "net/http" + + "github.com/gorilla/schema" +) + +type Parser struct { + decoder *schema.Decoder +} + +func NewParser() *Parser { + d := schema.NewDecoder() + d.IgnoreUnknownKeys(true) + return &Parser{d} +} + +func (p *Parser) Parse(r *http.Request, data interface{}) error { + err := r.ParseForm() + if err != nil { + return errors.ThrowInternal(err, "FORM-lCC9zI", "error parsing http form") + } + + return p.decoder.Decode(data, r.Form) +} diff --git a/internal/i18n/i18n.go b/internal/i18n/i18n.go new file mode 100644 index 0000000000..6c48c0fb04 --- /dev/null +++ b/internal/i18n/i18n.go @@ -0,0 +1,128 @@ +package i18n + +import ( + "encoding/json" + "io/ioutil" + "net/http" + "os" + + http_util "github.com/caos/zitadel/internal/api/http" + "github.com/caos/zitadel/internal/errors" + + "github.com/caos/logging" + "github.com/ghodss/yaml" + "github.com/nicksnyder/go-i18n/v2/i18n" + "golang.org/x/text/language" +) + +const ( + i18nPath = "/i18n" +) + +type Translator struct { + bundle *i18n.Bundle + cookieName string + cookieHandler *http_util.CookieHandler +} + +type TranslatorConfig struct { + DefaultLanguage language.Tag + CookieName string +} + +func NewTranslator(dir http.FileSystem, config TranslatorConfig) (*Translator, error) { + t := new(Translator) + var err error + t.bundle, err = newBundle(dir, config.DefaultLanguage) + if err != nil { + return nil, err + } + t.cookieHandler = http_util.NewCookieHandler() + t.cookieName = config.CookieName + return t, nil +} + +func newBundle(dir http.FileSystem, defaultLanguage language.Tag) (*i18n.Bundle, error) { + bundle := i18n.NewBundle(defaultLanguage) + bundle.RegisterUnmarshalFunc("yaml", yaml.Unmarshal) + bundle.RegisterUnmarshalFunc("json", json.Unmarshal) + i18nDir, err := dir.Open(i18nPath) + if err != nil { + return nil, errors.ThrowNotFound(err, "I18N-MnXRie", "path not found") + } + defer i18nDir.Close() + files, err := i18nDir.Readdir(0) + if err != nil { + return nil, errors.ThrowNotFound(err, "I18N-Gew23", "cannot read dir") + } + for _, file := range files { + if err := addFileToBundle(dir, bundle, file); err != nil { + return nil, errors.ThrowNotFound(err, "I18N-ZS2AW", "cannot append file to bundle") + } + } + return bundle, nil +} + +func addFileToBundle(dir http.FileSystem, bundle *i18n.Bundle, file os.FileInfo) error { + f, err := dir.Open("/i18n/" + file.Name()) + if err != nil { + return err + } + defer f.Close() + content, err := ioutil.ReadAll(f) + if err != nil { + return err + } + bundle.MustParseMessageFileBytes(content, file.Name()) + return nil +} + +func (t *Translator) LocalizeFromRequest(r *http.Request, id string, args map[string]interface{}) string { + s, err := t.localizerFromRequest(r).Localize(&i18n.LocalizeConfig{ + MessageID: id, + TemplateData: args, + }) + if err != nil { + logging.Log("I18N-MsF5sx").WithError(err).Warnf("missing translation") + return id + } + return s +} + +func (t *Translator) Localize(id string, args map[string]interface{}) string { + s, _ := t.localizer().Localize(&i18n.LocalizeConfig{ + MessageID: id, + TemplateData: args, + }) + return s +} + +func (t *Translator) Lang(r *http.Request) language.Tag { + matcher := language.NewMatcher(t.bundle.LanguageTags()) + tag, _ := language.MatchStrings(matcher, t.langsFromRequest(r)...) + return tag +} + +func (t *Translator) SetLangCookie(w http.ResponseWriter, lang language.Tag) { + t.cookieHandler.SetCookie(w, t.cookieName, lang.String()) +} + +func (t *Translator) localizerFromRequest(r *http.Request) *i18n.Localizer { + return t.localizer(t.langsFromRequest(r)...) +} + +func (t *Translator) localizer(langs ...string) *i18n.Localizer { + return i18n.NewLocalizer(t.bundle, langs...) +} + +func (t *Translator) langsFromRequest(r *http.Request) []string { + langs := make([]string, 0) + if r != nil { + lang, err := t.cookieHandler.GetCookieValue(r, t.cookieName) + if err == nil { + langs = append(langs, lang) + } + langs = append(langs, r.Header.Get("Accept-Language")) + } + return langs +} diff --git a/internal/iam/repository/eventsourcing/model/iam.go b/internal/iam/repository/eventsourcing/model/iam.go index 1cd98beed7..bc0226a20c 100644 --- a/internal/iam/repository/eventsourcing/model/iam.go +++ b/internal/iam/repository/eventsourcing/model/iam.go @@ -65,7 +65,7 @@ func (i *Iam) AppendEvent(event *es_models.Event) (err error) { i.SetUpDone = true case IamProjectSet, GlobalOrgSet: - err = i.setData(event) + err = i.SetData(event) case IamMemberAdded: err = i.appendAddMemberEvent(event) case IamMemberChanged: @@ -76,7 +76,7 @@ func (i *Iam) AppendEvent(event *es_models.Event) (err error) { return err } -func (i *Iam) setData(event *es_models.Event) error { +func (i *Iam) SetData(event *es_models.Event) error { i.ObjectRoot.AppendEvent(event) if err := json.Unmarshal(event.Data, i); err != nil { logging.Log("EVEN-9sie4").WithError(err).Error("could not unmarshal event data") diff --git a/internal/iam/repository/eventsourcing/model/iam_member.go b/internal/iam/repository/eventsourcing/model/iam_member.go index 4ba5a3456d..7fc23d2b18 100644 --- a/internal/iam/repository/eventsourcing/model/iam_member.go +++ b/internal/iam/repository/eventsourcing/model/iam_member.go @@ -56,7 +56,7 @@ func IamMemberToModel(member *IamMember) *model.IamMember { func (iam *Iam) appendAddMemberEvent(event *es_models.Event) error { member := &IamMember{} - err := member.setData(event) + err := member.SetData(event) if err != nil { return err } @@ -67,7 +67,7 @@ func (iam *Iam) appendAddMemberEvent(event *es_models.Event) error { func (iam *Iam) appendChangeMemberEvent(event *es_models.Event) error { member := &IamMember{} - err := member.setData(event) + err := member.SetData(event) if err != nil { return err } @@ -79,7 +79,7 @@ func (iam *Iam) appendChangeMemberEvent(event *es_models.Event) error { func (iam *Iam) appendRemoveMemberEvent(event *es_models.Event) error { member := &IamMember{} - err := member.setData(event) + err := member.SetData(event) if err != nil { return err } @@ -91,7 +91,7 @@ func (iam *Iam) appendRemoveMemberEvent(event *es_models.Event) error { return nil } -func (m *IamMember) setData(event *es_models.Event) error { +func (m *IamMember) SetData(event *es_models.Event) error { m.ObjectRoot.AppendEvent(event) if err := json.Unmarshal(event.Data, m); err != nil { logging.Log("EVEN-e4dkp").WithError(err).Error("could not unmarshal event data") diff --git a/internal/key/model/key.go b/internal/key/model/key.go new file mode 100644 index 0000000000..a0af401dc1 --- /dev/null +++ b/internal/key/model/key.go @@ -0,0 +1,46 @@ +package model + +import ( + "time" + + "github.com/caos/zitadel/internal/crypto" + es_models "github.com/caos/zitadel/internal/eventstore/models" +) + +type KeyPair struct { + es_models.ObjectRoot + + Usage KeyUsage + Algorithm string + PrivateKey *Key + PublicKey *Key +} + +type KeyUsage int32 + +const ( + KeyUsageSigning KeyUsage = iota +) + +func (u KeyUsage) String() string { + switch u { + case KeyUsageSigning: + return "sig" + } + return "" +} + +type Key struct { + Key *crypto.CryptoValue + Expiry time.Time +} + +func (k *KeyPair) IsValid() bool { + return k.Algorithm != "" && + k.PrivateKey != nil && k.PrivateKey.IsValid() && + k.PublicKey != nil && k.PublicKey.IsValid() +} + +func (k *Key) IsValid() bool { + return k.Key != nil +} diff --git a/internal/key/model/key_view.go b/internal/key/model/key_view.go new file mode 100644 index 0000000000..545f986158 --- /dev/null +++ b/internal/key/model/key_view.go @@ -0,0 +1,120 @@ +package model + +import ( + "time" + + "github.com/caos/zitadel/internal/crypto" + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/model" +) + +type KeyView struct { + ID string + Private bool + Expiry time.Time + Algorithm string + Usage KeyUsage + Key *crypto.CryptoValue + Sequence uint64 +} + +type SigningKey struct { + ID string + Algorithm string + Key interface{} +} + +type PublicKey struct { + ID string + Algorithm string + Usage KeyUsage + Key interface{} +} + +type KeySearchRequest struct { + Offset uint64 + Limit uint64 + SortingColumn KeySearchKey + Asc bool + Queries []*KeySearchQuery +} + +type KeySearchKey int32 + +const ( + KEYSEARCHKEY_UNSPECIFIED KeySearchKey = iota + KEYSEARCHKEY_ID + KEYSEARCHKEY_PRIVATE + KEYSEARCHKEY_EXPIRY + KEYSEARCHKEY_USAGE +) + +type KeySearchQuery struct { + Key KeySearchKey + Method model.SearchMethod + Value interface{} +} + +type KeySearchResponse struct { + Offset uint64 + Limit uint64 + TotalResult uint64 + Result []*KeyView +} + +func (r *KeySearchRequest) EnsureLimit(limit uint64) { + if r.Limit == 0 || r.Limit > limit { + r.Limit = limit + } +} + +func SigningKeyFromKeyView(key *KeyView, alg crypto.EncryptionAlgorithm) (*SigningKey, error) { + if key.Usage != KeyUsageSigning || !key.Private { + return nil, errors.ThrowInvalidArgument(nil, "MODEL-5HBdh", "key must be private signing key") + } + keyData, err := crypto.Decrypt(key.Key, alg) + if err != nil { + return nil, err + } + privateKey, err := crypto.BytesToPrivateKey(keyData) + if err != nil { + return nil, err + } + return &SigningKey{ + ID: key.ID, + Algorithm: key.Algorithm, + Key: privateKey, + }, nil +} + +func PublicKeysFromKeyView(keys []*KeyView, alg crypto.EncryptionAlgorithm) ([]*PublicKey, error) { + converted := make([]*PublicKey, len(keys)) + var err error + for i, key := range keys { + converted[i], err = PublicKeyFromKeyView(key, alg) + if err != nil { + return nil, err + } + } + return converted, nil + +} +func PublicKeyFromKeyView(key *KeyView, alg crypto.EncryptionAlgorithm) (*PublicKey, error) { + if key.Private { + return nil, errors.ThrowInvalidArgument(nil, "MODEL-dTZa2", "key must be public") + } + keyData, err := crypto.Decrypt(key.Key, alg) + if err != nil { + return nil, err + } + publicKey, err := crypto.BytesToPublicKey(keyData) + if err != nil { + return nil, err + } + return &PublicKey{ + ID: key.ID, + Algorithm: key.Algorithm, + Usage: key.Usage, + Key: publicKey, + }, nil +} diff --git a/internal/key/repository/eventsourcing/eventstore.go b/internal/key/repository/eventsourcing/eventstore.go new file mode 100644 index 0000000000..149480f5c8 --- /dev/null +++ b/internal/key/repository/eventsourcing/eventstore.go @@ -0,0 +1,84 @@ +package eventsourcing + +import ( + "context" + "time" + + "github.com/caos/zitadel/internal/config/types" + "github.com/caos/zitadel/internal/crypto" + caos_errs "github.com/caos/zitadel/internal/errors" + es_int "github.com/caos/zitadel/internal/eventstore" + "github.com/caos/zitadel/internal/eventstore/models" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + "github.com/caos/zitadel/internal/id" + key_model "github.com/caos/zitadel/internal/key/model" + "github.com/caos/zitadel/internal/key/repository/eventsourcing/model" +) + +type KeyEventstore struct { + es_int.Eventstore + keySize int + keyAlgorithm crypto.EncryptionAlgorithm + privateKeyLifetime time.Duration + publicKeyLifetime time.Duration + idGenerator id.Generator +} + +type KeyConfig struct { + Size int + PrivateKeyLifetime types.Duration + PublicKeyLifetime types.Duration + EncryptionConfig *crypto.KeyConfig + SigningKeyRotation types.Duration +} + +func StartKey(eventstore es_int.Eventstore, config KeyConfig, keyAlgorithm crypto.EncryptionAlgorithm, generator id.Generator) (*KeyEventstore, error) { + return &KeyEventstore{ + Eventstore: eventstore, + keySize: config.Size, + keyAlgorithm: keyAlgorithm, + privateKeyLifetime: config.PrivateKeyLifetime.Duration, + publicKeyLifetime: config.PublicKeyLifetime.Duration, + idGenerator: generator, + }, nil +} + +func (es *KeyEventstore) GenerateKeyPair(ctx context.Context, usage key_model.KeyUsage, algorithm string) (*key_model.KeyPair, error) { + privateKey, publicKey, err := crypto.GenerateEncryptedKeyPair(es.keySize, es.keyAlgorithm) + if err != nil { + return nil, err + } + privateKeyExp := time.Now().UTC().Add(es.privateKeyLifetime) + publicKeyExp := time.Now().UTC().Add(es.publicKeyLifetime) + return es.CreateKeyPair(ctx, &key_model.KeyPair{ + ObjectRoot: models.ObjectRoot{}, + Usage: usage, + Algorithm: algorithm, + PrivateKey: &key_model.Key{ + Key: privateKey, + Expiry: privateKeyExp, + }, + PublicKey: &key_model.Key{ + Key: publicKey, + Expiry: publicKeyExp, + }, + }) +} +func (es *KeyEventstore) CreateKeyPair(ctx context.Context, pair *key_model.KeyPair) (*key_model.KeyPair, error) { + if !pair.IsValid() { + return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-G34ga", "Name is required") + } + id, err := es.idGenerator.Next() + if err != nil { + return nil, err + } + pair.AggregateID = id + repoKey := model.KeyPairFromModel(pair) + + createAggregate := KeyPairCreateAggregate(es.AggregateCreator(), repoKey) + err = es_sdk.Push(ctx, es.PushAggregates, repoKey.AppendEvents, createAggregate) + if err != nil { + return nil, err + } + return model.KeyPairToModel(repoKey), nil +} diff --git a/internal/key/repository/eventsourcing/key.go b/internal/key/repository/eventsourcing/key.go new file mode 100644 index 0000000000..b23d38bfb4 --- /dev/null +++ b/internal/key/repository/eventsourcing/key.go @@ -0,0 +1,33 @@ +package eventsourcing + +import ( + "context" + + "github.com/caos/zitadel/internal/errors" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/key/repository/eventsourcing/model" +) + +func KeyPairQuery(latestSequence uint64) *es_models.SearchQuery { + return es_models.NewSearchQuery(). + AggregateTypeFilter(model.KeyPairAggregate). + LatestSequenceFilter(latestSequence) +} + +func KeyPairAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, pair *model.KeyPair) (*es_models.Aggregate, error) { + if pair == nil { + return nil, errors.ThrowPreconditionFailed(nil, "EVENT-d5HNJA", "existing key pair must not be nil") + } + return aggCreator.NewAggregate(ctx, pair.AggregateID, model.KeyPairAggregate, model.KeyPairVersion, pair.Sequence) +} + +func KeyPairCreateAggregate(aggCreator *es_models.AggregateCreator, pair *model.KeyPair) func(ctx context.Context) (*es_models.Aggregate, error) { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := KeyPairAggregate(ctx, aggCreator, pair) + if err != nil { + return nil, err + } + + return agg.AppendEvent(model.KeyPairAdded, pair) + } +} diff --git a/internal/key/repository/eventsourcing/model/key.go b/internal/key/repository/eventsourcing/model/key.go new file mode 100644 index 0000000000..50325612dd --- /dev/null +++ b/internal/key/repository/eventsourcing/model/key.go @@ -0,0 +1,90 @@ +package model + +import ( + "encoding/json" + "time" + + "github.com/caos/logging" + + "github.com/caos/zitadel/internal/crypto" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/key/model" +) + +const ( + KeyPairVersion = "v1" +) + +type KeyPair struct { + es_models.ObjectRoot + + Usage int32 `json:"usage"` + Algorithm string `json:"algorithm"` + PrivateKey *Key `json:"privateKey"` + PublicKey *Key `json:"publicKey"` +} + +type Key struct { + Key *crypto.CryptoValue `json:"key"` + Expiry time.Time `json:"expiry"` +} + +func KeyPairFromModel(pair *model.KeyPair) *KeyPair { + return &KeyPair{ + ObjectRoot: pair.ObjectRoot, + Usage: int32(pair.Usage), + Algorithm: pair.Algorithm, + PrivateKey: KeyFromModel(pair.PrivateKey), + PublicKey: KeyFromModel(pair.PublicKey), + } +} + +func KeyPairToModel(pair *KeyPair) *model.KeyPair { + return &model.KeyPair{ + ObjectRoot: pair.ObjectRoot, + Usage: model.KeyUsage(pair.Usage), + Algorithm: pair.Algorithm, + PrivateKey: KeyToModel(pair.PrivateKey), + PublicKey: KeyToModel(pair.PublicKey), + } +} + +func KeyFromModel(key *model.Key) *Key { + return &Key{ + Key: key.Key, + Expiry: key.Expiry, + } +} + +func KeyToModel(key *Key) *model.Key { + return &model.Key{ + Key: key.Key, + Expiry: key.Expiry, + } +} + +func (k *KeyPair) AppendEvents(events ...*es_models.Event) error { + for _, event := range events { + if err := k.AppendEvent(event); err != nil { + return err + } + } + return nil +} + +func (k *KeyPair) AppendEvent(event *es_models.Event) error { + k.ObjectRoot.AppendEvent(event) + switch event.Type { + case KeyPairAdded: + return k.AppendAddKeyPair(event) + } + return nil +} + +func (k *KeyPair) AppendAddKeyPair(event *es_models.Event) error { + if err := json.Unmarshal(event.Data, k); err != nil { + logging.Log("EVEN-Je92s").WithError(err).Error("could not unmarshal event data") + return err + } + return nil +} diff --git a/internal/key/repository/eventsourcing/model/types.go b/internal/key/repository/eventsourcing/model/types.go new file mode 100644 index 0000000000..2a7975ec04 --- /dev/null +++ b/internal/key/repository/eventsourcing/model/types.go @@ -0,0 +1,9 @@ +package model + +import "github.com/caos/zitadel/internal/eventstore/models" + +const ( + KeyPairAggregate models.AggregateType = "key_pair" + + KeyPairAdded models.EventType = "key_pair.added" +) diff --git a/internal/key/repository/view/key.go b/internal/key/repository/view/key.go new file mode 100644 index 0000000000..482ddf9370 --- /dev/null +++ b/internal/key/repository/view/key.go @@ -0,0 +1,70 @@ +package view + +import ( + "time" + + "github.com/jinzhu/gorm" + + key_model "github.com/caos/zitadel/internal/key/model" + "github.com/caos/zitadel/internal/key/repository/view/model" + global_model "github.com/caos/zitadel/internal/model" + "github.com/caos/zitadel/internal/view" +) + +func KeyByIDAndType(db *gorm.DB, table, keyID string, private bool) (*model.KeyView, error) { + key := new(model.KeyView) + query := view.PrepareGetByQuery(table, + model.KeySearchQuery{Key: key_model.KEYSEARCHKEY_ID, Method: global_model.SEARCHMETHOD_EQUALS, Value: keyID}, + model.KeySearchQuery{Key: key_model.KEYSEARCHKEY_PRIVATE, Method: global_model.SEARCHMETHOD_EQUALS, Value: private}, + ) + err := query(db, key) + return key, err +} + +func GetSigningKey(db *gorm.DB, table string) (*model.KeyView, error) { + key := new(model.KeyView) + query := view.PrepareGetByQuery(table, + model.KeySearchQuery{Key: key_model.KEYSEARCHKEY_PRIVATE, Method: global_model.SEARCHMETHOD_EQUALS, Value: true}, + model.KeySearchQuery{Key: key_model.KEYSEARCHKEY_USAGE, Method: global_model.SEARCHMETHOD_EQUALS, Value: key_model.KeyUsageSigning}, + model.KeySearchQuery{Key: key_model.KEYSEARCHKEY_EXPIRY, Method: global_model.SEARCHMETHOD_GREATER_THAN, Value: time.Now().UTC()}, + ) + err := query(db, key) + return key, err +} + +func GetActivePublicKeys(db *gorm.DB, table string) ([]*model.KeyView, error) { + keys := make([]*model.KeyView, 0) + query := view.PrepareSearchQuery(table, + model.KeySearchRequest{ + Queries: []*key_model.KeySearchQuery{ + {Key: key_model.KEYSEARCHKEY_PRIVATE, Method: global_model.SEARCHMETHOD_EQUALS, Value: false}, + {Key: key_model.KEYSEARCHKEY_USAGE, Method: global_model.SEARCHMETHOD_EQUALS, Value: key_model.KeyUsageSigning}, + {Key: key_model.KEYSEARCHKEY_EXPIRY, Method: global_model.SEARCHMETHOD_GREATER_THAN, Value: time.Now().UTC()}, + }, + }, + ) + _, err := query(db, &keys) + return keys, err +} + +func PutKeys(db *gorm.DB, table string, privateKey, publicKey *model.KeyView) error { + save := view.PrepareSave(table) + err := save(db, privateKey) + if err != nil { + return err + } + return save(db, publicKey) +} + +func DeleteKey(db *gorm.DB, table, keyID string, private bool) error { + delete := view.PrepareDeleteByKeys(table, + view.Key{Key: model.KeySearchKey(key_model.KEYSEARCHKEY_ID), Value: keyID}, + view.Key{Key: model.KeySearchKey(key_model.KEYSEARCHKEY_PRIVATE), Value: private}, + ) + return delete(db) +} + +func DeleteKeyPair(db *gorm.DB, table, keyID string) error { + delete := view.PrepareDeleteByKey(table, model.KeySearchKey(key_model.KEYSEARCHKEY_ID), keyID) + return delete(db) +} diff --git a/internal/key/repository/view/model/key.go b/internal/key/repository/view/model/key.go new file mode 100644 index 0000000000..8cae30b6ae --- /dev/null +++ b/internal/key/repository/view/model/key.go @@ -0,0 +1,88 @@ +package model + +import ( + "database/sql" + "encoding/json" + "time" + + "github.com/caos/logging" + + "github.com/caos/zitadel/internal/crypto" + caos_errs "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/key/model" + es_model "github.com/caos/zitadel/internal/key/repository/eventsourcing/model" +) + +const ( + KeyKeyID = "id" + KeyPrivate = "private" + KeyUsage = "usage" + KeyAlgorithm = "algorithm" + KeyExpiry = "expiry" +) + +type KeyView struct { + ID string `json:"-" gorm:"column:id;primary_key"` + Private sql.NullBool `json:"-" gorm:"column:private;primary_key"` + Expiry time.Time `json:"-" gorm:"column:expiry"` + Algorithm string `json:"-" gorm:"column:algorithm"` + Usage int32 `json:"-" gorm:"column:usage"` + Key *crypto.CryptoValue `json:"-" gorm:"column:key"` + Sequence uint64 `json:"-" gorm:"column:sequence"` +} + +func KeysFromPairEvent(event *models.Event) (*KeyView, *KeyView, error) { + pair := new(es_model.KeyPair) + if err := json.Unmarshal(event.Data, pair); err != nil { + logging.Log("MODEL-s3Ga1").WithError(err).Error("could not unmarshal event data") + return nil, nil, caos_errs.ThrowInternal(nil, "MODEL-G3haa", "could not unmarshal data") + } + privateKey := &KeyView{ + ID: event.AggregateID, + Private: sql.NullBool{Bool: true, Valid: true}, + Expiry: pair.PrivateKey.Expiry, + Algorithm: pair.Algorithm, + Usage: pair.Usage, + Key: pair.PrivateKey.Key, + Sequence: pair.Sequence, + } + publicKey := &KeyView{ + ID: event.AggregateID, + Private: sql.NullBool{Bool: false, Valid: true}, + Expiry: pair.PublicKey.Expiry, + Algorithm: pair.Algorithm, + Usage: pair.Usage, + Key: pair.PublicKey.Key, + Sequence: pair.Sequence, + } + return privateKey, publicKey, nil +} + +func KeyViewsToModel(keys []*KeyView) []*model.KeyView { + converted := make([]*model.KeyView, len(keys)) + for i, key := range keys { + converted[i] = KeyViewToModel(key) + } + return converted +} + +func KeyViewToModel(key *KeyView) *model.KeyView { + return &model.KeyView{ + ID: key.ID, + Private: key.Private.Bool, + Expiry: key.Expiry, + Algorithm: key.Algorithm, + Usage: model.KeyUsage(key.Usage), + Key: key.Key, + Sequence: key.Sequence, + } +} + +func (k *KeyView) setData(event *models.Event) error { + if err := json.Unmarshal(event.Data, k); err != nil { + logging.Log("MODEL-4ag41").WithError(err).Error("could not unmarshal event data") + return caos_errs.ThrowInternal(nil, "MODEL-GFQ31", "could not unmarshal data") + } + return nil +} diff --git a/internal/key/repository/view/model/key_query.go b/internal/key/repository/view/model/key_query.go new file mode 100644 index 0000000000..68764231e5 --- /dev/null +++ b/internal/key/repository/view/model/key_query.go @@ -0,0 +1,65 @@ +package model + +import ( + key_model "github.com/caos/zitadel/internal/key/model" + global_model "github.com/caos/zitadel/internal/model" + "github.com/caos/zitadel/internal/view" +) + +type KeySearchRequest key_model.KeySearchRequest +type KeySearchQuery key_model.KeySearchQuery +type KeySearchKey key_model.KeySearchKey + +func (req KeySearchRequest) GetLimit() uint64 { + return req.Limit +} + +func (req KeySearchRequest) GetOffset() uint64 { + return req.Offset +} + +func (req KeySearchRequest) GetSortingColumn() view.ColumnKey { + if req.SortingColumn == key_model.KEYSEARCHKEY_UNSPECIFIED { + return nil + } + return KeySearchKey(req.SortingColumn) +} + +func (req KeySearchRequest) GetAsc() bool { + return req.Asc +} + +func (req KeySearchRequest) GetQueries() []view.SearchQuery { + result := make([]view.SearchQuery, len(req.Queries)) + for i, q := range req.Queries { + result[i] = KeySearchQuery{Key: q.Key, Value: q.Value, Method: q.Method} + } + return result +} + +func (req KeySearchQuery) GetKey() view.ColumnKey { + return KeySearchKey(req.Key) +} + +func (req KeySearchQuery) GetMethod() global_model.SearchMethod { + return req.Method +} + +func (req KeySearchQuery) GetValue() interface{} { + return req.Value +} + +func (key KeySearchKey) ToColumnName() string { + switch key_model.KeySearchKey(key) { + case key_model.KEYSEARCHKEY_ID: + return KeyKeyID + case key_model.KEYSEARCHKEY_PRIVATE: + return KeyPrivate + case key_model.KEYSEARCHKEY_USAGE: + return KeyUsage + case key_model.KEYSEARCHKEY_EXPIRY: + return KeyExpiry + default: + return "" + } +} diff --git a/internal/login/config.go b/internal/login/config.go deleted file mode 100644 index 7912985764..0000000000 --- a/internal/login/config.go +++ /dev/null @@ -1,4 +0,0 @@ -package login - -type Config struct { -} diff --git a/internal/login/handler/auth_request.go b/internal/login/handler/auth_request.go new file mode 100644 index 0000000000..885be90da0 --- /dev/null +++ b/internal/login/handler/auth_request.go @@ -0,0 +1,27 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + queryAuthRequestID = "authRequestID" +) + +func (l *Login) getAuthRequest(r *http.Request) (*model.AuthRequest, error) { + authRequestID := r.FormValue(queryAuthRequestID) + if authRequestID == "" { + return nil, nil + } + return l.authRepo.AuthRequestByID(r.Context(), authRequestID) +} + +func (l *Login) getAuthRequestAndParseData(r *http.Request, data interface{}) (*model.AuthRequest, error) { + authReq, err := l.getAuthRequest(r) + if err != nil { + return nil, err + } + err = l.parser.Parse(r, data) + return authReq, err +} diff --git a/internal/login/handler/callback_handler.go b/internal/login/handler/callback_handler.go new file mode 100644 index 0000000000..9f4b80fbcf --- /dev/null +++ b/internal/login/handler/callback_handler.go @@ -0,0 +1,11 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +func (l *Login) redirectToCallback(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + callback := l.oidcAuthCallbackURL + authReq.ID + http.Redirect(w, r, callback, http.StatusFound) +} diff --git a/internal/login/handler/change_password_handler.go b/internal/login/handler/change_password_handler.go new file mode 100644 index 0000000000..bb39181a12 --- /dev/null +++ b/internal/login/handler/change_password_handler.go @@ -0,0 +1,52 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + tmplChangePassword = "changepassword" + tmplChangePasswordDone = "changepassworddone" +) + +type changePasswordData struct { + OldPassword string `schema:"old_password"` + NewPassword string `schema:"new_password"` +} + +func (l *Login) handleChangePassword(w http.ResponseWriter, r *http.Request) { + data := new(changePasswordData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + err = l.authRepo.ChangePassword(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.OldPassword, data.NewPassword) + if err != nil { + l.renderChangePassword(w, r, authReq, err) + return + } + l.renderChangePasswordDone(w, r, authReq) +} + +func (l *Login) renderChangePassword(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + data := userData{ + baseData: l.getBaseData(r, authReq, "Change Password", errType, errMessage), + UserName: authReq.UserName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangePassword], data, nil) +} + +func (l *Login) renderChangePasswordDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + var errType, errMessage string + data := userData{ + baseData: l.getBaseData(r, authReq, "Password Change Done", errType, errMessage), + UserName: authReq.UserName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplChangePasswordDone], data, nil) +} diff --git a/internal/login/handler/health_handler.go b/internal/login/handler/health_handler.go new file mode 100644 index 0000000000..42ce77174f --- /dev/null +++ b/internal/login/handler/health_handler.go @@ -0,0 +1,18 @@ +package handler + +import ( + "net/http" +) + +func (l *Login) handleHealthz(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("OK")) +} + +func (l *Login) handleReadiness(w http.ResponseWriter, r *http.Request) { + err := l.authRepo.Health(r.Context()) + if err != nil { + http.Error(w, "not ready", http.StatusInternalServerError) + return + } + w.Write([]byte("OK")) +} diff --git a/internal/login/handler/init_password_handler.go b/internal/login/handler/init_password_handler.go new file mode 100644 index 0000000000..f6a61717a8 --- /dev/null +++ b/internal/login/handler/init_password_handler.go @@ -0,0 +1,97 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "github.com/caos/zitadel/internal/errors" + "net/http" +) + +const ( + queryInitPWCode = "code" + queryInitPWUserID = "userID" + + tmplInitPassword = "initpassword" + tmplInitPasswordDone = "initpassworddone" +) + +type initPasswordFormData struct { + Code string `schema:"code"` + Password string `schema:"password"` + PasswordConfirm string `schema:"passwordconfirm"` + UserID string `schema:"userID"` + Resend bool `schema:"resend"` +} + +type initPasswordData struct { + baseData + Code string + UserID string +} + +func (l *Login) handleInitPassword(w http.ResponseWriter, r *http.Request) { + userID := r.FormValue(queryInitPWUserID) + code := r.FormValue(queryInitPWCode) + l.renderInitPassword(w, r, nil, userID, code, nil) +} + +func (l *Login) handleInitPasswordCheck(w http.ResponseWriter, r *http.Request) { + data := new(initPasswordFormData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + + if data.Resend { + l.resendPasswordSet(w, r, authReq) + return + } + l.checkPWCode(w, r, authReq, data, nil) +} + +func (l *Login) checkPWCode(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *initPasswordFormData, err error) { + if data.Password != data.PasswordConfirm { + err := errors.ThrowInvalidArgument(nil, "VIEW-KaGue", "passwords dont match") + l.renderInitPassword(w, r, authReq, data.UserID, data.Code, err) + return + } + userOrg := login + if authReq != nil { + userOrg = authReq.UserOrgID + } + err = l.authRepo.SetPassword(setContext(r.Context(), userOrg), data.UserID, data.Code, data.Password) + if err != nil { + l.renderInitPassword(w, r, authReq, data.UserID, "", err) + return + } + l.renderInitPasswordDone(w, r, authReq) +} + +func (l *Login) resendPasswordSet(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + err := l.authRepo.RequestPasswordReset(r.Context(), authReq.UserName) + l.renderInitPassword(w, r, authReq, authReq.UserID, "", err) +} + +func (l *Login) renderInitPassword(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID, code string, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + if userID == "" && authReq != nil { + userID = authReq.UserID + } + data := initPasswordData{ + baseData: l.getBaseData(r, authReq, "Init Password", errType, errMessage), + UserID: userID, + Code: code, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitPassword], data, nil) +} + +func (l *Login) renderInitPasswordDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + data := userData{ + baseData: l.getBaseData(r, authReq, "Password Init Done", "", ""), + UserName: authReq.UserName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitPasswordDone], data, nil) +} diff --git a/internal/login/handler/init_user_handler.go b/internal/login/handler/init_user_handler.go new file mode 100644 index 0000000000..b6d89f281a --- /dev/null +++ b/internal/login/handler/init_user_handler.go @@ -0,0 +1,105 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + caos_errs "github.com/caos/zitadel/internal/errors" + "net/http" +) + +const ( + queryInitUserCode = "code" + queryInitUserUserID = "userID" + + tmplInitUser = "inituser" + tmplInitUserDone = "inituserdone" +) + +type initUserFormData struct { + Code string `schema:"code"` + Password string `schema:"password"` + PasswordConfirm string `schema:"passwordconfirm"` + UserID string `schema:"userID"` + Resend bool `schema:"resend"` +} + +type initUserData struct { + baseData + Code string + UserID string +} + +func (l *Login) handleInitUser(w http.ResponseWriter, r *http.Request) { + userID := r.FormValue(queryInitUserUserID) + code := r.FormValue(queryInitUserCode) + l.renderInitUser(w, r, nil, userID, code, nil) +} + +func (l *Login) handleInitUserCheck(w http.ResponseWriter, r *http.Request) { + data := new(initUserFormData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, nil, err) + return + } + + if data.Resend { + l.resendUserInit(w, r, authReq, data.UserID) + return + } + l.checkUserInitCode(w, r, authReq, data, nil) +} + +func (l *Login) checkUserInitCode(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *initUserFormData, err error) { + if data.Password != data.PasswordConfirm { + err := caos_errs.ThrowInvalidArgument(nil, "VIEW-fsdfd", "passwords dont match") + l.renderInitUser(w, r, nil, data.UserID, data.Code, err) + return + } + userOrgID := login + if authReq != nil { + userOrgID = authReq.UserOrgID + } + err = l.authRepo.VerifyInitCode(setContext(r.Context(), userOrgID), data.UserID, data.Code, data.Password) + if err != nil { + l.renderInitUser(w, r, nil, data.UserID, "", err) + return + } + l.renderInitUserDone(w, r, nil) +} + +func (l *Login) resendUserInit(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID string) { + userOrgID := login + if authReq != nil { + userOrgID = authReq.UserOrgID + } + err := l.authRepo.ResendInitVerificationMail(setContext(r.Context(), userOrgID), userID) + l.renderInitUser(w, r, authReq, userID, "", err) +} + +func (l *Login) renderInitUser(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID, code string, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + if authReq != nil { + userID = authReq.UserID + } + data := initUserData{ + baseData: l.getBaseData(r, nil, "Init User", errType, errMessage), + UserID: userID, + Code: code, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitUser], data, nil) +} + +func (l *Login) renderInitUserDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + var errType, errMessage, userName string + if authReq != nil { + userName = authReq.UserName + } + data := userData{ + baseData: l.getBaseData(r, authReq, "User Init Done", errType, errMessage), + UserName: userName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplInitUserDone], data, nil) +} diff --git a/internal/login/handler/login.go b/internal/login/handler/login.go new file mode 100644 index 0000000000..4144adb490 --- /dev/null +++ b/internal/login/handler/login.go @@ -0,0 +1,92 @@ +package handler + +import ( + "context" + "net" + "net/http" + + "github.com/caos/logging" + "github.com/gorilla/mux" + "github.com/rakyll/statik/fs" + "golang.org/x/text/language" + + "github.com/caos/zitadel/internal/api/auth" + "github.com/caos/zitadel/internal/auth/repository/eventsourcing" + "github.com/caos/zitadel/internal/form" + + _ "github.com/caos/zitadel/internal/login/statik" +) + +type Login struct { + endpoint string + router *mux.Router + renderer *Renderer + parser *form.Parser + authRepo *eventsourcing.EsRepository + zitadelURL string + oidcAuthCallbackURL string +} + +type Config struct { + Port string + OidcAuthCallbackURL string + ZitadelURL string + LanguageCookieName string + DefaultLanguage language.Tag +} + +const ( + login = "LOGIN" +) + +func StartLogin(ctx context.Context, config Config, authRepo *eventsourcing.EsRepository) { + login := &Login{ + endpoint: config.Port, + oidcAuthCallbackURL: config.OidcAuthCallbackURL, + zitadelURL: config.ZitadelURL, + authRepo: authRepo, + } + statikFS, err := fs.NewWithNamespace("login") + logging.Log("CONFI-7usEW").OnError(err).Panic("unable to start listener") + + login.router = CreateRouter(login, statikFS) + login.renderer = CreateRenderer(statikFS, config.LanguageCookieName, config.DefaultLanguage) + login.parser = form.NewParser() + login.Listen(ctx) +} + +func (l *Login) Listen(ctx context.Context) { + if l.endpoint == "" { + l.endpoint = ":80" + } else { + l.endpoint = ":" + l.endpoint + } + + defer logging.LogWithFields("APP-xUZof", "port", l.endpoint).Info("html is listening") + httpListener, err := net.Listen("tcp", l.endpoint) + logging.Log("CONFI-W5q2O").OnError(err).Panic("unable to start listener") + + httpServer := &http.Server{ + Handler: l.router, + } + + go func() { + <-ctx.Done() + if err = httpServer.Shutdown(ctx); err != nil { + logging.Log("APP-mJKTv").WithError(err) + } + }() + + go func() { + err := httpServer.Serve(httpListener) + logging.Log("APP-oSklt").OnError(err).Panic("unable to start listener") + }() +} + +func setContext(ctx context.Context, resourceOwner string) context.Context { + data := auth.CtxData{ + UserID: login, + OrgID: resourceOwner, + } + return auth.SetCtxData(ctx, data) +} diff --git a/internal/login/handler/login_handler.go b/internal/login/handler/login_handler.go new file mode 100644 index 0000000000..e009426383 --- /dev/null +++ b/internal/login/handler/login_handler.go @@ -0,0 +1,63 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + tmplLogin = "login" +) + +type loginData struct { + UserName string `schema:"username"` +} + +func (l *Login) handleLogin(w http.ResponseWriter, r *http.Request) { + authReq, err := l.getAuthRequest(r) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + if authReq == nil { + http.Redirect(w, r, l.zitadelURL, http.StatusFound) + return + } + l.renderNextStep(w, r, authReq) +} + +func (l *Login) handleUsername(w http.ResponseWriter, r *http.Request) { + authSession, err := l.getAuthRequest(r) + if err != nil { + l.renderError(w, r, authSession, err) + return + } + l.renderLogin(w, r, authSession, nil) +} + +func (l *Login) handleUsernameCheck(w http.ResponseWriter, r *http.Request) { + data := new(loginData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + err = l.authRepo.CheckUsername(r.Context(), authReq.ID, data.UserName) + if err != nil { + l.renderLogin(w, r, authReq, err) + return + } + l.renderNextStep(w, r, authReq) +} + +func (l *Login) renderLogin(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + data := userData{ + baseData: l.getBaseData(r, authReq, "Login", errType, errMessage), + UserName: authReq.UserName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplLogin], data, nil) +} diff --git a/internal/login/handler/logout_handler.go b/internal/login/handler/logout_handler.go new file mode 100644 index 0000000000..19cb8c94dd --- /dev/null +++ b/internal/login/handler/logout_handler.go @@ -0,0 +1,20 @@ +package handler + +import ( + "net/http" +) + +const ( + tmplLogoutDone = "logoutdone" +) + +func (l *Login) handleLogoutDone(w http.ResponseWriter, r *http.Request) { + l.renderLogoutDone(w, r) +} + +func (l *Login) renderLogoutDone(w http.ResponseWriter, r *http.Request) { + data := userData{ + baseData: l.getBaseData(r, nil, "Logout Done", "", ""), + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplLogoutDone], data, nil) +} diff --git a/internal/login/handler/mail_verify_handler.go b/internal/login/handler/mail_verify_handler.go new file mode 100644 index 0000000000..ba99a56e50 --- /dev/null +++ b/internal/login/handler/mail_verify_handler.go @@ -0,0 +1,90 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + queryCode = "code" + queryUserID = "userID" + + tmplMailVerification = "mail_verification" + tmplMailVerified = "mail_verified" +) + +type mailVerificationFormData struct { + Code string `schema:"code"` + UserID string `schema:"userID"` + Resend bool `schema:"resend"` +} + +type mailVerificationData struct { + baseData + UserID string +} + +func (l *Login) handleMailVerification(w http.ResponseWriter, r *http.Request) { + userID := r.FormValue(queryUserID) + code := r.FormValue(queryCode) + if code != "" { + l.checkMailCode(w, r, nil, userID, code) + return + } + l.renderMailVerification(w, r, nil, userID, nil) +} + +func (l *Login) handleMailVerificationCheck(w http.ResponseWriter, r *http.Request) { + data := new(mailVerificationFormData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + if !data.Resend { + l.checkMailCode(w, r, authReq, data.UserID, data.Code) + return + } + userOrg := login + if authReq != nil { + userOrg = authReq.UserOrgID + } + err = l.authRepo.ResendEmailVerificationMail(setContext(r.Context(), userOrg), data.UserID) + l.renderMailVerification(w, r, authReq, data.UserID, err) +} + +func (l *Login) checkMailCode(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID, code string) { + userOrg := login + if authReq != nil { + userID = authReq.UserID + userOrg = authReq.UserOrgID + } + err := l.authRepo.VerifyEmail(setContext(r.Context(), userOrg), userID, code) + if err != nil { + l.renderMailVerification(w, r, authReq, userID, err) + return + } + l.renderMailVerified(w, r, authReq) +} + +func (l *Login) renderMailVerification(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, userID string, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + if userID == "" { + userID = authReq.UserID + } + data := mailVerificationData{ + baseData: l.getBaseData(r, authReq, "Mail Verification", errType, errMessage), + UserID: userID, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMailVerification], data, nil) +} + +func (l *Login) renderMailVerified(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + data := mailVerificationData{ + baseData: l.getBaseData(r, authReq, "Mail Verified", "", ""), + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMailVerified], data, nil) +} diff --git a/internal/login/handler/mfa_init_done_handler.go b/internal/login/handler/mfa_init_done_handler.go new file mode 100644 index 0000000000..b88d7838e4 --- /dev/null +++ b/internal/login/handler/mfa_init_done_handler.go @@ -0,0 +1,20 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + tmplMfaInitDone = "mfainitdone" +) + +type mfaInitDoneData struct { +} + +func (l *Login) renderMfaInitDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaDoneData) { + var errType, errMessage string + data.baseData = l.getBaseData(r, authReq, "Mfa Init Done", errType, errMessage) + data.UserName = authReq.UserName + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMfaInitDone], data, nil) +} diff --git a/internal/login/handler/mfa_init_verify_handler.go b/internal/login/handler/mfa_init_verify_handler.go new file mode 100644 index 0000000000..53a9fea609 --- /dev/null +++ b/internal/login/handler/mfa_init_verify_handler.go @@ -0,0 +1,95 @@ +package handler + +import ( + "bytes" + "net/http" + + "github.com/aaronarduino/goqrsvg" + svg "github.com/ajstarks/svgo" + "github.com/boombuler/barcode/qr" + "github.com/caos/zitadel/internal/auth_request/model" +) + +const ( + tmplMfaInitVerify = "mfainitverify" +) + +type mfaInitVerifyData struct { + MfaType model.MfaType `schema:"mfaType"` + Code string `schema:"code"` + URL string `schema:"url"` + Secret string `schema:"secret"` +} + +func (l *Login) handleMfaInitVerify(w http.ResponseWriter, r *http.Request) { + data := new(mfaInitVerifyData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + var verifyData *mfaVerifyData + switch data.MfaType { + case model.MfaTypeOTP: + verifyData = l.handleOtpVerify(w, r, authReq, data) + } + + if verifyData != nil { + l.renderMfaInitVerify(w, r, authReq, verifyData, err) + return + } + + done := &mfaDoneData{ + MfaType: data.MfaType, + } + l.renderMfaInitDone(w, r, authReq, done) +} + +func (l *Login) handleOtpVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaInitVerifyData) *mfaVerifyData { + err := l.authRepo.VerifyMfaOTPSetup(setContext(r.Context(), authReq.UserOrgID), authReq.UserID, data.Code) + if err == nil { + return nil + } + mfadata := &mfaVerifyData{ + MfaType: data.MfaType, + otpData: otpData{ + Secret: data.Secret, + Url: data.URL, + }, + } + + return mfadata +} + +func (l *Login) renderMfaInitVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaVerifyData, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + data.baseData = l.getBaseData(r, authReq, "Mfa Init Verify", errType, errMessage) + data.UserName = authReq.UserName + if data.MfaType == model.MfaTypeOTP { + code, err := generateQrCode(data.otpData.Url) + if err == nil { + data.otpData.QrCode = code + } + } + + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMfaInitVerify], data, nil) +} + +func generateQrCode(url string) (string, error) { + var b bytes.Buffer + s := svg.New(&b) + + qrCode, err := qr.Encode(url, qr.M, qr.Auto) + if err != nil { + return "", err + } + qs := goqrsvg.NewQrSVG(qrCode, 5) + qs.StartQrSVG(s) + qs.WriteQrSVG(s) + + s.End() + return string(b.Bytes()), nil +} diff --git a/internal/login/handler/mfa_prompt_handler.go b/internal/login/handler/mfa_prompt_handler.go new file mode 100644 index 0000000000..863bea60e3 --- /dev/null +++ b/internal/login/handler/mfa_prompt_handler.go @@ -0,0 +1,88 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + caos_errs "github.com/caos/zitadel/internal/errors" + "net/http" +) + +const ( + tmplMfaPrompt = "mfaprompt" +) + +type mfaPromptData struct { + MfaProvider model.MfaType `schema:"provider"` + Skip bool `schema:"skip"` +} + +func (l *Login) handleMfaPrompt(w http.ResponseWriter, r *http.Request) { + data := new(mfaPromptData) + authSession, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authSession, err) + return + } + if !data.Skip { + mfaVerifyData := new(mfaVerifyData) + mfaVerifyData.MfaType = data.MfaProvider + l.handleMfaCreation(w, r, authSession, mfaVerifyData) + return + } + err = l.authRepo.SkipMfaInit(setContext(r.Context(), authSession.UserOrgID), authSession.UserID) + if err != nil { + l.renderError(w, r, authSession, err) + return + } + l.handleLogin(w, r) +} + +func (l *Login) renderMfaPrompt(w http.ResponseWriter, r *http.Request, authSession *model.AuthRequest, mfaPromptData *model.MfaPromptStep, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + data := mfaData{ + baseData: l.getBaseData(r, authSession, "Mfa Prompt", errType, errMessage), + UserName: authSession.UserName, + } + + if mfaPromptData == nil { + l.renderError(w, r, authSession, caos_errs.ThrowPreconditionFailed(nil, "APP-XU0tj", "No available mfa providers")) + return + } + + data.MfaProviders = mfaPromptData.MfaProviders + data.MfaRequired = mfaPromptData.Required + + if len(mfaPromptData.MfaProviders) == 1 && mfaPromptData.Required { + data := &mfaVerifyData{ + MfaType: mfaPromptData.MfaProviders[0], + } + l.handleMfaCreation(w, r, authSession, data) + return + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMfaPrompt], data, nil) +} + +func (l *Login) handleMfaCreation(w http.ResponseWriter, r *http.Request, authSession *model.AuthRequest, data *mfaVerifyData) { + switch data.MfaType { + case model.MfaTypeOTP: + l.handleOtpCreation(w, r, authSession, data) + return + } + l.renderError(w, r, authSession, caos_errs.ThrowPreconditionFailed(nil, "APP-Or3HO", "No available mfa providers")) +} + +func (l *Login) handleOtpCreation(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, data *mfaVerifyData) { + otp, err := l.authRepo.AddMfaOTP(setContext(r.Context(), authReq.UserOrgID), authReq.UserID) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + + data.otpData = otpData{ + Secret: otp.SecretString, + Url: otp.Url, + } + l.renderMfaInitVerify(w, r, authReq, data, nil) +} diff --git a/internal/login/handler/mfa_verify_handler.go b/internal/login/handler/mfa_verify_handler.go new file mode 100644 index 0000000000..dbe8008b2e --- /dev/null +++ b/internal/login/handler/mfa_verify_handler.go @@ -0,0 +1,49 @@ +package handler + +import ( + "net/http" + + "github.com/caos/zitadel/internal/auth_request/model" +) + +const ( + tmplMfaVerify = "mfaverify" +) + +type mfaVerifyFormData struct { + MfaType model.MfaType `schema:"mfaType"` + Code string `schema:"code"` +} + +func (l *Login) handleMfaVerify(w http.ResponseWriter, r *http.Request) { + data := new(mfaVerifyFormData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + if data.MfaType == model.MfaTypeOTP { + err = l.authRepo.VerifyMfaOTP(setContext(r.Context(), authReq.UserOrgID), authReq.ID, authReq.UserID, data.Code, model.BrowserInfoFromRequest(r)) + } + if err != nil { + l.renderError(w, r, authReq, err) + return + } + l.renderNextStep(w, r, authReq) +} + +func (l *Login) renderMfaVerify(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, verificationStep *model.MfaVerificationStep, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + data := userData{ + baseData: l.getBaseData(r, authReq, "Mfa Verify", errType, errMessage), + UserName: authReq.UserName, + } + if verificationStep != nil { + data.MfaProviders = verificationStep.MfaProviders + data.SelectedMfaProvider = verificationStep.MfaProviders[0] + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplMfaVerify], data, nil) +} diff --git a/internal/login/handler/password_handler.go b/internal/login/handler/password_handler.go new file mode 100644 index 0000000000..c06e4a5d79 --- /dev/null +++ b/internal/login/handler/password_handler.go @@ -0,0 +1,42 @@ +package handler + +import ( + "net/http" + + "github.com/caos/zitadel/internal/auth_request/model" +) + +const ( + tmplPassword = "password" +) + +type passwordData struct { + Password string `schema:"password"` +} + +func (l *Login) renderPassword(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + data := userData{ + baseData: l.getBaseData(r, authReq, "Password", errType, errMessage), + UserName: authReq.UserName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplPassword], data, nil) +} + +func (l *Login) handlePasswordCheck(w http.ResponseWriter, r *http.Request) { + data := new(passwordData) + authReq, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + err = l.authRepo.VerifyPassword(setContext(r.Context(), authReq.UserOrgID), authReq.ID, authReq.UserID, data.Password, model.BrowserInfoFromRequest(r)) + if err != nil { + l.renderPassword(w, r, authReq, err) + return + } + l.renderNextStep(w, r, authReq) +} diff --git a/internal/login/handler/password_reset_handler.go b/internal/login/handler/password_reset_handler.go new file mode 100644 index 0000000000..d9168e6a23 --- /dev/null +++ b/internal/login/handler/password_reset_handler.go @@ -0,0 +1,32 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + tmplPasswordResetDone = "passwordresetdone" +) + +func (l *Login) handlePasswordReset(w http.ResponseWriter, r *http.Request) { + authReq, err := l.getAuthRequest(r) + if err != nil { + l.renderError(w, r, authReq, err) + return + } + err = l.authRepo.RequestPasswordReset(setContext(r.Context(), authReq.UserOrgID), authReq.UserName) + l.renderPasswordResetDone(w, r, authReq, err) +} + +func (l *Login) renderPasswordResetDone(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + data := userData{ + baseData: l.getBaseData(r, authReq, "Password Reset Done", errType, errMessage), + UserName: authReq.UserName, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplPasswordResetDone], data, nil) +} diff --git a/internal/login/handler/register_handler.go b/internal/login/handler/register_handler.go new file mode 100644 index 0000000000..b61b6106e8 --- /dev/null +++ b/internal/login/handler/register_handler.go @@ -0,0 +1,119 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + caos_errs "github.com/caos/zitadel/internal/errors" + usr_model "github.com/caos/zitadel/internal/user/model" + "golang.org/x/text/language" + "net/http" +) + +const ( + tmplRegister = "register" + + globalRO = "GlobalResourceOwner" +) + +type registerFormData struct { + Email string `schema:"email"` + Firstname string `schema:"firstname"` + Lastname string `schema:"lastname"` + Language string `schema:"language"` + Gender int32 `schema:"gender"` + Password string `schema:"password"` + Password2 string `schema:"password2"` +} + +type registerData struct { + baseData + registerFormData +} + +func (l *Login) handleRegister(w http.ResponseWriter, r *http.Request) { + data := new(registerFormData) + authRequest, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authRequest, err) + return + } + l.renderRegister(w, r, authRequest, data, nil) +} + +func (l *Login) handleRegisterCheck(w http.ResponseWriter, r *http.Request) { + data := new(registerFormData) + authRequest, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authRequest, err) + return + } + if data.Password != data.Password2 { + err := caos_errs.ThrowInvalidArgument(nil, "VIEW-KaGue", "passwords dont match") + l.renderRegister(w, r, authRequest, data, err) + return + } + iam, err := l.authRepo.GetIam(r.Context()) + if err != nil { + l.renderRegister(w, r, authRequest, data, err) + return + } + user, err := l.authRepo.Register(setContext(r.Context(), iam.GlobalOrgID), data.toUserModel(), iam.GlobalOrgID) + if err != nil { + l.renderRegister(w, r, authRequest, data, err) + return + } + if authRequest == nil { + http.Redirect(w, r, l.zitadelURL, http.StatusFound) + return + } + authRequest.UserName = user.UserName + l.renderNextStep(w, r, authRequest) +} + +func (l *Login) renderRegister(w http.ResponseWriter, r *http.Request, authRequest *model.AuthRequest, formData *registerFormData, err error) { + var errType, errMessage string + if err != nil { + errMessage = err.Error() + } + if formData == nil { + formData = new(registerFormData) + } + if formData.Language == "" { + formData.Language = l.renderer.Lang(r).String() + } + data := registerData{ + baseData: l.getBaseData(r, authRequest, "Register", errType, errMessage), + registerFormData: *formData, + } + funcs := map[string]interface{}{ + "selectedLanguage": func(l string) bool { + if formData == nil { + return false + } + return formData.Language == l + }, + "selectedGender": func(g int32) bool { + if formData == nil { + return false + } + return formData.Gender == g + }, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplRegister], data, funcs) +} + +func (d registerFormData) toUserModel() *usr_model.User { + return &usr_model.User{ + Profile: &usr_model.Profile{ + FirstName: d.Firstname, + LastName: d.Lastname, + PreferredLanguage: language.Make(d.Language), + Gender: usr_model.Gender(d.Gender), + }, + Password: &usr_model.Password{ + SecretString: d.Password, + }, + Email: &usr_model.Email{ + EmailAddress: d.Email, + }, + } +} diff --git a/internal/login/handler/renderer.go b/internal/login/handler/renderer.go new file mode 100644 index 0000000000..c968b11b1a --- /dev/null +++ b/internal/login/handler/renderer.go @@ -0,0 +1,260 @@ +package handler + +import ( + "fmt" + "github.com/caos/zitadel/internal/auth_request/model" + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/i18n" + "github.com/caos/zitadel/internal/renderer" + "net/http" + "path" + + "github.com/caos/logging" + "golang.org/x/text/language" +) + +const ( + tmplError = "error" +) + +type Renderer struct { + *renderer.Renderer +} + +func CreateRenderer(staticDir http.FileSystem, cookieName string, defaultLanguage language.Tag) *Renderer { + r := new(Renderer) + tmplMapping := map[string]string{ + tmplError: "error.html", + tmplLogin: "login.html", + tmplUserSelection: "select_user.html", + tmplPassword: "password.html", + tmplMfaVerify: "mfa_verify.html", + tmplMfaPrompt: "mfa_prompt.html", + tmplMfaInitVerify: "mfa_init_verify.html", + tmplMfaInitDone: "mfa_init_done.html", + tmplMailVerification: "mail_verification.html", + tmplMailVerified: "mail_verified.html", + tmplInitPassword: "init_password.html", + tmplInitPasswordDone: "init_password_done.html", + tmplInitUser: "init_user.html", + tmplInitUserDone: "init_user_done.html", + tmplPasswordResetDone: "password_reset_done.html", + tmplChangePassword: "change_password.html", + tmplChangePasswordDone: "change_password_done.html", + tmplRegister: "register.html", + tmplLogoutDone: "logout_done.html", + } + funcs := map[string]interface{}{ + "resourceUrl": func(file string) string { + return path.Join(EndpointResources, file) + }, + "resourceThemeUrl": func(file, theme string) string { + return path.Join(EndpointResources, "themes", theme, file) + }, + "loginUrl": func() string { + return EndpointLogin + }, + "registerUrl": func(id string) string { + return fmt.Sprintf("%s?%s=%s", EndpointRegister, queryAuthRequestID, id) + }, + "usernameUrl": func() string { + return EndpointUsername + }, + "usernameChangeUrl": func(id string) string { + return fmt.Sprintf("%s?%s=%s", EndpointUsername, queryAuthRequestID, id) + }, + "userSelectionUrl": func() string { + return EndpointUserSelection + }, + "passwordResetUrl": func(id string) string { + return fmt.Sprintf("%s?%s=%s", EndpointPasswordReset, queryAuthRequestID, id) + }, + "passwordUrl": func() string { + return EndpointPassword + }, + "mfaVerifyUrl": func() string { + return EndpointMfaVerify + }, + "mfaPromptUrl": func() string { + return EndpointMfaPrompt + }, + "mfaInitVerifyUrl": func() string { + return EndpointMfaInitVerify + }, + "mailVerificationUrl": func() string { + return EndpointMailVerification + }, + "initPasswordUrl": func() string { + return EndpointInitPassword + }, + "initUserUrl": func() string { + return EndpointInitUser + }, + "changePasswordUrl": func() string { + return EndpointChangePassword + }, + "registrationUrl": func() string { + return EndpointRegister + }, + "selectedLanguage": func(l string) bool { + return false + }, + "selectedGender": func(g int32) bool { + return false + }, + } + var err error + r.Renderer, err = renderer.NewRenderer( + staticDir, + tmplMapping, funcs, + i18n.TranslatorConfig{DefaultLanguage: defaultLanguage, CookieName: cookieName}, + ) + logging.Log("APP-40tSoJ").OnError(err).WithError(err).Panic("error creating renderer") + return r +} + +func (l *Login) renderNextStep(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest) { + authReq, err := l.authRepo.AuthRequestByID(r.Context(), authReq.ID) + if err != nil { + l.renderInternalError(w, r, authReq, errors.ThrowInternal(nil, "APP-sio0W", "could not get authreq")) + } + if len(authReq.PossibleSteps) == 0 { + l.renderInternalError(w, r, authReq, errors.ThrowInternal(nil, "APP-9sdp4", "no possible steps")) + return + } + l.chooseNextStep(w, r, authReq, 0, nil) +} + +func (l *Login) renderError(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { + if authReq == nil || len(authReq.PossibleSteps) == 0 { + l.renderInternalError(w, r, authReq, errors.ThrowInternal(err, "APP-OVOiT", "no possible steps")) + return + } + l.chooseNextStep(w, r, authReq, 0, err) +} + +func (l *Login) chooseNextStep(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, stepNumber int, err error) { + switch step := authReq.PossibleSteps[stepNumber].(type) { + case *model.LoginStep: + if len(authReq.PossibleSteps) > 1 { + l.chooseNextStep(w, r, authReq, 1, err) + return + } + l.renderLogin(w, r, authReq, err) + case *model.SelectUserStep: + l.renderUserSelection(w, r, authReq, step) + case *model.InitPasswordStep: + l.renderInitPassword(w, r, authReq, authReq.UserID, "", err) + case *model.PasswordStep: + l.renderPassword(w, r, authReq, nil) + case *model.MfaVerificationStep: + l.renderMfaVerify(w, r, authReq, step, err) + case *model.RedirectToCallbackStep: + if len(authReq.PossibleSteps) > 1 { + l.chooseNextStep(w, r, authReq, 1, err) + return + } + l.redirectToCallback(w, r, authReq) + case *model.ChangePasswordStep: + l.renderChangePassword(w, r, authReq, err) + case *model.VerifyEMailStep: + l.renderMailVerification(w, r, authReq, "", err) + case *model.MfaPromptStep: + l.renderMfaPrompt(w, r, authReq, step, err) + case *model.InitUserStep: + l.renderInitUser(w, r, authReq, "", "", nil) + default: + l.renderInternalError(w, r, authReq, errors.ThrowInternal(nil, "APP-ds3QF", "step no possible")) + } +} + +func (l *Login) renderInternalError(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, err error) { + var msg string + if err != nil { + msg = err.Error() + } + data := l.getBaseData(r, authReq, "Error", "Internal", msg) + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplError], data, nil) +} + +func (l *Login) getBaseData(r *http.Request, authReq *model.AuthRequest, title string, errType, errMessage string) baseData { + return baseData{ + errorData: errorData{ + ErrType: errType, + ErrMessage: errMessage, + }, + Lang: l.renderer.Lang(r).String(), + Title: title, + Theme: l.getTheme(r), + ThemeMode: l.getThemeMode(r), + AuthReqID: getRequestID(authReq, r), + } +} + +func (l *Login) getTheme(r *http.Request) string { + return "zitadel" //TODO: impl +} + +func (l *Login) getThemeMode(r *http.Request) string { + return "" //TODO: impl +} + +func getRequestID(authReq *model.AuthRequest, r *http.Request) string { + if authReq != nil { + return authReq.ID + } + return r.FormValue(queryAuthRequestID) +} + +type baseData struct { + errorData + Lang string + Title string + Theme string + ThemeMode string + AuthReqID string +} + +type errorData struct { + ErrType string + ErrMessage string +} + +type userData struct { + baseData + UserName string + PasswordChecked string + MfaProviders []model.MfaType + SelectedMfaProvider model.MfaType +} + +type userSelectionData struct { + baseData + Users []model.UserSelection +} + +type mfaData struct { + baseData + UserName string + MfaProviders []model.MfaType + MfaRequired bool +} + +type mfaVerifyData struct { + baseData + UserName string + MfaType model.MfaType + otpData +} + +type mfaDoneData struct { + baseData + UserName string + MfaType model.MfaType +} + +type otpData struct { + Url string + Secret string + QrCode string +} diff --git a/internal/login/handler/resources_handler.go b/internal/login/handler/resources_handler.go new file mode 100644 index 0000000000..b06449a6da --- /dev/null +++ b/internal/login/handler/resources_handler.go @@ -0,0 +1,9 @@ +package handler + +import ( + "net/http" +) + +func (l *Login) handleResources(staticDir http.FileSystem) http.Handler { + return http.FileServer(staticDir) +} diff --git a/internal/login/handler/router.go b/internal/login/handler/router.go new file mode 100644 index 0000000000..60b0ba4eb3 --- /dev/null +++ b/internal/login/handler/router.go @@ -0,0 +1,58 @@ +package handler + +import ( + "net/http" + + "github.com/gorilla/mux" +) + +const ( + EndpointRoot = "/" + EndpointHealthz = "/healthz" + EndpointReadiness = "/ready" + EndpointLogin = "/login" + EndpointUsername = "/username" + EndpointUserSelection = "/userselection" + EndpointPassword = "/password" + EndpointInitPassword = "/password/init" + EndpointChangePassword = "/password/change" + EndpointPasswordReset = "/password/reset" + EndpointInitUser = "/user/init" + EndpointMfaVerify = "/mfa/verify" + EndpointMfaPrompt = "/mfa/prompt" + EndpointMfaInitVerify = "/mfa/init/verify" + EndpointMailVerification = "/mail/verification" + EndpointMailVerified = "/mail/verified" + EndpointRegister = "/register" + EndpointLogoutDone = "/logout/done" + + EndpointResources = "/resources" +) + +func CreateRouter(login *Login, staticDir http.FileSystem) *mux.Router { + router := mux.NewRouter() + router.HandleFunc(EndpointRoot, login.handleLogin).Methods(http.MethodGet) + router.HandleFunc(EndpointHealthz, login.handleHealthz).Methods(http.MethodGet) + router.HandleFunc(EndpointReadiness, login.handleReadiness).Methods(http.MethodGet) + router.HandleFunc(EndpointLogin, login.handleLogin).Methods(http.MethodGet, http.MethodPost) + router.HandleFunc(EndpointUsername, login.handleUsername).Methods(http.MethodGet) + router.HandleFunc(EndpointUsername, login.handleUsernameCheck).Methods(http.MethodPost) + router.HandleFunc(EndpointUserSelection, login.handleSelectUser).Methods(http.MethodPost) + router.HandleFunc(EndpointPassword, login.handlePasswordCheck).Methods(http.MethodPost) + router.HandleFunc(EndpointInitPassword, login.handleInitPassword).Methods(http.MethodGet) + router.HandleFunc(EndpointInitPassword, login.handleInitPasswordCheck).Methods(http.MethodPost) + router.HandleFunc(EndpointPasswordReset, login.handlePasswordReset).Methods(http.MethodGet) + router.HandleFunc(EndpointInitUser, login.handleInitUser).Methods(http.MethodGet) + router.HandleFunc(EndpointInitUser, login.handleInitUserCheck).Methods(http.MethodPost) + router.HandleFunc(EndpointMfaVerify, login.handleMfaVerify).Methods(http.MethodPost) + router.HandleFunc(EndpointMfaPrompt, login.handleMfaPrompt).Methods(http.MethodPost) + router.HandleFunc(EndpointMfaInitVerify, login.handleMfaInitVerify).Methods(http.MethodPost) + router.HandleFunc(EndpointMailVerification, login.handleMailVerification).Methods(http.MethodGet) + router.HandleFunc(EndpointMailVerification, login.handleMailVerificationCheck).Methods(http.MethodPost) + router.HandleFunc(EndpointChangePassword, login.handleChangePassword).Methods(http.MethodPost) + router.HandleFunc(EndpointRegister, login.handleRegister).Methods(http.MethodGet) + router.HandleFunc(EndpointRegister, login.handleRegisterCheck).Methods(http.MethodPost) + router.HandleFunc(EndpointLogoutDone, login.handleLogoutDone).Methods(http.MethodGet) + router.PathPrefix(EndpointResources).Handler(login.handleResources(staticDir)).Methods(http.MethodGet) + return router +} diff --git a/internal/login/handler/select_user_handler.go b/internal/login/handler/select_user_handler.go new file mode 100644 index 0000000000..1676ee5ccf --- /dev/null +++ b/internal/login/handler/select_user_handler.go @@ -0,0 +1,42 @@ +package handler + +import ( + "github.com/caos/zitadel/internal/auth_request/model" + "net/http" +) + +const ( + tmplUserSelection = "userselection" +) + +type userSelectionFormData struct { + UserID string `schema:"userID"` +} + +func (l *Login) renderUserSelection(w http.ResponseWriter, r *http.Request, authReq *model.AuthRequest, selectionData *model.SelectUserStep) { + var errType, errMessage string + data := userSelectionData{ + baseData: l.getBaseData(r, authReq, "Select User", errType, errMessage), + Users: selectionData.Users, + } + l.renderer.RenderTemplate(w, r, l.renderer.Templates[tmplUserSelection], data, nil) +} + +func (l *Login) handleSelectUser(w http.ResponseWriter, r *http.Request) { + data := new(userSelectionFormData) + authSession, err := l.getAuthRequestAndParseData(r, data) + if err != nil { + l.renderError(w, r, authSession, err) + return + } + if data.UserID == "0" { + l.renderLogin(w, r, authSession, nil) + return + } + err = l.authRepo.SelectUser(r.Context(), authSession.ID, data.UserID) + if err != nil { + l.renderError(w, r, authSession, err) + return + } + l.renderNextStep(w, r, authSession) +} diff --git a/internal/login/login.go b/internal/login/login.go new file mode 100644 index 0000000000..61a0a0a4ae --- /dev/null +++ b/internal/login/login.go @@ -0,0 +1,17 @@ +package login + +import ( + "context" + + "github.com/caos/zitadel/internal/auth/repository/eventsourcing" + sd "github.com/caos/zitadel/internal/config/systemdefaults" + "github.com/caos/zitadel/internal/login/handler" +) + +type Config struct { + Handler handler.Config +} + +func Start(ctx context.Context, config Config, systemDefaults sd.SystemDefaults, authRepo *eventsourcing.EsRepository) { + handler.StartLogin(ctx, config.Handler, authRepo) +} diff --git a/internal/login/static/i18n/de.yaml b/internal/login/static/i18n/de.yaml new file mode 100644 index 0000000000..ae20d7e6a9 --- /dev/null +++ b/internal/login/static/i18n/de.yaml @@ -0,0 +1,119 @@ +Password: + Title: Passwort + Description: Gib deine Benutzerdaten ein. + Password: Passwort + +Login: + Title: Anmeldung + Description: Gib deine Benutzerdaten ein. + Username: Benutzername + +UserSelection: + Title: Account auswählen + Description: Wähle deinen Account aus. + OtherUser: Anderer Benutzer + SessionState0: aktiv + SessionState1: inaktiv + +MfaVerify: + Title: Multifaktor verifizieren + Description: Verifiziere deinen Multifaktor + OTP: OTP + Code: Code + +InitPassword: + Title: Passwort setzen + Description: Du hast einen Code erhalten, welcher im untenstehenden Formular eingegeben werden muss um ein neues Passwort zu setzen. + Code: Code + NewPassword: Neues Passwort + NewPasswordConfirm: Passwort bestätigen + +InitPasswordDone: + Title: Passwort gesetzt + Description: Passwort erfolgreich gesetzt + +InitUser: + Title: User aktivieren + Description: Du hast einen Code erhalten, welcher im untenstehenden Formular eingegeben werden muss um deine EMail zu verifizieren und ein neues Passwort zu setzen. + Code: Code + NewPassword: Neues Passwort + NewPasswordConfirm: Passwort bestätigen + +InitUserDone: + Title: User aktiviert + Description: EMail verifiziert und Passwort erfolgreich gesetzt + +MfaPrompt: + Title: Multifaktor hinzufügen + Description: Möchtest du einen Mulitfaktor hinzufügen? + Provider0: OTP + Provider1: SMS + +MfaInitVerify: + Title: Multifaktor Verifizierung + Description: Verifiziere deinen Multifaktor + OtpDescription: Scanne den Code mit einem Authentifizierungs-App (z.B Google Authentificator) oder kopiere das Secret und gib anschliessend den Code ein. + Secret: Secret + Code: Code + +MfaInitDone: + Title: Multifaktor Verifizierung erstellt + Description: Multifikator Verifizierung erfolgreich abgeschlossen. Der Multifaktor muss bei jeder Anmeldung eingegeben werden, dies beinhaltet auch den aktuellen Authentifizierungs Prozess. + +PasswordChange: + Title: Passwort ändern + Description: Ändere dein Password in dem du dein altes und dann dein neuen Passwort eingibst. + OldPassword: Altes Passwort + NewPassword: Neues Passwort + +PasswordChangeDone: + Title: Passwort ändern + Description: Das Passwort wurde erfolgreich geändert. + +PasswordResetDone: + Title: Resetlink versendet + Description: Prüfe dein E-Mail Postfach, um ein neues Passwort zu setzen. + +PasswordSetDone: + Title: Passwort gesetzt + Description: Das Passwort wurde erfolgreich gesetzt. + +EmailVerification: + Title: E-Mail Verifizierung + Description: Du hast ein E-Mail zur Verifizierung deiner E-Mail Adresse bekommen. Gib den Code im untenstehenden Formular ein. Mit erneut versenden, wird dir ein neues E-Mail zugestellt. + Code: Code + +EmailVerificationDone: + Title: E-Mail Verifizierung + Description: Deine E-Mail Adresse wurde erfolgreich verifiziert. + +Registration: + Title: Registration + Description: Gib deine Benutzerangaben an. Die E-Mail Adresse wird als Benutzernamen verwendet. + Email: E-Mail + Firstname: Vorname + Lastname: Nachname + Language: Sprache + German: Deutsch + English: English + Gender: Geschlecht + Female: weiblich + Male: männlich + Diverse: diverse + Password: Passwort + Password2: Passwort wiederholen + +LogoutDone: + Title: Ausgeloggt + Description: Du wurdest erfolgreich ausgeloggt. + +Actions: + Login: anmelden + Next: weiter + Back: zurück + Resend: erneut senden + Skip: überspringen + Register: registrieren + ForgotPassword: Password zurücksetzen + +optional: (optional) diff --git a/internal/login/static/i18n/en.yaml b/internal/login/static/i18n/en.yaml new file mode 100644 index 0000000000..417dae0636 --- /dev/null +++ b/internal/login/static/i18n/en.yaml @@ -0,0 +1,119 @@ +Login: + Title: Login + Description: Enter your logindata. + Username: Username + +UserSelection: + Title: Select account + Description: Select your account. + OtherUser: Other User + SessionState0: active + SessionState1: inactive + +Password: + Title: Password + Description: Enter your logindata. + Password: Password + +MfaVerify: + Title: Verify Multificator + Description: Verify your multifactor + OTP: OTP + Code: Code + +InitPassword: + Title: Set Password + Description: You have received a code, which you have to enter in the form below, to set your new password. + Code: Code + NewPassword: New Password + NewPasswordConfirm: Confirm Password + +InitPasswordDone: + Title: Passwortd set + Description: Password successfully set + +InitUser: + Title: Activate User + Description: You have received a code, which you have to enter in the form below, to verify your email and set your new password. + Code: Code + NewPassword: New Password + NewPasswordConfirm: Confirm Password + +InitUserDone: + Title: User activated + Description: Email verified and Password successfully set + +MfaPrompt: + Title: Multifactor Setup + Description: Would you like to setup multifactor authentication? + Provider0: OTP + Provider1: SMS + +MfaInitVerify: + Title: Multifactor Verification + Description: Verify your multifactor. + OtpDescription: Scan the code with your authenticator app (e.g Google-Authenticator) or copy the secret and insert the generated code below. + Secret: Secret + Code: Code + +MfaInitDone: + Title: Multifcator Verification done + Description: Multifactor verification successfully done. The multifactor has to be entered on each login, even in the actual authentification process. + +PasswordChange: + Title: Change Password + Description: Change your password. Enter your old and new password. + OldPassword: Old Password + NewPassword: New Password + +PasswordChangeDone: + Title: Change Password + Description: Your password was changed successfully. + +PasswordResetDone: + Title: Reset link set + Description: Check your email to to reset your password. + +PasswordSetDone: + Title: Password set + Description: Your password was set successfully. + +EmailVerification: + Title: E-Mail Verification + Description: We have sent you an email to verify your address. Please enter the code in the form below. + Code: Code + +EmailVerificationDone: + Title: E-Mail Verification + Description: Your email address has been successfully verified. + +Registration: + Title: Registration + Description: Enter your Userdata. Your email address will be used as username. + Email: E-Mail + Firstname: Firstname + Lastname: Lastname + Language: Language + German: Deutsch + English: English + Gender: Gender + Female: Female + Male: Male + Diverse: diverse / X + Password: Password + Password2: Password confirmation + +LogoutDone: + Title: Logged out + Description: You have logged out successfully. + +Actions: + Login: login + Next: next + Back: back + Resend: resend + Skip: skip + Register: register + ForgotPassword: Reset password + +optional: (optional) diff --git a/internal/login/static/resources/fonts/ailerons/ailerons.otf b/internal/login/static/resources/fonts/ailerons/ailerons.otf new file mode 100644 index 0000000000..8a18b632c6 Binary files /dev/null and b/internal/login/static/resources/fonts/ailerons/ailerons.otf differ diff --git a/internal/login/static/resources/fonts/lato/Lato-Black.ttf b/internal/login/static/resources/fonts/lato/Lato-Black.ttf new file mode 100755 index 0000000000..a4a924f9bd Binary files /dev/null and b/internal/login/static/resources/fonts/lato/Lato-Black.ttf differ diff --git a/internal/login/static/resources/fonts/lato/Lato-BlackItalic.ttf b/internal/login/static/resources/fonts/lato/Lato-BlackItalic.ttf new file mode 100755 index 0000000000..d6f8945018 Binary files /dev/null and b/internal/login/static/resources/fonts/lato/Lato-BlackItalic.ttf differ diff --git a/internal/login/static/resources/fonts/lato/Lato-Bold.ttf b/internal/login/static/resources/fonts/lato/Lato-Bold.ttf new file mode 100755 index 0000000000..b63a14d6ae Binary files /dev/null and b/internal/login/static/resources/fonts/lato/Lato-Bold.ttf differ diff --git a/internal/login/static/resources/fonts/lato/Lato-BoldItalic.ttf b/internal/login/static/resources/fonts/lato/Lato-BoldItalic.ttf new file mode 100755 index 0000000000..8f9a50d135 Binary files /dev/null and b/internal/login/static/resources/fonts/lato/Lato-BoldItalic.ttf differ diff --git a/internal/login/static/resources/fonts/lato/Lato-Italic.ttf b/internal/login/static/resources/fonts/lato/Lato-Italic.ttf new file mode 100755 index 0000000000..49e9f2c3e3 Binary files /dev/null and b/internal/login/static/resources/fonts/lato/Lato-Italic.ttf differ diff --git a/internal/login/static/resources/fonts/lato/Lato-Light.ttf b/internal/login/static/resources/fonts/lato/Lato-Light.ttf new file mode 100755 index 0000000000..9c0a705362 Binary files /dev/null and b/internal/login/static/resources/fonts/lato/Lato-Light.ttf differ diff --git a/internal/login/static/resources/fonts/lato/Lato-LightItalic.ttf b/internal/login/static/resources/fonts/lato/Lato-LightItalic.ttf new file mode 100755 index 0000000000..53b140bc94 Binary files /dev/null and b/internal/login/static/resources/fonts/lato/Lato-LightItalic.ttf differ diff --git a/internal/login/static/resources/fonts/lato/Lato-Regular.ttf b/internal/login/static/resources/fonts/lato/Lato-Regular.ttf new file mode 100755 index 0000000000..33eba8b192 Binary files /dev/null and b/internal/login/static/resources/fonts/lato/Lato-Regular.ttf differ diff --git a/internal/login/static/resources/fonts/lato/Lato-Thin.ttf b/internal/login/static/resources/fonts/lato/Lato-Thin.ttf new file mode 100755 index 0000000000..0c599a043d Binary files /dev/null and b/internal/login/static/resources/fonts/lato/Lato-Thin.ttf differ diff --git a/internal/login/static/resources/fonts/lato/Lato-ThinItalic.ttf b/internal/login/static/resources/fonts/lato/Lato-ThinItalic.ttf new file mode 100755 index 0000000000..7db3a8cccb Binary files /dev/null and b/internal/login/static/resources/fonts/lato/Lato-ThinItalic.ttf differ diff --git a/internal/login/static/resources/fonts/lato/OFL.txt b/internal/login/static/resources/fonts/lato/OFL.txt new file mode 100755 index 0000000000..98383e3d83 --- /dev/null +++ b/internal/login/static/resources/fonts/lato/OFL.txt @@ -0,0 +1,93 @@ +Copyright (c) 2010-2014 by tyPoland Lukasz Dziedzic (team@latofonts.com) with Reserved Font Name "Lato" + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/internal/login/static/resources/fonts/material/MaterialIcons-Regular.eot b/internal/login/static/resources/fonts/material/MaterialIcons-Regular.eot new file mode 100644 index 0000000000..70508ebabc Binary files /dev/null and b/internal/login/static/resources/fonts/material/MaterialIcons-Regular.eot differ diff --git a/internal/login/static/resources/fonts/material/MaterialIcons-Regular.ttf b/internal/login/static/resources/fonts/material/MaterialIcons-Regular.ttf new file mode 100644 index 0000000000..7015564ad1 Binary files /dev/null and b/internal/login/static/resources/fonts/material/MaterialIcons-Regular.ttf differ diff --git a/internal/login/static/resources/fonts/material/MaterialIcons-Regular.woff b/internal/login/static/resources/fonts/material/MaterialIcons-Regular.woff new file mode 100644 index 0000000000..b648a3eea2 Binary files /dev/null and b/internal/login/static/resources/fonts/material/MaterialIcons-Regular.woff differ diff --git a/internal/login/static/resources/fonts/material/MaterialIcons-Regular.woff2 b/internal/login/static/resources/fonts/material/MaterialIcons-Regular.woff2 new file mode 100644 index 0000000000..9fa2112520 Binary files /dev/null and b/internal/login/static/resources/fonts/material/MaterialIcons-Regular.woff2 differ diff --git a/internal/login/static/resources/generate.go b/internal/login/static/resources/generate.go new file mode 100644 index 0000000000..95cb7ff036 --- /dev/null +++ b/internal/login/static/resources/generate.go @@ -0,0 +1,7 @@ +package resources + +// scss +//go:generate sass themes/scss/zitadel/dark.scss themes/zitadel/css/dark.css +//go:generate sass themes/scss/zitadel/light.scss themes/zitadel/css/light.css +//go:generate sass themes/scss/caos/dark.scss themes/caos/css/dark.css +//go:generate sass themes/scss/caos/light.scss themes/caos/css/light.css diff --git a/internal/login/static/resources/themes/caos/css/dark.css b/internal/login/static/resources/themes/caos/css/dark.css new file mode 100644 index 0000000000..54f36e6474 --- /dev/null +++ b/internal/login/static/resources/themes/caos/css/dark.css @@ -0,0 +1,257 @@ +@font-face { + font-family: Aileron; + src: url(../../../fonts/ailerons/ailerons.otf) format("opentype"); +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Thin.ttf) format("truetype"); + font-style: normal; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-ThinItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Light.ttf) format("truetype"); + font-style: normal; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-LightItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Regular.ttf) format("truetype"); + font-style: normal; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Italic.ttf) format("truetype"); + font-style: italic; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Bold.ttf) format("truetype"); + font-style: normal; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BoldItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Black.ttf) format("truetype"); + font-style: normal; + font-weight: 800; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BlackItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 800; +} +@font-face { + font-family: "Material Icons"; + font-style: normal; + font-weight: 400; + src: url(../../../fonts/material/MaterialIcons-Regular.eot); + /* For IE6-8 */ + src: local("Material Icons"), local("MaterialIcons-Regular"), url(../../../fonts/material/MaterialIcons-Regular.woff2) format("woff2"), url(../../../fonts/material/MaterialIcons-Regular.woff) format("woff"), url(../../../fonts/material/MaterialIcons-Regular.ttf) format("truetype"); +} +*, *::before, *::after { + box-sizing: border-box; + font-family: Lato; + font-size: 18px; + font-weight: 400; +} + +body { + margin: 0; +} + +html { + background-color: #282828; + color: white; +} + +h1 { + color: white; + font-family: Aileron; + text-transform: uppercase; + text-align: center; + font-size: 40px; +} + +p { + font-width: 300; +} + +header { + padding: 8px; +} +header .logo { + background-image: url("../logo-dark.png"); + background-repeat: no-repeat; + background-size: contain; + height: 80px; + margin: 30px; +} + +.content { + margin: auto; + padding: 20px; + width: 100%; + max-width: 500px; +} + +a { + color: #760038; + text-decoration: none; + text-transform: uppercase; + font-weight: 600; +} +a:hover { + color: #f60075; +} + +button { + text-transform: uppercase; + background-color: #282828; + color: #760038; + border: 2px solid #760038; + border-radius: 5px; + width: 100%; + max-width: 600px; + height: 50px; + transition: all 0.3s ease 0s; + cursor: pointer; + outline: none; +} +button:hover { + background-color: #f60075; + border: 2px solid #f60075; +} +button.primary { + background-color: #760038; + color: white; + border: none; +} +button.primary:hover { + background-color: #f60075; +} +button > .sessionstate { + text-transform: lowercase; +} + +input:not([type=radio]), select { + background-color: #252525; + color: white; + height: 50px; + border: 2px solid #595959; + border-radius: 5px; + padding-left: 15px; +} + +form .field { + display: grid; + padding: 10px 0; +} +form .field.radio-button { + display: flex; +} +form .field.radio-button input[type=radio] { + height: 20px; + vertical-align: middle; +} +form .field.radio-button label { + height: 20px; + display: inline-block; + padding: 3px 0 0 15px; + width: 100%; +} +form label { + color: #898989; + text-transform: uppercase; + font-size: 0.9rem; + margin-bottom: 3px; +} +form label span.optional { + font-style: italic; + text-transform: none; +} +form .actions { + padding: 20px 0; +} +form .actions .right { + float: right; +} +form .actions button, form .actions a { + margin: 10px 0; +} + +#copy-secret { + visibility: hidden; + position: absolute; +} + +#qrcode { + text-align: center; +} +#qrcode svg rect[style*="fill:white"] { + fill: #282828 !important; +} +#qrcode svg rect[style*="fill:black"] { + fill: white !important; +} + +#secret .copy { + float: right; + cursor: pointer; +} + +footer { + background-image: url("../gradientdeco-full.svg"); + width: 100%; + background-size: cover; + height: 44vw; + position: fixed; + bottom: 0; + z-index: -1; +} + +.material-icons { + font-family: "Material Icons"; + font-weight: normal; + font-style: normal; + font-size: 24px; + /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + /* Support for IE. */ + font-feature-settings: "liga"; +} + +/*# sourceMappingURL=dark.css.map */ diff --git a/internal/login/static/resources/themes/caos/css/dark.css.map b/internal/login/static/resources/themes/caos/css/dark.css.map new file mode 100644 index 0000000000..6a09f3088a --- /dev/null +++ b/internal/login/static/resources/themes/caos/css/dark.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCGW;EDFX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCDc;EDEd,OCDQ;;;ADIZ;EACI,OCLQ;EDMR,aCZS;EDaT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCnCW;EDoCX;EACA;EACA;;AAEA;EACI,OCxCY;;;AD4CpB;EACI;EACA,kBCjDc;EDkDd,OChDW;EDiDX;EACA;EACA;EACA;EACA,QE/DU;EFgEV;EACA;EACA;;AACA;EACI,kBCzDY;ED0DZ;;AAGJ;EACI,kBC/DO;EDgEP,OCjEI;EDkEJ;;AACA;EACI,kBClEQ;;ADsEhB;EACI;;;AAIR;EACI,kBE7EmB;EF8EnB,OC/EQ;EDgFR,QEzFU;EF0FV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OE9GK;EF+GL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKJ;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA","file":"dark.css"} \ No newline at end of file diff --git a/internal/login/static/resources/themes/caos/css/light.css b/internal/login/static/resources/themes/caos/css/light.css new file mode 100644 index 0000000000..f8eda48dc1 --- /dev/null +++ b/internal/login/static/resources/themes/caos/css/light.css @@ -0,0 +1,299 @@ +@font-face { + font-family: Aileron; + src: url(../../../fonts/ailerons/ailerons.otf) format("opentype"); +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Thin.ttf) format("truetype"); + font-style: normal; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-ThinItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Light.ttf) format("truetype"); + font-style: normal; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-LightItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Regular.ttf) format("truetype"); + font-style: normal; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Italic.ttf) format("truetype"); + font-style: italic; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Bold.ttf) format("truetype"); + font-style: normal; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BoldItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Black.ttf) format("truetype"); + font-style: normal; + font-weight: 800; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BlackItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 800; +} +@font-face { + font-family: "Material Icons"; + font-style: normal; + font-weight: 400; + src: url(../../../fonts/material/MaterialIcons-Regular.eot); + /* For IE6-8 */ + src: local("Material Icons"), local("MaterialIcons-Regular"), url(../../../fonts/material/MaterialIcons-Regular.woff2) format("woff2"), url(../../../fonts/material/MaterialIcons-Regular.woff) format("woff"), url(../../../fonts/material/MaterialIcons-Regular.ttf) format("truetype"); +} +*, *::before, *::after { + box-sizing: border-box; + font-family: Lato; + font-size: 18px; + font-weight: 400; +} + +body { + margin: 0; +} + +html { + background-color: #282828; + color: white; +} + +h1 { + color: white; + font-family: Aileron; + text-transform: uppercase; + text-align: center; + font-size: 40px; +} + +p { + font-width: 300; +} + +header { + padding: 8px; +} +header .logo { + background-image: url("../logo-dark.png"); + background-repeat: no-repeat; + background-size: contain; + height: 80px; + margin: 30px; +} + +.content { + margin: auto; + padding: 20px; + width: 100%; + max-width: 500px; +} + +a { + color: #760038; + text-decoration: none; + text-transform: uppercase; + font-weight: 600; +} +a:hover { + color: #f60075; +} + +button { + text-transform: uppercase; + background-color: #282828; + color: #760038; + border: 2px solid #760038; + border-radius: 5px; + width: 100%; + max-width: 600px; + height: 50px; + transition: all 0.3s ease 0s; + cursor: pointer; + outline: none; +} +button:hover { + background-color: #f60075; + border: 2px solid #f60075; +} +button.primary { + background-color: #760038; + color: white; + border: none; +} +button.primary:hover { + background-color: #f60075; +} +button > .sessionstate { + text-transform: lowercase; +} + +input:not([type=radio]), select { + background-color: #252525; + color: white; + height: 50px; + border: 2px solid #595959; + border-radius: 5px; + padding-left: 15px; +} + +form .field { + display: grid; + padding: 10px 0; +} +form .field.radio-button { + display: flex; +} +form .field.radio-button input[type=radio] { + height: 20px; + vertical-align: middle; +} +form .field.radio-button label { + height: 20px; + display: inline-block; + padding: 3px 0 0 15px; + width: 100%; +} +form label { + color: #898989; + text-transform: uppercase; + font-size: 0.9rem; + margin-bottom: 3px; +} +form label span.optional { + font-style: italic; + text-transform: none; +} +form .actions { + padding: 20px 0; +} +form .actions .right { + float: right; +} +form .actions button, form .actions a { + margin: 10px 0; +} + +#copy-secret { + visibility: hidden; + position: absolute; +} + +#qrcode { + text-align: center; +} +#qrcode svg rect[style*="fill:white"] { + fill: #282828 !important; +} +#qrcode svg rect[style*="fill:black"] { + fill: white !important; +} + +#secret .copy { + float: right; + cursor: pointer; +} + +footer { + background-image: url("../gradientdeco-full.svg"); + width: 100%; + background-size: cover; + height: 44vw; + position: fixed; + bottom: 0; + z-index: -1; +} + +.material-icons { + font-family: "Material Icons"; + font-weight: normal; + font-style: normal; + font-size: 24px; + /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + /* Support for IE. */ + font-feature-settings: "liga"; +} + +html { + background-color: white; + color: #282828; +} +html header .logo { + background-image: url("../logo-light.png"); +} +html h1 { + color: #282828; +} +html button { + background-color: white; + color: #760038; + border: 2px solid #760038; +} +html button:hover { + background-color: #f60075; + border: 2px solid #f60075; +} +html button.primary { + background-color: #760038; + color: white; + border: none; + box-shadow: 0px 10px 30px #760038; +} +html button.primary:hover { + background-color: #f60075; +} +html input { + background-color: white; + color: #282828; +} +html #qrcode svg rect[style*="fill:white"] { + fill: white !important; +} +html #qrcode svg rect[style*="fill:black"] { + fill: #282828 !important; +} +html footer { + background-image: url("../gradientdeco-full.svg"); +} + +/*# sourceMappingURL=light.css.map */ diff --git a/internal/login/static/resources/themes/caos/css/light.css.map b/internal/login/static/resources/themes/caos/css/light.css.map new file mode 100644 index 0000000000..2e0ba005c5 --- /dev/null +++ b/internal/login/static/resources/themes/caos/css/light.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/caos/variables.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCGW;EDFX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCDc;EDEd,OCDQ;;;ADIZ;EACI,OCLQ;EDMR,aCZS;EDaT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCnCW;EDoCX;EACA;EACA;;AAEA;EACI,OCxCY;;;AD4CpB;EACI;EACA,kBCjDc;EDkDd,OChDW;EDiDX;EACA;EACA;EACA;EACA,QE/DU;EFgEV;EACA;EACA;;AACA;EACI,kBCzDY;ED0DZ;;AAGJ;EACI,kBC/DO;EDgEP,OCjEI;EDkEJ;;AACA;EACI,kBClEQ;;ADsEhB;EACI;;;AAIR;EACI,kBE7EmB;EF8EnB,OC/EQ;EDgFR,QEzFU;EF0FV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OE9GK;EF+GL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKJ;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AG1MJ;EACI,kBFYQ;EEXR,OFUc;;AERd;EACI;;AAGJ;EACI,OFGU;;AEAd;EACI;EACA;EACA;;AAEA;EACI,kBFIa;EEHb;;AAGJ;EACI,kBFTG;EEUH,OFXA;EEYA;EACA;;AACA;EACI,kBFbI;;AEkBhB;EACI,kBFrBI;EEsBJ,OFvBU;;AE2BV;EACI;;AAGJ;EACI;;AAIR;EACI","file":"light.css"} \ No newline at end of file diff --git a/internal/login/static/resources/themes/caos/favicon.ico b/internal/login/static/resources/themes/caos/favicon.ico new file mode 100644 index 0000000000..fcc06db395 Binary files /dev/null and b/internal/login/static/resources/themes/caos/favicon.ico differ diff --git a/internal/login/static/resources/themes/caos/gradientdeco-full.svg b/internal/login/static/resources/themes/caos/gradientdeco-full.svg new file mode 100644 index 0000000000..bd2418a23b --- /dev/null +++ b/internal/login/static/resources/themes/caos/gradientdeco-full.svg @@ -0,0 +1,50 @@ + + + diff --git a/internal/login/static/resources/themes/caos/logo-dark.png b/internal/login/static/resources/themes/caos/logo-dark.png new file mode 100644 index 0000000000..48d5a9da16 Binary files /dev/null and b/internal/login/static/resources/themes/caos/logo-dark.png differ diff --git a/internal/login/static/resources/themes/caos/logo-light.png b/internal/login/static/resources/themes/caos/logo-light.png new file mode 100644 index 0000000000..39008bbc8a Binary files /dev/null and b/internal/login/static/resources/themes/caos/logo-light.png differ diff --git a/internal/login/static/resources/themes/scss/caos/dark.scss b/internal/login/static/resources/themes/scss/caos/dark.scss new file mode 100644 index 0000000000..b34f994b21 --- /dev/null +++ b/internal/login/static/resources/themes/scss/caos/dark.scss @@ -0,0 +1,3 @@ +@import "../variables.scss"; +@import "./variables.scss"; +@import "../main.scss"; diff --git a/internal/login/static/resources/themes/scss/caos/light.scss b/internal/login/static/resources/themes/scss/caos/light.scss new file mode 100644 index 0000000000..112a44a1a0 --- /dev/null +++ b/internal/login/static/resources/themes/scss/caos/light.scss @@ -0,0 +1,4 @@ +@import "../variables.scss"; +@import "./variables.scss"; +@import "../main.scss"; +@import "../light.scss"; diff --git a/internal/login/static/resources/themes/scss/caos/variables.scss b/internal/login/static/resources/themes/scss/caos/variables.scss new file mode 100644 index 0000000000..19c5abcc0a --- /dev/null +++ b/internal/login/static/resources/themes/scss/caos/variables.scss @@ -0,0 +1,24 @@ +$logoImgDark: "../logo-dark.png"; +$logoImgLight: "../logo-light.png"; + +$footerimgDark: "../gradientdeco-full.svg"; +$footerimgLight: "../gradientdeco-full.svg"; + +// ----- FONTS ------------ +$standardFont: Lato; +$headerFont: Aileron; + +// ----- COLORS ------------ + +// ------ DARK-THEME ------- +$backgroundColor: #282828; +$fontColor: white; +$primaryColor: #760038; +$primaryColorHover: lighten($primaryColor, 25%); + + +// ------ LIGHT-THEME ------- +$backgroundColorLight: $fontColor; +$fontColorLight: $backgroundColor; +$primaryColorLight: $primaryColor; +$primaryColorHoverLight: lighten($primaryColorLight, 25%); \ No newline at end of file diff --git a/internal/login/static/resources/themes/scss/fonts.scss b/internal/login/static/resources/themes/scss/fonts.scss new file mode 100644 index 0000000000..423a199f4a --- /dev/null +++ b/internal/login/static/resources/themes/scss/fonts.scss @@ -0,0 +1,84 @@ +//Aileron +@font-face { + font-family: Aileron; + src: url(../../../fonts/ailerons/ailerons.otf ) format('opentype'); +} + +//Lato +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Thin.ttf ) format('truetype'); + font-style: normal; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-ThinItalic.ttf ) format('truetype'); + font-style: italic; + font-weight: 100; +} + +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Light.ttf ) format('truetype'); + font-style: normal; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-LightItalic.ttf ) format('truetype'); + font-style: italic; + font-weight: 200; +} + +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Regular.ttf ) format('truetype'); + font-style: normal; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Italic.ttf ) format('truetype'); + font-style: italic; + font-weight: 400; +} + +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Bold.ttf ) format('truetype'); + font-style: normal; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BoldItalic.ttf ) format('truetype'); + font-style: italic; + font-weight: 700; +} + +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Black.ttf ) format('truetype'); + font-style: normal; + font-weight: 800; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BlackItalic.ttf ) format('truetype'); + font-style: italic; + font-weight: 800; +} + +//Material Icons +@font-face { + font-family: 'Material Icons'; + font-style: normal; + font-weight: 400; + src: url(../../../fonts/material/MaterialIcons-Regular.eot); /* For IE6-8 */ + src: local('Material Icons'), + local('MaterialIcons-Regular'), + url(../../../fonts/material/MaterialIcons-Regular.woff2) format('woff2'), + url(../../../fonts/material/MaterialIcons-Regular.woff) format('woff'), + url(../../../fonts/material/MaterialIcons-Regular.ttf) format('truetype'); +} diff --git a/internal/login/static/resources/themes/scss/light.scss b/internal/login/static/resources/themes/scss/light.scss new file mode 100644 index 0000000000..f5a9cc8123 --- /dev/null +++ b/internal/login/static/resources/themes/scss/light.scss @@ -0,0 +1,53 @@ +// ---- LIGHT-THEME------- +html { + background-color: $backgroundColorLight; + color: $fontColorLight; + + header .logo { + background-image: url($logoImgLight); + } + + h1 { + color: $fontColorLight; + } + + button { + background-color: $backgroundColorLight; + color: $primaryColorLight; + border: 2px solid $primaryColorLight; + + &:hover { + background-color: $primaryColorHoverLight; + border: 2px solid $primaryColorHoverLight; + } + + &.primary { + background-color: $primaryColor; + color: $fontColor; + border: none; + box-shadow: 0px 10px 30px $primaryColor; + &:hover { + background-color: $primaryColorHover; + } + } + } + + input { + background-color: $backgroundColorLight; + color: $fontColorLight; + } + + #qrcode { + svg rect[style*="fill:white"] { + fill: $backgroundColorLight !important; + } + + svg rect[style*="fill:black"] { + fill: $fontColorLight !important; + } + } + + footer { + background-image: url($footerimgLight); + } +} \ No newline at end of file diff --git a/internal/login/static/resources/themes/scss/main.scss b/internal/login/static/resources/themes/scss/main.scss new file mode 100644 index 0000000000..b0a0017ebc --- /dev/null +++ b/internal/login/static/resources/themes/scss/main.scss @@ -0,0 +1,205 @@ +@import "fonts"; + +*, *::before, *::after { + box-sizing: border-box; + font-family: $standardFont; + font-size: 18px; + font-weight: 400; +} + +body { + margin: 0; +} + +html { + background-color: $backgroundColor; + color: $fontColor; +} + +h1 { + color: $fontColor; + font-family: $headerFont; + text-transform: uppercase; + text-align: center; + font-size: 40px; +} + +p { + font-width: 300; +} + +header { + padding: 8px; + + .logo { + background-image: url($logoImgDark); + background-repeat: no-repeat; + background-size: contain; + height: 80px; + margin: 30px; + } +} + +.content { + margin: auto; + padding: 20px; + width: 100%; + max-width: 500px; +} + +a { + color: $primaryColor; + text-decoration: none; + text-transform: uppercase; + font-weight: 600; + + &:hover { + color: $primaryColorHover; + } +} + +button { + text-transform: uppercase; + background-color: $backgroundColor; + color: $primaryColor; + border: 2px solid $primaryColor; + border-radius: 5px; + width: 100%; + max-width: 600px; + height: $inputHeight; + transition: all 0.3s ease 0s; + cursor: pointer; + outline: none; + &:hover { + background-color: $primaryColorHover; + border: 2px solid $primaryColorHover; + } + + &.primary { + background-color: $primaryColor; + color: $fontColor; + border: none; + &:hover { + background-color: $primaryColorHover; + } + } + + & > .sessionstate { + text-transform: lowercase; + } +} + +input:not([type='radio']), select { + background-color: $inputBackgroundColor; + color: $fontColor; + height: $inputHeight; + border: 2px solid $inputBorderColor; + border-radius: 5px; + padding-left: 15px; +} + +form { + .field { + display: grid; + padding: 10px 0; + } + + .field.radio-button { + display: flex; + + input[type='radio'] { + height: 20px; + vertical-align: middle; + } + + & label { + height: 20px; + display: inline-block; + padding: 3px 0 0 15px; + width: 100%; + } + } + + label { + color: $labelColor; + text-transform: uppercase; + font-size: 0.9rem; + margin-bottom: 3px; + + span.optional { + font-style: italic; + text-transform: none; + } + } + + .actions { + padding: 20px 0; + + .right { + float: right; + } + + button, a { + margin: 10px 0; + } + } +} + +#copy-secret { + visibility: hidden; + position: absolute; +} + +#qrcode { + text-align: center; + + svg rect[style*="fill:white"] { + fill: $backgroundColor !important; + } + + svg rect[style*="fill:black"] { + fill: $fontColor !important; + } +} + +#secret { + .copy { + float: right; + cursor: pointer; + } +} + +footer { + background-image: url($footerimgDark); + width: 100%; + background-size: cover; + height: 44vw; + position: fixed; + bottom: 0; + z-index: -1; +} + +.material-icons { + font-family: 'Material Icons'; + font-weight: normal; + font-style: normal; + font-size: 24px; /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + + /* Support for IE. */ + font-feature-settings: 'liga'; +} diff --git a/internal/login/static/resources/themes/scss/variables.scss b/internal/login/static/resources/themes/scss/variables.scss new file mode 100644 index 0000000000..03fd773f07 --- /dev/null +++ b/internal/login/static/resources/themes/scss/variables.scss @@ -0,0 +1,23 @@ +// ----- FONTS ------------ +$standardFont: Lato; +$headerFont: Aileron; + +// ----- LAYOUT ------------ +$inputHeight: 50px; + + +// ----- DARK-THEME -------- +$backgroundColor: #282828; +$fontColor: #FFFFFF; +$primaryColor: #364DF6; +$primaryColorHover: lighten($primaryColor, 10%); +$labelColor: #898989; +$inputBorderColor: #595959; +$inputBackgroundColor: #252525; + + +// ----- LIGHT-THEME -------- +$backgroundColorLight: $fontColor; +$fontColorLight: $backgroundColor; +$primaryColorLight: $primaryColor; +$primaryColorHoverLight: lighten($primaryColorLight, 10%); \ No newline at end of file diff --git a/internal/login/static/resources/themes/scss/zitadel/dark.scss b/internal/login/static/resources/themes/scss/zitadel/dark.scss new file mode 100644 index 0000000000..b34f994b21 --- /dev/null +++ b/internal/login/static/resources/themes/scss/zitadel/dark.scss @@ -0,0 +1,3 @@ +@import "../variables.scss"; +@import "./variables.scss"; +@import "../main.scss"; diff --git a/internal/login/static/resources/themes/scss/zitadel/light.scss b/internal/login/static/resources/themes/scss/zitadel/light.scss new file mode 100644 index 0000000000..112a44a1a0 --- /dev/null +++ b/internal/login/static/resources/themes/scss/zitadel/light.scss @@ -0,0 +1,4 @@ +@import "../variables.scss"; +@import "./variables.scss"; +@import "../main.scss"; +@import "../light.scss"; diff --git a/internal/login/static/resources/themes/scss/zitadel/variables.scss b/internal/login/static/resources/themes/scss/zitadel/variables.scss new file mode 100644 index 0000000000..14b52e3b9d --- /dev/null +++ b/internal/login/static/resources/themes/scss/zitadel/variables.scss @@ -0,0 +1,5 @@ +$logoImgDark: "../logo-dark.png"; +$logoImgLight: "../logo-light.png"; + +$footerimgDark: "../gradientdeco-full.svg"; +$footerimgLight: "../gradientdeco-full.svg"; \ No newline at end of file diff --git a/internal/login/static/resources/themes/zitadel/css/dark.css b/internal/login/static/resources/themes/zitadel/css/dark.css new file mode 100644 index 0000000000..ff63cfafe1 --- /dev/null +++ b/internal/login/static/resources/themes/zitadel/css/dark.css @@ -0,0 +1,257 @@ +@font-face { + font-family: Aileron; + src: url(../../../fonts/ailerons/ailerons.otf) format("opentype"); +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Thin.ttf) format("truetype"); + font-style: normal; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-ThinItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Light.ttf) format("truetype"); + font-style: normal; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-LightItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Regular.ttf) format("truetype"); + font-style: normal; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Italic.ttf) format("truetype"); + font-style: italic; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Bold.ttf) format("truetype"); + font-style: normal; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BoldItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Black.ttf) format("truetype"); + font-style: normal; + font-weight: 800; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BlackItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 800; +} +@font-face { + font-family: "Material Icons"; + font-style: normal; + font-weight: 400; + src: url(../../../fonts/material/MaterialIcons-Regular.eot); + /* For IE6-8 */ + src: local("Material Icons"), local("MaterialIcons-Regular"), url(../../../fonts/material/MaterialIcons-Regular.woff2) format("woff2"), url(../../../fonts/material/MaterialIcons-Regular.woff) format("woff"), url(../../../fonts/material/MaterialIcons-Regular.ttf) format("truetype"); +} +*, *::before, *::after { + box-sizing: border-box; + font-family: Lato; + font-size: 18px; + font-weight: 400; +} + +body { + margin: 0; +} + +html { + background-color: #282828; + color: #FFFFFF; +} + +h1 { + color: #FFFFFF; + font-family: Aileron; + text-transform: uppercase; + text-align: center; + font-size: 40px; +} + +p { + font-width: 300; +} + +header { + padding: 8px; +} +header .logo { + background-image: url("../logo-dark.png"); + background-repeat: no-repeat; + background-size: contain; + height: 80px; + margin: 30px; +} + +.content { + margin: auto; + padding: 20px; + width: 100%; + max-width: 500px; +} + +a { + color: #364DF6; + text-decoration: none; + text-transform: uppercase; + font-weight: 600; +} +a:hover { + color: #6778f8; +} + +button { + text-transform: uppercase; + background-color: #282828; + color: #364DF6; + border: 2px solid #364DF6; + border-radius: 5px; + width: 100%; + max-width: 600px; + height: 50px; + transition: all 0.3s ease 0s; + cursor: pointer; + outline: none; +} +button:hover { + background-color: #6778f8; + border: 2px solid #6778f8; +} +button.primary { + background-color: #364DF6; + color: #FFFFFF; + border: none; +} +button.primary:hover { + background-color: #6778f8; +} +button > .sessionstate { + text-transform: lowercase; +} + +input:not([type=radio]), select { + background-color: #252525; + color: #FFFFFF; + height: 50px; + border: 2px solid #595959; + border-radius: 5px; + padding-left: 15px; +} + +form .field { + display: grid; + padding: 10px 0; +} +form .field.radio-button { + display: flex; +} +form .field.radio-button input[type=radio] { + height: 20px; + vertical-align: middle; +} +form .field.radio-button label { + height: 20px; + display: inline-block; + padding: 3px 0 0 15px; + width: 100%; +} +form label { + color: #898989; + text-transform: uppercase; + font-size: 0.9rem; + margin-bottom: 3px; +} +form label span.optional { + font-style: italic; + text-transform: none; +} +form .actions { + padding: 20px 0; +} +form .actions .right { + float: right; +} +form .actions button, form .actions a { + margin: 10px 0; +} + +#copy-secret { + visibility: hidden; + position: absolute; +} + +#qrcode { + text-align: center; +} +#qrcode svg rect[style*="fill:white"] { + fill: #282828 !important; +} +#qrcode svg rect[style*="fill:black"] { + fill: #FFFFFF !important; +} + +#secret .copy { + float: right; + cursor: pointer; +} + +footer { + background-image: url("../gradientdeco-full.svg"); + width: 100%; + background-size: cover; + height: 44vw; + position: fixed; + bottom: 0; + z-index: -1; +} + +.material-icons { + font-family: "Material Icons"; + font-weight: normal; + font-style: normal; + font-size: 24px; + /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + /* Support for IE. */ + font-feature-settings: "liga"; +} + +/*# sourceMappingURL=dark.css.map */ diff --git a/internal/login/static/resources/themes/zitadel/css/dark.css.map b/internal/login/static/resources/themes/zitadel/css/dark.css.map new file mode 100644 index 0000000000..6f813dd6a2 --- /dev/null +++ b/internal/login/static/resources/themes/zitadel/css/dark.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCLc;EDMd,OCLQ;;;ADQZ;EACI,OCTQ;EDUR,aClBS;EDmBT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCvCW;EDwCX;EACA;EACA;;AAEA;EACI,OC5CY;;;ADgDpB;EACI;EACA,kBCrDc;EDsDd,OCpDW;EDqDX;EACA;EACA;EACA;EACA,QC/DU;EDgEV;EACA;EACA;;AACA;EACI,kBC7DY;ED8DZ;;AAGJ;EACI,kBCnEO;EDoEP,OCrEI;EDsEJ;;AACA;EACI,kBCtEQ;;AD0EhB;EACI;;;AAIR;EACI,kBC7EmB;ED8EnB,OCnFQ;EDoFR,QCzFU;ED0FV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OC9GK;ED+GL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKJ;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA","file":"dark.css"} \ No newline at end of file diff --git a/internal/login/static/resources/themes/zitadel/css/light.css b/internal/login/static/resources/themes/zitadel/css/light.css new file mode 100644 index 0000000000..b49348d315 --- /dev/null +++ b/internal/login/static/resources/themes/zitadel/css/light.css @@ -0,0 +1,299 @@ +@font-face { + font-family: Aileron; + src: url(../../../fonts/ailerons/ailerons.otf) format("opentype"); +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Thin.ttf) format("truetype"); + font-style: normal; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-ThinItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 100; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Light.ttf) format("truetype"); + font-style: normal; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-LightItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 200; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Regular.ttf) format("truetype"); + font-style: normal; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Italic.ttf) format("truetype"); + font-style: italic; + font-weight: 400; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Bold.ttf) format("truetype"); + font-style: normal; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BoldItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 700; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-Black.ttf) format("truetype"); + font-style: normal; + font-weight: 800; +} +@font-face { + font-family: Lato; + src: url(../../../fonts/lato/Lato-BlackItalic.ttf) format("truetype"); + font-style: italic; + font-weight: 800; +} +@font-face { + font-family: "Material Icons"; + font-style: normal; + font-weight: 400; + src: url(../../../fonts/material/MaterialIcons-Regular.eot); + /* For IE6-8 */ + src: local("Material Icons"), local("MaterialIcons-Regular"), url(../../../fonts/material/MaterialIcons-Regular.woff2) format("woff2"), url(../../../fonts/material/MaterialIcons-Regular.woff) format("woff"), url(../../../fonts/material/MaterialIcons-Regular.ttf) format("truetype"); +} +*, *::before, *::after { + box-sizing: border-box; + font-family: Lato; + font-size: 18px; + font-weight: 400; +} + +body { + margin: 0; +} + +html { + background-color: #282828; + color: #FFFFFF; +} + +h1 { + color: #FFFFFF; + font-family: Aileron; + text-transform: uppercase; + text-align: center; + font-size: 40px; +} + +p { + font-width: 300; +} + +header { + padding: 8px; +} +header .logo { + background-image: url("../logo-dark.png"); + background-repeat: no-repeat; + background-size: contain; + height: 80px; + margin: 30px; +} + +.content { + margin: auto; + padding: 20px; + width: 100%; + max-width: 500px; +} + +a { + color: #364DF6; + text-decoration: none; + text-transform: uppercase; + font-weight: 600; +} +a:hover { + color: #6778f8; +} + +button { + text-transform: uppercase; + background-color: #282828; + color: #364DF6; + border: 2px solid #364DF6; + border-radius: 5px; + width: 100%; + max-width: 600px; + height: 50px; + transition: all 0.3s ease 0s; + cursor: pointer; + outline: none; +} +button:hover { + background-color: #6778f8; + border: 2px solid #6778f8; +} +button.primary { + background-color: #364DF6; + color: #FFFFFF; + border: none; +} +button.primary:hover { + background-color: #6778f8; +} +button > .sessionstate { + text-transform: lowercase; +} + +input:not([type=radio]), select { + background-color: #252525; + color: #FFFFFF; + height: 50px; + border: 2px solid #595959; + border-radius: 5px; + padding-left: 15px; +} + +form .field { + display: grid; + padding: 10px 0; +} +form .field.radio-button { + display: flex; +} +form .field.radio-button input[type=radio] { + height: 20px; + vertical-align: middle; +} +form .field.radio-button label { + height: 20px; + display: inline-block; + padding: 3px 0 0 15px; + width: 100%; +} +form label { + color: #898989; + text-transform: uppercase; + font-size: 0.9rem; + margin-bottom: 3px; +} +form label span.optional { + font-style: italic; + text-transform: none; +} +form .actions { + padding: 20px 0; +} +form .actions .right { + float: right; +} +form .actions button, form .actions a { + margin: 10px 0; +} + +#copy-secret { + visibility: hidden; + position: absolute; +} + +#qrcode { + text-align: center; +} +#qrcode svg rect[style*="fill:white"] { + fill: #282828 !important; +} +#qrcode svg rect[style*="fill:black"] { + fill: #FFFFFF !important; +} + +#secret .copy { + float: right; + cursor: pointer; +} + +footer { + background-image: url("../gradientdeco-full.svg"); + width: 100%; + background-size: cover; + height: 44vw; + position: fixed; + bottom: 0; + z-index: -1; +} + +.material-icons { + font-family: "Material Icons"; + font-weight: normal; + font-style: normal; + font-size: 24px; + /* Preferred icon size */ + display: inline-block; + line-height: 1; + text-transform: none; + letter-spacing: normal; + word-wrap: normal; + white-space: nowrap; + direction: ltr; + /* Support for all WebKit browsers. */ + -webkit-font-smoothing: antialiased; + /* Support for Safari and Chrome. */ + text-rendering: optimizeLegibility; + /* Support for Firefox. */ + -moz-osx-font-smoothing: grayscale; + /* Support for IE. */ + font-feature-settings: "liga"; +} + +html { + background-color: #FFFFFF; + color: #282828; +} +html header .logo { + background-image: url("../logo-light.png"); +} +html h1 { + color: #282828; +} +html button { + background-color: #FFFFFF; + color: #364DF6; + border: 2px solid #364DF6; +} +html button:hover { + background-color: #6778f8; + border: 2px solid #6778f8; +} +html button.primary { + background-color: #364DF6; + color: #FFFFFF; + border: none; + box-shadow: 0px 10px 30px #364DF6; +} +html button.primary:hover { + background-color: #6778f8; +} +html input { + background-color: #FFFFFF; + color: #282828; +} +html #qrcode svg rect[style*="fill:white"] { + fill: #FFFFFF !important; +} +html #qrcode svg rect[style*="fill:black"] { + fill: #282828 !important; +} +html footer { + background-image: url("../gradientdeco-full.svg"); +} + +/*# sourceMappingURL=light.css.map */ diff --git a/internal/login/static/resources/themes/zitadel/css/light.css.map b/internal/login/static/resources/themes/zitadel/css/light.css.map new file mode 100644 index 0000000000..b6e2b250ab --- /dev/null +++ b/internal/login/static/resources/themes/zitadel/css/light.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../../scss/fonts.scss","../../scss/main.scss","../../scss/variables.scss","../../scss/light.scss"],"names":[],"mappings":"AACA;EACI;EACA;;AAIJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAEJ;EACI;EACA;EACA;EACA;;AAIJ;EACI;EACA;EACA;EACA;AAA6D;EAC7D;;AC5EJ;EACI;EACA,aCHW;EDIX;EACA;;;AAGJ;EACI;;;AAGJ;EACI,kBCLc;EDMd,OCLQ;;;ADQZ;EACI,OCTQ;EDUR,aClBS;EDmBT;EACA;EACA;;;AAGJ;EACI;;;AAGJ;EACI;;AAEA;EACI;EACA;EACA;EACA;EACA;;;AAIR;EACI;EACA;EACA;EACA;;;AAGJ;EACI,OCvCW;EDwCX;EACA;EACA;;AAEA;EACI,OC5CY;;;ADgDpB;EACI;EACA,kBCrDc;EDsDd,OCpDW;EDqDX;EACA;EACA;EACA;EACA,QC/DU;EDgEV;EACA;EACA;;AACA;EACI,kBC7DY;ED8DZ;;AAGJ;EACI,kBCnEO;EDoEP,OCrEI;EDsEJ;;AACA;EACI,kBCtEQ;;AD0EhB;EACI;;;AAIR;EACI,kBC7EmB;ED8EnB,OCnFQ;EDoFR,QCzFU;ED0FV;EACA;EACA;;;AAIA;EACI;EACA;;AAGJ;EACI;;AAEA;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAIR;EACI,OC9GK;ED+GL;EACA;EACA;;AAEA;EACI;EACA;;AAIR;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKZ;EACI;EACA;;;AAGJ;EACI;;AAEA;EACI;;AAGJ;EACI;;;AAKJ;EACI;EACA;;;AAIR;EACI;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGJ;EACI;EACA;EACA;EACA;AAAkB;EAClB;EACA;EACA;EACA;EACA;EACA;EACA;AAEA;EACA;AACA;EACA;AAEA;EACA;AAEA;EACA;;;AE1MJ;EACI,kBDQQ;ECPR,ODMc;;ACJd;EACI;;AAGJ;EACI,ODDU;;ACId;EACI,kBDJI;ECKJ,ODJO;ECKP;;AAEA;EACI,kBDGa;ECFb;;AAGJ;EACI,kBDbG;ECcH,ODfA;ECgBA;EACA;;AACA;EACI,kBDjBI;;ACsBhB;EACI,kBDzBI;EC0BJ,OD3BU;;AC+BV;EACI;;AAGJ;EACI;;AAIR;EACI","file":"light.css"} \ No newline at end of file diff --git a/internal/login/static/resources/themes/zitadel/favicon.ico b/internal/login/static/resources/themes/zitadel/favicon.ico new file mode 100644 index 0000000000..b488a5d341 Binary files /dev/null and b/internal/login/static/resources/themes/zitadel/favicon.ico differ diff --git a/internal/login/static/resources/themes/zitadel/gradientdeco-full.svg b/internal/login/static/resources/themes/zitadel/gradientdeco-full.svg new file mode 100644 index 0000000000..bd2418a23b --- /dev/null +++ b/internal/login/static/resources/themes/zitadel/gradientdeco-full.svg @@ -0,0 +1,50 @@ + + + diff --git a/internal/login/static/resources/themes/zitadel/logo-dark.png b/internal/login/static/resources/themes/zitadel/logo-dark.png new file mode 100644 index 0000000000..b77c080722 Binary files /dev/null and b/internal/login/static/resources/themes/zitadel/logo-dark.png differ diff --git a/internal/login/static/resources/themes/zitadel/logo-light.png b/internal/login/static/resources/themes/zitadel/logo-light.png new file mode 100644 index 0000000000..365021ab49 Binary files /dev/null and b/internal/login/static/resources/themes/zitadel/logo-light.png differ diff --git a/internal/login/static/templates/change_password.html b/internal/login/static/templates/change_password.html new file mode 100644 index 0000000000..1874206202 --- /dev/null +++ b/internal/login/static/templates/change_password.html @@ -0,0 +1,32 @@ +{{template "main-top" .}} + + +
{{t "PasswordChange.Description"}}
+ + + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/change_password_done.html b/internal/login/static/templates/change_password_done.html new file mode 100644 index 0000000000..8ff07063bd --- /dev/null +++ b/internal/login/static/templates/change_password_done.html @@ -0,0 +1,19 @@ +{{template "main-top" .}} + + +{{t "PasswordChangeDone.Description"}}
+ + + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/error-message.html b/internal/login/static/templates/error-message.html new file mode 100644 index 0000000000..8bee342aa1 --- /dev/null +++ b/internal/login/static/templates/error-message.html @@ -0,0 +1,9 @@ +{{ define "error-message" }} +{{if .ErrMessage }} +{{t "InitPassword.Description" }}
+ + + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/init_password_done.html b/internal/login/static/templates/init_password_done.html new file mode 100644 index 0000000000..cae159ef6b --- /dev/null +++ b/internal/login/static/templates/init_password_done.html @@ -0,0 +1,17 @@ +{{template "main-top" .}} + + +{{t "PasswordSetDone.Description"}}
+ + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/init_user.html b/internal/login/static/templates/init_user.html new file mode 100644 index 0000000000..3383ed64bf --- /dev/null +++ b/internal/login/static/templates/init_user.html @@ -0,0 +1,37 @@ +{{template "main-top" .}} + + +{{t "InitUser.Description" }}
+ + + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/init_user_done.html b/internal/login/static/templates/init_user_done.html new file mode 100644 index 0000000000..62d9fa0e7b --- /dev/null +++ b/internal/login/static/templates/init_user_done.html @@ -0,0 +1,17 @@ +{{template "main-top" .}} + + +{{t "InitUserDone.Description"}}
+ + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/login.html b/internal/login/static/templates/login.html new file mode 100644 index 0000000000..a9c8a3b6b5 --- /dev/null +++ b/internal/login/static/templates/login.html @@ -0,0 +1,27 @@ +{{template "main-top" .}} + +{{t "Login.Description"}}
+ + + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/logout_done.html b/internal/login/static/templates/logout_done.html new file mode 100644 index 0000000000..3416a808f1 --- /dev/null +++ b/internal/login/static/templates/logout_done.html @@ -0,0 +1,15 @@ +{{template "main-top" .}} + + +{{t "LogoutDone.Description"}}
+ + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/mail_verification.html b/internal/login/static/templates/mail_verification.html new file mode 100644 index 0000000000..b70863d586 --- /dev/null +++ b/internal/login/static/templates/mail_verification.html @@ -0,0 +1,31 @@ +{{template "main-top" .}} + + +{{t "EmailVerification.Description"}}
+ + + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/mail_verified.html b/internal/login/static/templates/mail_verified.html new file mode 100644 index 0000000000..e7b212f8ce --- /dev/null +++ b/internal/login/static/templates/mail_verified.html @@ -0,0 +1,19 @@ +{{template "main-top" .}} + + +{{t "EmailVerificationDone.Description"}}
+ + + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/main.html b/internal/login/static/templates/main.html new file mode 100644 index 0000000000..5b9aab1f6b --- /dev/null +++ b/internal/login/static/templates/main.html @@ -0,0 +1,34 @@ +{{define "main-top"}} + + + + + + + + {{if .ThemeMode}} + + {{else}} + + + {{end}} + + +{{t "MfaInitDone.Description"}}
+ + + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/mfa_init_verify.html b/internal/login/static/templates/mfa_init_verify.html new file mode 100644 index 0000000000..fe1f472e2b --- /dev/null +++ b/internal/login/static/templates/mfa_init_verify.html @@ -0,0 +1,47 @@ +{{template "main-top" .}} + + +{{t "MfaInitVerify.Description"}}
+ + + + + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/mfa_prompt.html b/internal/login/static/templates/mfa_prompt.html new file mode 100644 index 0000000000..0f2b2581cd --- /dev/null +++ b/internal/login/static/templates/mfa_prompt.html @@ -0,0 +1,30 @@ +{{template "main-top" .}} + + +{{t "MfaVerify.Description"}}
+ + + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/password.html b/internal/login/static/templates/password.html new file mode 100644 index 0000000000..4b813f2b2b --- /dev/null +++ b/internal/login/static/templates/password.html @@ -0,0 +1,33 @@ +{{template "main-top" .}} + + +{{t "PasswordResetDone.Description"}}
+ + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/static/templates/register.html b/internal/login/static/templates/register.html new file mode 100644 index 0000000000..83de5f3535 --- /dev/null +++ b/internal/login/static/templates/register.html @@ -0,0 +1,61 @@ +{{template "main-top" .}} + +{{t "Registration.Description"}}
+ + + + +{{template "main-bottom" .}} diff --git a/internal/login/static/templates/select_user.html b/internal/login/static/templates/select_user.html new file mode 100644 index 0000000000..1dc69726af --- /dev/null +++ b/internal/login/static/templates/select_user.html @@ -0,0 +1,25 @@ +{{template "main-top" .}} + + +{{t "UserSelection.Description"}}
+ + + + +{{template "main-bottom" .}} + \ No newline at end of file diff --git a/internal/login/statik/generate.go b/internal/login/statik/generate.go new file mode 100644 index 0000000000..75330afad9 --- /dev/null +++ b/internal/login/statik/generate.go @@ -0,0 +1,3 @@ +package statik + +//go:generate statik -src=../static -dest=.. -ns=login diff --git a/internal/management/auth/token_verifier.go b/internal/management/auth/token_verifier.go index 84ba0abe38..842874c568 100644 --- a/internal/management/auth/token_verifier.go +++ b/internal/management/auth/token_verifier.go @@ -3,23 +3,34 @@ package auth import ( "context" "github.com/caos/zitadel/internal/api/auth" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" +) + +const ( + mgmtName = "Management-API" ) type TokenVerifier struct { + mgmtID string + authZRepo *authz_repo.EsRepository } -func Start() (v *TokenVerifier) { - return new(TokenVerifier) +func Start(authZRepo *authz_repo.EsRepository) (v *TokenVerifier) { + return &TokenVerifier{authZRepo: authZRepo} } func (v *TokenVerifier) VerifyAccessToken(ctx context.Context, token string) (string, string, string, error) { - return "", "", "", nil + userID, clientID, agentID, err := v.authZRepo.VerifyAccessToken(ctx, token, mgmtName, v.mgmtID) + if clientID != "" { + v.mgmtID = clientID + } + return userID, clientID, agentID, err } -func (v *TokenVerifier) ResolveGrants(ctx context.Context, userID, orgID string) ([]*auth.Grant, error) { - return nil, nil +func (v *TokenVerifier) ResolveGrant(ctx context.Context) (*auth.Grant, error) { + return v.authZRepo.ResolveGrants(ctx) } func (v *TokenVerifier) GetProjectIDByClientID(ctx context.Context, clientID string) (string, error) { - return "", nil + return v.authZRepo.ProjectIDByClientID(ctx, clientID) } diff --git a/internal/management/repository/eventsourcing/eventstore/project.go b/internal/management/repository/eventsourcing/eventstore/project.go index 810c90d22b..f0e1b31f0b 100644 --- a/internal/management/repository/eventsourcing/eventstore/project.go +++ b/internal/management/repository/eventsourcing/eventstore/project.go @@ -2,6 +2,8 @@ package eventstore import ( "context" + "github.com/caos/zitadel/internal/api/auth" + global_model "github.com/caos/zitadel/internal/model" "strings" "github.com/caos/zitadel/internal/management/repository/eventsourcing/view" @@ -41,6 +43,13 @@ func (repo *ProjectRepo) ReactivateProject(ctx context.Context, id string) (*pro func (repo *ProjectRepo) SearchGrantedProjects(ctx context.Context, request *proj_model.GrantedProjectSearchRequest) (*proj_model.GrantedProjectSearchResponse, error) { request.EnsureLimit(repo.SearchLimit) + + permissions := auth.GetPermissionsFromCtx(ctx) + if !auth.HasGlobalPermission(permissions) { + ids := auth.GetPermissionCtxIDs(permissions) + request.Queries = append(request.Queries, &proj_model.GrantedProjectSearchQuery{Key: proj_model.GRANTEDPROJECTSEARCHKEY_PROJECTID, Method: global_model.SEARCHMETHOD_IN, Value: ids}) + } + projects, count, err := repo.View.SearchGrantedProjects(request) if err != nil { return nil, err diff --git a/internal/management/repository/eventsourcing/handler/org.go b/internal/management/repository/eventsourcing/handler/org.go index cddecd83be..832f9e984e 100644 --- a/internal/management/repository/eventsourcing/handler/org.go +++ b/internal/management/repository/eventsourcing/handler/org.go @@ -1,12 +1,12 @@ package handler import ( + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "time" "github.com/caos/logging" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/spooler" - org_model "github.com/caos/zitadel/internal/org/model" "github.com/caos/zitadel/internal/org/repository/eventsourcing" "github.com/caos/zitadel/internal/org/repository/view" ) @@ -37,9 +37,9 @@ func (o *Org) Process(event *es_models.Event) error { org := new(view.OrgView) switch event.Type { - case org_model.OrgAdded: + case model.OrgAdded: org.AppendEvent(event) - case org_model.OrgChanged: + case model.OrgChanged: err := org.SetData(event) if err != nil { return err diff --git a/internal/management/repository/eventsourcing/handler/org_member.go b/internal/management/repository/eventsourcing/handler/org_member.go index 79b0e0bce7..089e8a351e 100644 --- a/internal/management/repository/eventsourcing/handler/org_member.go +++ b/internal/management/repository/eventsourcing/handler/org_member.go @@ -2,13 +2,13 @@ package handler import ( "context" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "time" "github.com/caos/logging" "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/spooler" - org_model "github.com/caos/zitadel/internal/org/model" view_model "github.com/caos/zitadel/internal/org/repository/view" usr_model "github.com/caos/zitadel/internal/user/model" usr_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" @@ -36,13 +36,13 @@ func (m *OrgMember) EventQuery() (*models.SearchQuery, error) { return nil, err } return es_models.NewSearchQuery(). - AggregateTypeFilter(org_model.OrgAggregate, usr_es_model.UserAggregate). + AggregateTypeFilter(model.OrgAggregate, usr_es_model.UserAggregate). LatestSequenceFilter(sequence), nil } func (m *OrgMember) Process(event *models.Event) (err error) { switch event.AggregateType { - case org_model.OrgAggregate: + case model.OrgAggregate: err = m.processOrgMember(event) case usr_es_model.UserAggregate: err = m.processUser(event) @@ -53,10 +53,10 @@ func (m *OrgMember) Process(event *models.Event) (err error) { func (m *OrgMember) processOrgMember(event *models.Event) (err error) { member := new(view_model.OrgMemberView) switch event.Type { - case org_model.OrgMemberAdded: + case model.OrgMemberAdded: member.AppendEvent(event) m.fillData(member) - case org_model.OrgMemberChanged: + case model.OrgMemberChanged: err := member.SetData(event) if err != nil { return err @@ -66,7 +66,7 @@ func (m *OrgMember) processOrgMember(event *models.Event) (err error) { return err } member.AppendEvent(event) - case org_model.OrgMemberRemoved: + case model.OrgMemberRemoved: err := member.SetData(event) if err != nil { return err diff --git a/internal/model/search_method.go b/internal/model/search_method.go index 914a728024..9ad66d0e8a 100644 --- a/internal/model/search_method.go +++ b/internal/model/search_method.go @@ -10,4 +10,7 @@ const ( SEARCHMETHOD_STARTS_WITH_IGNORE_CASE SEARCHMETHOD_CONTAINS_IGNORE_CASE SEARCHMETHOD_NOT_EQUALS + SEARCHMETHOD_GREATER_THAN + SEARCHMETHOD_LESS_THAN + SEARCHMETHOD_IN ) diff --git a/internal/notification/types/email_verification_code.go b/internal/notification/types/email_verification_code.go index dd03d2705f..fd0a6d043c 100644 --- a/internal/notification/types/email_verification_code.go +++ b/internal/notification/types/email_verification_code.go @@ -30,5 +30,5 @@ func SendEmailVerificationCode(user *view_model.NotifyUser, code *es_model.Email if err != nil { return err } - return generateEmail(user, template, systemDefaults.Notifications, true) + return generateEmail(user, systemDefaults.Notifications.TemplateData.VerifyEmail.Subject, template, systemDefaults.Notifications, true) } diff --git a/internal/notification/types/init_code.go b/internal/notification/types/init_code.go index 4ece7e3ae6..0c73e3f7d8 100644 --- a/internal/notification/types/init_code.go +++ b/internal/notification/types/init_code.go @@ -35,5 +35,5 @@ func SendUserInitCode(user *view_model.NotifyUser, code *es_model.InitUserCode, if err != nil { return err } - return generateEmail(user, template, systemDefaults.Notifications, true) + return generateEmail(user, systemDefaults.Notifications.TemplateData.InitCode.Subject, template, systemDefaults.Notifications, true) } diff --git a/internal/notification/types/password_code.go b/internal/notification/types/password_code.go index 0bfc236a7e..b3843185de 100644 --- a/internal/notification/types/password_code.go +++ b/internal/notification/types/password_code.go @@ -30,5 +30,5 @@ func SendPasswordCode(user *view_model.NotifyUser, code *es_model.PasswordCode, if err != nil { return err } - return generateEmail(user, template, systemDefaults.Notifications, false) + return generateEmail(user, systemDefaults.Notifications.TemplateData.PasswordReset.Subject, template, systemDefaults.Notifications, false) } diff --git a/internal/notification/types/user_email.go b/internal/notification/types/user_email.go index c916a6c8af..d6b3928e2e 100644 --- a/internal/notification/types/user_email.go +++ b/internal/notification/types/user_email.go @@ -9,7 +9,7 @@ import ( view_model "github.com/caos/zitadel/internal/user/repository/view/model" ) -func generateEmail(user *view_model.NotifyUser, content string, config systemdefaults.Notifications, lastEmail bool) error { +func generateEmail(user *view_model.NotifyUser, subject, content string, config systemdefaults.Notifications, lastEmail bool) error { provider, err := email.InitEmailProvider(config.Providers.Email) if err != nil { return err @@ -17,7 +17,7 @@ func generateEmail(user *view_model.NotifyUser, content string, config systemdef message := &email.EmailMessage{ SenderEmail: config.Providers.Email.From, Recipients: []string{user.VerifiedEmail}, - Subject: config.TemplateData.InitCode.Subject, + Subject: subject, Content: content, } if lastEmail { diff --git a/internal/org/repository/eventsourcing/eventstore.go b/internal/org/repository/eventsourcing/eventstore.go index 5e5b22d1be..6ccf48d89f 100644 --- a/internal/org/repository/eventsourcing/eventstore.go +++ b/internal/org/repository/eventsourcing/eventstore.go @@ -8,6 +8,7 @@ import ( es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/id" org_model "github.com/caos/zitadel/internal/org/model" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" ) type OrgEventstore struct { @@ -26,7 +27,7 @@ func StartOrg(conf OrgConfig) *OrgEventstore { } } -func (es *OrgEventstore) PrepareCreateOrg(ctx context.Context, orgModel *org_model.Org) (*Org, []*es_models.Aggregate, error) { +func (es *OrgEventstore) PrepareCreateOrg(ctx context.Context, orgModel *org_model.Org) (*model.Org, []*es_models.Aggregate, error) { if orgModel == nil || !orgModel.IsValid() { return nil, nil, errors.ThrowInvalidArgument(nil, "EVENT-OeLSk", "org not valid") } @@ -35,7 +36,7 @@ func (es *OrgEventstore) PrepareCreateOrg(ctx context.Context, orgModel *org_mod return nil, nil, errors.ThrowInternal(err, "EVENT-OwciI", "id gen failed") } orgModel.AggregateID = id - org := OrgFromModel(orgModel) + org := model.OrgFromModel(orgModel) aggregates, err := orgCreatedAggregates(ctx, es.AggregateCreator(), org) @@ -49,7 +50,7 @@ func (es *OrgEventstore) CreateOrg(ctx context.Context, orgModel *org_model.Org) return nil, err } - return OrgToModel(org), nil + return model.OrgToModel(org), nil } func (es *OrgEventstore) OrgByID(ctx context.Context, org *org_model.Org) (*org_model.Org, error) { @@ -61,7 +62,7 @@ func (es *OrgEventstore) OrgByID(ctx context.Context, org *org_model.Org) (*org_ return nil, err } - esOrg := OrgFromModel(org) + esOrg := model.OrgFromModel(org) err = es_sdk.Filter(ctx, es.FilterEvents, esOrg.AppendEvents, query) if err != nil && !errors.IsNotFound(err) { return nil, err @@ -70,7 +71,7 @@ func (es *OrgEventstore) OrgByID(ctx context.Context, org *org_model.Org) (*org_ return nil, errors.ThrowNotFound(nil, "EVENT-kVLb2", "org not found") } - return OrgToModel(esOrg), nil + return model.OrgToModel(esOrg), nil } func (es *OrgEventstore) IsOrgUnique(ctx context.Context, name, domain string) (isUnique bool, err error) { @@ -93,7 +94,7 @@ func isUniqueValidation(unique *bool) func(events ...*es_models.Event) error { if len(events) == 0 { return nil } - *unique = *unique || events[0].Type == org_model.OrgDomainReserved || events[0].Type == org_model.OrgNameReserved + *unique = *unique || events[0].Type == model.OrgDomainReserved || events[0].Type == model.OrgNameReserved return nil } @@ -104,7 +105,7 @@ func (es *OrgEventstore) DeactivateOrg(ctx context.Context, orgID string) (*org_ if err != nil { return nil, errors.ThrowInvalidArgument(nil, "EVENT-oL9nT", "org not found") } - org := OrgFromModel(existingOrg) + org := model.OrgFromModel(existingOrg) aggregate := orgDeactivateAggregate(es.AggregateCreator(), org) err = es_sdk.Push(ctx, es.PushAggregates, org.AppendEvents, aggregate) @@ -112,7 +113,7 @@ func (es *OrgEventstore) DeactivateOrg(ctx context.Context, orgID string) (*org_ return nil, err } - return OrgToModel(org), nil + return model.OrgToModel(org), nil } func (es *OrgEventstore) ReactivateOrg(ctx context.Context, orgID string) (*org_model.Org, error) { @@ -120,7 +121,7 @@ func (es *OrgEventstore) ReactivateOrg(ctx context.Context, orgID string) (*org_ if err != nil { return nil, errors.ThrowInvalidArgument(nil, "EVENT-oL9nT", "org not set") } - org := OrgFromModel(existingOrg) + org := model.OrgFromModel(existingOrg) aggregate := orgReactivateAggregate(es.AggregateCreator(), org) err = es_sdk.Push(ctx, es.PushAggregates, org.AppendEvents, aggregate) @@ -128,7 +129,7 @@ func (es *OrgEventstore) ReactivateOrg(ctx context.Context, orgID string) (*org_ return nil, err } - return OrgToModel(org), nil + return model.OrgToModel(org), nil } func (es *OrgEventstore) OrgMemberByIDs(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) { @@ -150,12 +151,12 @@ func (es *OrgEventstore) OrgMemberByIDs(ctx context.Context, member *org_model.O return nil, errors.ThrowNotFound(nil, "EVENT-SXji6", "member not found") } -func (es *OrgEventstore) PrepareAddOrgMember(ctx context.Context, member *org_model.OrgMember) (*OrgMember, *es_models.Aggregate, error) { +func (es *OrgEventstore) PrepareAddOrgMember(ctx context.Context, member *org_model.OrgMember) (*model.OrgMember, *es_models.Aggregate, error) { if member == nil || !member.IsValid() { return nil, nil, errors.ThrowPreconditionFailed(nil, "EVENT-9dk45", "UserID and Roles are required") } - repoMember := OrgMemberFromModel(member) + repoMember := model.OrgMemberFromModel(member) addAggregate, err := orgMemberAddedAggregate(ctx, es.Eventstore.AggregateCreator(), repoMember) return repoMember, addAggregate, err @@ -171,7 +172,7 @@ func (es *OrgEventstore) AddOrgMember(ctx context.Context, member *org_model.Org return nil, err } - return OrgMemberToModel(repoMember), nil + return model.OrgMemberToModel(repoMember), nil } func (es *OrgEventstore) ChangeOrgMember(ctx context.Context, member *org_model.OrgMember) (*org_model.OrgMember, error) { @@ -185,8 +186,8 @@ func (es *OrgEventstore) ChangeOrgMember(ctx context.Context, member *org_model. } member.ObjectRoot = existingMember.ObjectRoot - repoMember := OrgMemberFromModel(member) - repoExistingMember := OrgMemberFromModel(existingMember) + repoMember := model.OrgMemberFromModel(member) + repoExistingMember := model.OrgMemberFromModel(existingMember) orgAggregate := orgMemberChangedAggregate(es.Eventstore.AggregateCreator(), repoExistingMember, repoMember) err = es_sdk.Push(ctx, es.PushAggregates, repoMember.AppendEvents, orgAggregate) @@ -194,7 +195,7 @@ func (es *OrgEventstore) ChangeOrgMember(ctx context.Context, member *org_model. return nil, err } - return OrgMemberToModel(repoMember), nil + return model.OrgMemberToModel(repoMember), nil } func (es *OrgEventstore) RemoveOrgMember(ctx context.Context, member *org_model.OrgMember) error { @@ -211,7 +212,7 @@ func (es *OrgEventstore) RemoveOrgMember(ctx context.Context, member *org_model. } member.ObjectRoot = existingMember.ObjectRoot - repoMember := OrgMemberFromModel(member) + repoMember := model.OrgMemberFromModel(member) orgAggregate := orgMemberRemovedAggregate(es.Eventstore.AggregateCreator(), repoMember) return es_sdk.Push(ctx, es.PushAggregates, repoMember.AppendEvents, orgAggregate) diff --git a/internal/org/repository/eventsourcing/eventstore_test.go b/internal/org/repository/eventsourcing/eventstore_test.go index 4cfa83302d..bf9cad3dee 100644 --- a/internal/org/repository/eventsourcing/eventstore_test.go +++ b/internal/org/repository/eventsourcing/eventstore_test.go @@ -2,6 +2,7 @@ package eventsourcing import ( "context" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "testing" "time" @@ -428,7 +429,7 @@ func TestOrgEventstore_OrgMemberByIDs(t *testing.T) { { name: "new events found and added success", fields: fields{Eventstore: newTestEventstore(t).expectFilterEvents([]*es_models.Event{ - {Sequence: 6, Data: []byte("{\"userId\": \"banana\", \"roles\": [\"bananaa\"]}"), Type: org_model.OrgMemberChanged}, + {Sequence: 6, Data: []byte("{\"userId\": \"banana\", \"roles\": [\"bananaa\"]}"), Type: model.OrgMemberChanged}, }, nil)}, args: args{ ctx: auth.NewMockContext("user", "org"), @@ -442,8 +443,8 @@ func TestOrgEventstore_OrgMemberByIDs(t *testing.T) { { name: "not member of org error", fields: fields{Eventstore: newTestEventstore(t).expectFilterEvents([]*es_models.Event{ - {Sequence: 6, Data: []byte("{\"userId\": \"banana\", \"roles\": [\"bananaa\"]}"), Type: org_model.OrgMemberAdded}, - {Sequence: 7, Data: []byte("{\"userId\": \"apple\"}"), Type: org_model.OrgMemberRemoved}, + {Sequence: 6, Data: []byte("{\"userId\": \"banana\", \"roles\": [\"bananaa\"]}"), Type: model.OrgMemberAdded}, + {Sequence: 7, Data: []byte("{\"userId\": \"apple\"}"), Type: model.OrgMemberRemoved}, }, nil)}, args: args{ ctx: auth.NewMockContext("user", "org"), @@ -511,7 +512,7 @@ func TestOrgEventstore_AddOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, @@ -541,7 +542,7 @@ func TestOrgEventstore_AddOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, @@ -570,7 +571,7 @@ func TestOrgEventstore_AddOrgMember(t *testing.T) { expectAggregateCreator(). expectFilterEvents([]*es_models.Event{ { - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, @@ -600,12 +601,12 @@ func TestOrgEventstore_AddOrgMember(t *testing.T) { expectPushEvents(10, nil). expectFilterEvents([]*es_models.Event{ { - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, { - Type: org_model.OrgMemberRemoved, + Type: model.OrgMemberRemoved, Data: []byte(`{"userId": "hodor"}`), Sequence: 10, }, @@ -708,13 +709,13 @@ func TestOrgEventstore_ChangeOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "brudi", "roles": ["master of desaster"]}`), Sequence: 6, }, @@ -740,13 +741,13 @@ func TestOrgEventstore_ChangeOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, @@ -772,13 +773,13 @@ func TestOrgEventstore_ChangeOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, @@ -805,13 +806,13 @@ func TestOrgEventstore_ChangeOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, @@ -890,13 +891,13 @@ func TestOrgEventstore_RemoveOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "brudi", "roles": ["master of desaster"]}`), Sequence: 6, }, @@ -921,13 +922,13 @@ func TestOrgEventstore_RemoveOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, @@ -952,13 +953,13 @@ func TestOrgEventstore_RemoveOrgMember(t *testing.T) { expectFilterEvents([]*es_models.Event{ { AggregateID: "hodor-org", - Type: org_model.OrgAdded, + Type: model.OrgAdded, Sequence: 4, Data: []byte("{}"), }, { AggregateID: "hodor-org", - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId": "hodor", "roles": ["master"]}`), Sequence: 6, }, @@ -996,7 +997,7 @@ func TestOrgEventstore_RemoveOrgMember(t *testing.T) { func orgCreatedEvent() *es_models.Event { return &es_models.Event{ AggregateID: "hodor-org", - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, AggregateVersion: "v1", CreationDate: time.Now().Add(-1 * time.Minute), Data: []byte(`{"name": "hodor-org", "domain":"hodor.org"}`), @@ -1005,14 +1006,14 @@ func orgCreatedEvent() *es_models.Event { ID: "sdlfö4t23kj", ResourceOwner: "hodor-org", Sequence: 32, - Type: org_model.OrgAdded, + Type: model.OrgAdded, } } func orgInactiveEvent() *es_models.Event { return &es_models.Event{ AggregateID: "hodor-org", - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, AggregateVersion: "v1", CreationDate: time.Now().Add(-1 * time.Minute), Data: nil, @@ -1021,6 +1022,6 @@ func orgInactiveEvent() *es_models.Event { ID: "sdlfö4t23kj", ResourceOwner: "hodor-org", Sequence: 52, - Type: org_model.OrgDeactivated, + Type: model.OrgDeactivated, } } diff --git a/internal/org/repository/eventsourcing/member_model.go b/internal/org/repository/eventsourcing/model/member_model.go similarity index 95% rename from internal/org/repository/eventsourcing/member_model.go rename to internal/org/repository/eventsourcing/model/member_model.go index e8483ac2c7..2390d66a97 100644 --- a/internal/org/repository/eventsourcing/member_model.go +++ b/internal/org/repository/eventsourcing/model/member_model.go @@ -1,4 +1,4 @@ -package eventsourcing +package model import ( "encoding/json" @@ -29,10 +29,10 @@ func (m *OrgMember) AppendEvents(events ...*es_models.Event) error { func (m *OrgMember) AppendEvent(event *es_models.Event) error { m.ObjectRoot.AppendEvent(event) - return m.setData(event) + return m.SetData(event) } -func (m *OrgMember) setData(event *es_models.Event) error { +func (m *OrgMember) SetData(event *es_models.Event) error { err := json.Unmarshal(event.Data, m) if err != nil { return errors.ThrowInternal(err, "EVENT-Hz7Mb", "unable to unmarshal data") diff --git a/internal/org/repository/eventsourcing/org_model.go b/internal/org/repository/eventsourcing/model/org_model.go similarity index 92% rename from internal/org/repository/eventsourcing/org_model.go rename to internal/org/repository/eventsourcing/model/org_model.go index 143a8e8a7c..cb13fe3c47 100644 --- a/internal/org/repository/eventsourcing/org_model.go +++ b/internal/org/repository/eventsourcing/model/org_model.go @@ -1,15 +1,14 @@ -package eventsourcing +package model import ( "encoding/json" - "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" org_model "github.com/caos/zitadel/internal/org/model" ) const ( - orgVersion = "v1" + OrgVersion = "v1" ) type Org struct { @@ -64,22 +63,22 @@ func (o *Org) AppendEvents(events ...*es_models.Event) error { func (o *Org) AppendEvent(event *es_models.Event) error { switch event.Type { - case org_model.OrgAdded: + case OrgAdded: *o = Org{} err := o.setData(event) if err != nil { return err } - case org_model.OrgChanged: + case OrgChanged: err := o.setData(event) if err != nil { return err } - case org_model.OrgDeactivated: + case OrgDeactivated: o.State = int32(org_model.ORGSTATE_INACTIVE) - case org_model.OrgReactivated: + case OrgReactivated: o.State = int32(org_model.ORGSTATE_ACTIVE) - case org_model.OrgMemberAdded: + case OrgMemberAdded: member, err := OrgMemberFromEvent(nil, event) if err != nil { return err @@ -87,7 +86,7 @@ func (o *Org) AppendEvent(event *es_models.Event) error { member.CreationDate = event.CreationDate o.setMember(member) - case org_model.OrgMemberChanged: + case OrgMemberChanged: member, err := OrgMemberFromEvent(nil, event) if err != nil { return err @@ -96,7 +95,7 @@ func (o *Org) AppendEvent(event *es_models.Event) error { member.CreationDate = existingMember.CreationDate o.setMember(member) - case org_model.OrgMemberRemoved: + case OrgMemberRemoved: member, err := OrgMemberFromEvent(nil, event) if err != nil { return err diff --git a/internal/org/repository/eventsourcing/org_model_test.go b/internal/org/repository/eventsourcing/model/org_model_test.go similarity index 93% rename from internal/org/repository/eventsourcing/org_model_test.go rename to internal/org/repository/eventsourcing/model/org_model_test.go index f3bad7f4c5..cfcdd950c1 100644 --- a/internal/org/repository/eventsourcing/org_model_test.go +++ b/internal/org/repository/eventsourcing/model/org_model_test.go @@ -1,4 +1,4 @@ -package eventsourcing +package model import ( "encoding/json" @@ -22,7 +22,7 @@ func TestOrgFromEvents(t *testing.T) { name: "org from events, ok", args: args{ event: []*es_models.Event{ - {AggregateID: "ID", Sequence: 1, Type: model.OrgAdded}, + {AggregateID: "ID", Sequence: 1, Type: OrgAdded}, }, org: &Org{Name: "OrgName"}, }, @@ -32,7 +32,7 @@ func TestOrgFromEvents(t *testing.T) { name: "org from events, nil org", args: args{ event: []*es_models.Event{ - {AggregateID: "ID", Sequence: 1, Type: model.OrgAdded}, + {AggregateID: "ID", Sequence: 1, Type: OrgAdded}, }, org: nil, }, @@ -66,7 +66,7 @@ func TestAppendEvent(t *testing.T) { { name: "append added event", args: args{ - event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.OrgAdded}, + event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgAdded}, org: &Org{Name: "OrgName"}, }, result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE), Name: "OrgName"}, @@ -74,7 +74,7 @@ func TestAppendEvent(t *testing.T) { { name: "append change event", args: args{ - event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.OrgChanged, Data: []byte(`{"domain": "OrgDomain"}`)}, + event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgChanged, Data: []byte(`{"domain": "OrgDomain"}`)}, org: &Org{Name: "OrgName", Domain: "asdf"}, }, result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE), Name: "OrgName", Domain: "OrgDomain"}, @@ -82,14 +82,14 @@ func TestAppendEvent(t *testing.T) { { name: "append deactivate event", args: args{ - event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.OrgDeactivated}, + event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgDeactivated}, }, result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_INACTIVE)}, }, { name: "append reactivate event", args: args{ - event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: model.OrgReactivated}, + event: &es_models.Event{AggregateID: "ID", Sequence: 1, Type: OrgReactivated}, }, result: &Org{ObjectRoot: es_models.ObjectRoot{AggregateID: "ID"}, State: int32(model.ORGSTATE_ACTIVE)}, }, diff --git a/internal/org/model/types.go b/internal/org/repository/eventsourcing/model/types.go similarity index 100% rename from internal/org/model/types.go rename to internal/org/repository/eventsourcing/model/types.go diff --git a/internal/org/repository/eventsourcing/org.go b/internal/org/repository/eventsourcing/org.go index 8c266d052f..3f18f653e8 100644 --- a/internal/org/repository/eventsourcing/org.go +++ b/internal/org/repository/eventsourcing/org.go @@ -5,6 +5,7 @@ import ( "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" org_model "github.com/caos/zitadel/internal/org/model" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" ) func OrgByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, error) { @@ -17,7 +18,7 @@ func OrgByIDQuery(id string, latestSequence uint64) (*es_models.SearchQuery, err func OrgDomainUniqueQuery(domain string) *es_models.SearchQuery { return es_models.NewSearchQuery(). - AggregateTypeFilter(org_model.OrgDomainAggregate). + AggregateTypeFilter(model.OrgDomainAggregate). AggregateIDFilter(domain). OrderDesc(). SetLimit(1) @@ -25,7 +26,7 @@ func OrgDomainUniqueQuery(domain string) *es_models.SearchQuery { func OrgNameUniqueQuery(name string) *es_models.SearchQuery { return es_models.NewSearchQuery(). - AggregateTypeFilter(org_model.OrgNameAggregate). + AggregateTypeFilter(model.OrgNameAggregate). AggregateIDFilter(name). OrderDesc(). SetLimit(1) @@ -33,15 +34,15 @@ func OrgNameUniqueQuery(name string) *es_models.SearchQuery { func OrgQuery(latestSequence uint64) *es_models.SearchQuery { return es_models.NewSearchQuery(). - AggregateTypeFilter(org_model.OrgAggregate). + AggregateTypeFilter(model.OrgAggregate). LatestSequenceFilter(latestSequence) } func OrgAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, id string, sequence uint64) (*es_models.Aggregate, error) { - return aggCreator.NewAggregate(ctx, id, org_model.OrgAggregate, orgVersion, sequence) + return aggCreator.NewAggregate(ctx, id, model.OrgAggregate, model.OrgVersion, sequence) } -func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, org *Org) (_ []*es_models.Aggregate, err error) { +func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, org *model.Org) (_ []*es_models.Aggregate, err error) { if org == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-kdie7", "org should not be nil") } @@ -56,11 +57,11 @@ func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCr return nil, err } - agg, err := aggCreator.NewAggregate(ctx, org.AggregateID, org_model.OrgAggregate, orgVersion, org.Sequence, es_models.OverwriteResourceOwner(org.AggregateID)) + agg, err := aggCreator.NewAggregate(ctx, org.AggregateID, model.OrgAggregate, model.OrgVersion, org.Sequence, es_models.OverwriteResourceOwner(org.AggregateID)) if err != nil { return nil, err } - agg, err = agg.AppendEvent(org_model.OrgAdded, org) + agg, err = agg.AppendEvent(model.OrgAdded, org) if err != nil { return nil, err } @@ -72,7 +73,7 @@ func orgCreatedAggregates(ctx context.Context, aggCreator *es_models.AggregateCr }, nil } -func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *Org, updated *Org) ([]*es_models.Aggregate, error) { +func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCreator, existing *model.Org, updated *model.Org) ([]*es_models.Aggregate, error) { if existing == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dk83d", "existing org must not be nil") } @@ -107,7 +108,7 @@ func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCre return nil, err } - orgAggregate, err = orgAggregate.AppendEvent(org_model.OrgChanged, changes) + orgAggregate, err = orgAggregate.AppendEvent(model.OrgChanged, changes) if err != nil { return nil, err } @@ -116,7 +117,7 @@ func OrgUpdateAggregates(ctx context.Context, aggCreator *es_models.AggregateCre return aggregates, nil } -func orgDeactivateAggregate(aggCreator *es_models.AggregateCreator, org *Org) func(ctx context.Context) (*es_models.Aggregate, error) { +func orgDeactivateAggregate(aggCreator *es_models.AggregateCreator, org *model.Org) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if org == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-R03z8", "existing org must not be nil") @@ -129,11 +130,11 @@ func orgDeactivateAggregate(aggCreator *es_models.AggregateCreator, org *Org) fu return nil, err } - return agg.AppendEvent(org_model.OrgDeactivated, nil) + return agg.AppendEvent(model.OrgDeactivated, nil) } } -func orgReactivateAggregate(aggCreator *es_models.AggregateCreator, org *Org) func(ctx context.Context) (*es_models.Aggregate, error) { +func orgReactivateAggregate(aggCreator *es_models.AggregateCreator, org *model.Org) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if org == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-cTHLd", "existing org must not be nil") @@ -146,40 +147,40 @@ func orgReactivateAggregate(aggCreator *es_models.AggregateCreator, org *Org) fu return nil, err } - return agg.AppendEvent(org_model.OrgReactivated, nil) + return agg.AppendEvent(model.OrgReactivated, nil) } } func uniqueDomainAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, domain string) (*es_models.Aggregate, error) { - aggregate, err := aggCreator.NewAggregate(ctx, domain, org_model.OrgDomainAggregate, orgVersion, 0) + aggregate, err := aggCreator.NewAggregate(ctx, domain, model.OrgDomainAggregate, model.OrgVersion, 0) if resourceOwner != "" { - aggregate, err = aggCreator.NewAggregate(ctx, domain, org_model.OrgDomainAggregate, orgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner)) + aggregate, err = aggCreator.NewAggregate(ctx, domain, model.OrgDomainAggregate, model.OrgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner)) } if err != nil { return nil, err } - aggregate, err = aggregate.AppendEvent(org_model.OrgDomainReserved, nil) + aggregate, err = aggregate.AppendEvent(model.OrgDomainReserved, nil) if err != nil { return nil, err } - return aggregate.SetPrecondition(OrgDomainUniqueQuery(domain), isReservedValidation(aggregate, org_model.OrgDomainReserved)), nil + return aggregate.SetPrecondition(OrgDomainUniqueQuery(domain), isReservedValidation(aggregate, model.OrgDomainReserved)), nil } func uniqueNameAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, resourceOwner, name string) (aggregate *es_models.Aggregate, err error) { - aggregate, err = aggCreator.NewAggregate(ctx, name, org_model.OrgNameAggregate, orgVersion, 0) + aggregate, err = aggCreator.NewAggregate(ctx, name, model.OrgNameAggregate, model.OrgVersion, 0) if resourceOwner != "" { - aggregate, err = aggCreator.NewAggregate(ctx, name, org_model.OrgNameAggregate, orgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner)) + aggregate, err = aggCreator.NewAggregate(ctx, name, model.OrgNameAggregate, model.OrgVersion, 0, es_models.OverwriteResourceOwner(resourceOwner)) } if err != nil { return nil, err } - aggregate, err = aggregate.AppendEvent(org_model.OrgNameReserved, nil) + aggregate, err = aggregate.AppendEvent(model.OrgNameReserved, nil) if err != nil { return nil, err } - return aggregate.SetPrecondition(OrgNameUniqueQuery(name), isReservedValidation(aggregate, org_model.OrgNameReserved)), nil + return aggregate.SetPrecondition(OrgNameUniqueQuery(name), isReservedValidation(aggregate, model.OrgNameReserved)), nil } func isReservedValidation(aggregate *es_models.Aggregate, resevedEventType es_models.EventType) func(...*es_models.Event) error { diff --git a/internal/org/repository/eventsourcing/org_member.go b/internal/org/repository/eventsourcing/org_member.go index 106ca3ff2f..26ff8b6582 100644 --- a/internal/org/repository/eventsourcing/org_member.go +++ b/internal/org/repository/eventsourcing/org_member.go @@ -2,33 +2,33 @@ package eventsourcing import ( "context" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" - org_model "github.com/caos/zitadel/internal/org/model" usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" ) -func orgMemberAddedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, member *OrgMember) (*es_models.Aggregate, error) { +func orgMemberAddedAggregate(ctx context.Context, aggCreator *es_models.AggregateCreator, member *model.OrgMember) (*es_models.Aggregate, error) { if member == nil { return nil, errors.ThrowInvalidArgument(nil, "EVENT-c63Ap", "member must not be nil") } - aggregate, err := aggCreator.NewAggregate(ctx, member.AggregateID, org_model.OrgAggregate, orgVersion, member.Sequence) + aggregate, err := aggCreator.NewAggregate(ctx, member.AggregateID, model.OrgAggregate, model.OrgVersion, member.Sequence) if err != nil { return nil, err } validationQuery := es_models.NewSearchQuery(). - AggregateTypeFilter(org_model.OrgAggregate, usr_model.UserAggregate). + AggregateTypeFilter(model.OrgAggregate, usr_model.UserAggregate). AggregateIDsFilter(member.AggregateID, member.UserID) validation := addMemberValidation(aggregate, member) - return aggregate.SetPrecondition(validationQuery, validation).AppendEvent(org_model.OrgMemberAdded, member) + return aggregate.SetPrecondition(validationQuery, validation).AppendEvent(model.OrgMemberAdded, member) } -func orgMemberChangedAggregate(aggCreator *es_models.AggregateCreator, existingMember *OrgMember, member *OrgMember) func(ctx context.Context) (*es_models.Aggregate, error) { +func orgMemberChangedAggregate(aggCreator *es_models.AggregateCreator, existingMember *model.OrgMember, member *model.OrgMember) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if member == nil || existingMember == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-d34fs", "member must not be nil") @@ -43,11 +43,11 @@ func orgMemberChangedAggregate(aggCreator *es_models.AggregateCreator, existingM if err != nil { return nil, err } - return agg.AppendEvent(org_model.OrgMemberChanged, changes) + return agg.AppendEvent(model.OrgMemberChanged, changes) } } -func orgMemberRemovedAggregate(aggCreator *es_models.AggregateCreator, member *OrgMember) func(ctx context.Context) (*es_models.Aggregate, error) { +func orgMemberRemovedAggregate(aggCreator *es_models.AggregateCreator, member *model.OrgMember) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if member == nil { return nil, errors.ThrowPreconditionFailed(nil, "EVENT-dieu7", "member must not be nil") @@ -57,11 +57,11 @@ func orgMemberRemovedAggregate(aggCreator *es_models.AggregateCreator, member *O if err != nil { return nil, err } - return agg.AppendEvent(org_model.OrgMemberRemoved, member) + return agg.AppendEvent(model.OrgMemberRemoved, member) } } -func addMemberValidation(aggregate *es_models.Aggregate, member *OrgMember) func(...*es_models.Event) error { +func addMemberValidation(aggregate *es_models.Aggregate, member *model.OrgMember) func(...*es_models.Event) error { return func(events ...*es_models.Event) error { existsOrg := false existsUser := false @@ -70,17 +70,17 @@ func addMemberValidation(aggregate *es_models.Aggregate, member *OrgMember) func switch event.AggregateType { case usr_model.UserAggregate: existsUser = true - case org_model.OrgAggregate: + case model.OrgAggregate: aggregate.PreviousSequence = event.Sequence existsOrg = true switch event.Type { - case org_model.OrgMemberAdded, org_model.OrgMemberRemoved: - manipulatedMember, err := OrgMemberFromEvent(new(OrgMember), event) + case model.OrgMemberAdded, model.OrgMemberRemoved: + manipulatedMember, err := model.OrgMemberFromEvent(new(model.OrgMember), event) if err != nil { return errors.ThrowInternal(err, "EVENT-Eg8St", "unable to validate object") } if manipulatedMember.UserID == member.UserID { - isMember = event.Type == org_model.OrgMemberAdded + isMember = event.Type == model.OrgMemberAdded } } } diff --git a/internal/org/repository/eventsourcing/org_member_test.go b/internal/org/repository/eventsourcing/org_member_test.go index b4076198fd..fb83f6792a 100644 --- a/internal/org/repository/eventsourcing/org_member_test.go +++ b/internal/org/repository/eventsourcing/org_member_test.go @@ -2,12 +2,12 @@ package eventsourcing import ( "context" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "testing" "github.com/caos/zitadel/internal/api/auth" "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" - org_model "github.com/caos/zitadel/internal/org/model" usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" ) @@ -18,7 +18,7 @@ func TestOrgMemberAddedAggregate(t *testing.T) { } type args struct { aggCreator *es_models.AggregateCreator - member *OrgMember + member *model.OrgMember ctx context.Context } tests := []struct { @@ -42,7 +42,7 @@ func TestOrgMemberAddedAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - member: &OrgMember{ + member: &model.OrgMember{ ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234}, }, }, @@ -78,8 +78,8 @@ func TestOrgMemberChangedAggregate(t *testing.T) { } type args struct { aggCreator *es_models.AggregateCreator - existingMember *OrgMember - member *OrgMember + existingMember *model.OrgMember + member *model.OrgMember ctx context.Context } tests := []struct { @@ -93,7 +93,7 @@ func TestOrgMemberChangedAggregate(t *testing.T) { aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), member: nil, - existingMember: &OrgMember{}, + existingMember: &model.OrgMember{}, }, res: res{ isErr: errors.IsPreconditionFailed, @@ -105,7 +105,7 @@ func TestOrgMemberChangedAggregate(t *testing.T) { aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), existingMember: nil, - member: &OrgMember{}, + member: &model.OrgMember{}, }, res: res{ isErr: errors.IsPreconditionFailed, @@ -116,10 +116,10 @@ func TestOrgMemberChangedAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - member: &OrgMember{ + member: &model.OrgMember{ ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234}, }, - existingMember: &OrgMember{ + existingMember: &model.OrgMember{ ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234}, }, }, @@ -132,11 +132,11 @@ func TestOrgMemberChangedAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - member: &OrgMember{ + member: &model.OrgMember{ ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234}, Roles: []string{"asdf"}, }, - existingMember: &OrgMember{ + existingMember: &model.OrgMember{ ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234}, Roles: []string{"asdf", "woeri"}, }, @@ -174,7 +174,7 @@ func TestOrgMemberRemovedAggregate(t *testing.T) { } type args struct { aggCreator *es_models.AggregateCreator - member *OrgMember + member *model.OrgMember ctx context.Context } tests := []struct { @@ -198,7 +198,7 @@ func TestOrgMemberRemovedAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - member: &OrgMember{ + member: &model.OrgMember{ ObjectRoot: es_models.ObjectRoot{AggregateID: "asdf", Sequence: 234}, }, }, @@ -236,7 +236,7 @@ func Test_addMemberValidation(t *testing.T) { type args struct { aggregate *es_models.Aggregate events []*es_models.Event - member *OrgMember + member *model.OrgMember } tests := []struct { name string @@ -258,21 +258,21 @@ func Test_addMemberValidation(t *testing.T) { aggregate: &es_models.Aggregate{}, events: []*es_models.Event{ { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 13, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 142, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 1234, - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId":"hodor"}`), }, }, - member: &OrgMember{UserID: "hodor"}, + member: &model.OrgMember{UserID: "hodor"}, }, res: res{ isErr: errors.IsPreconditionFailed, @@ -292,7 +292,7 @@ func Test_addMemberValidation(t *testing.T) { Sequence: 142, }, }, - member: &OrgMember{UserID: "hodor"}, + member: &model.OrgMember{UserID: "hodor"}, }, res: res{ isErr: errors.IsPreconditionFailed, @@ -308,11 +308,11 @@ func Test_addMemberValidation(t *testing.T) { Sequence: 13, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 142, }, }, - member: &OrgMember{UserID: "hodor"}, + member: &model.OrgMember{UserID: "hodor"}, }, res: res{ isErr: nil, @@ -329,23 +329,23 @@ func Test_addMemberValidation(t *testing.T) { Sequence: 13, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 142, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 1234, - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId":"hodor"}`), }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 1236, - Type: org_model.OrgMemberRemoved, + Type: model.OrgMemberRemoved, Data: []byte(`{"userId":"hodor"}`), }, }, - member: &OrgMember{UserID: "hodor"}, + member: &model.OrgMember{UserID: "hodor"}, }, res: res{ isErr: nil, @@ -362,17 +362,17 @@ func Test_addMemberValidation(t *testing.T) { Sequence: 13, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 142, }, { - AggregateType: org_model.OrgAggregate, + AggregateType: model.OrgAggregate, Sequence: 1234, - Type: org_model.OrgMemberAdded, + Type: model.OrgMemberAdded, Data: []byte(`{"userId":"hodor"}`), }, }, - member: &OrgMember{UserID: "hodor"}, + member: &model.OrgMember{UserID: "hodor"}, }, res: res{ isErr: errors.IsPreconditionFailed, diff --git a/internal/org/repository/eventsourcing/org_test.go b/internal/org/repository/eventsourcing/org_test.go index 805d962104..347cf4aabe 100644 --- a/internal/org/repository/eventsourcing/org_test.go +++ b/internal/org/repository/eventsourcing/org_test.go @@ -2,6 +2,7 @@ package eventsourcing import ( "context" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "testing" "github.com/caos/zitadel/internal/api/auth" @@ -217,7 +218,7 @@ func TestOrgReactivateAggregate(t *testing.T) { } type args struct { aggCreator *es_models.AggregateCreator - org *Org + org *model.Org ctx context.Context } tests := []struct { @@ -230,7 +231,7 @@ func TestOrgReactivateAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "orgID", Sequence: 2, @@ -244,7 +245,7 @@ func TestOrgReactivateAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "orgID", Sequence: 2, @@ -291,7 +292,7 @@ func TestOrgDeactivateAggregate(t *testing.T) { } type args struct { aggCreator *es_models.AggregateCreator - org *Org + org *model.Org ctx context.Context } tests := []struct { @@ -304,7 +305,7 @@ func TestOrgDeactivateAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "orgID", Sequence: 2, @@ -318,7 +319,7 @@ func TestOrgDeactivateAggregate(t *testing.T) { args: args{ aggCreator: es_models.NewAggregateCreator("test"), ctx: auth.NewMockContext("org", "user"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "orgID", Sequence: 2, @@ -367,8 +368,8 @@ func TestOrgUpdateAggregates(t *testing.T) { type args struct { ctx context.Context aggCreator *es_models.AggregateCreator - existing *Org - updated *Org + existing *model.Org + updated *model.Org } tests := []struct { name string @@ -381,7 +382,7 @@ func TestOrgUpdateAggregates(t *testing.T) { ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), existing: nil, - updated: &Org{}, + updated: &model.Org{}, }, res: res{ aggregateCount: 0, @@ -393,7 +394,7 @@ func TestOrgUpdateAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - existing: &Org{}, + existing: &model.Org{}, updated: nil, }, res: res{ @@ -406,8 +407,8 @@ func TestOrgUpdateAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - existing: &Org{}, - updated: &Org{}, + existing: &model.Org{}, + updated: &model.Org{}, }, res: res{ aggregateCount: 0, @@ -419,7 +420,7 @@ func TestOrgUpdateAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - existing: &Org{ + existing: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, @@ -427,7 +428,7 @@ func TestOrgUpdateAggregates(t *testing.T) { Domain: "caos.ch", Name: "coas", }, - updated: &Org{ + updated: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, @@ -446,7 +447,7 @@ func TestOrgUpdateAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - existing: &Org{ + existing: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, @@ -454,7 +455,7 @@ func TestOrgUpdateAggregates(t *testing.T) { Domain: "caos.swiss", Name: "caos", }, - updated: &Org{ + updated: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, @@ -493,7 +494,7 @@ func TestOrgCreatedAggregates(t *testing.T) { type args struct { ctx context.Context aggCreator *es_models.AggregateCreator - org *Org + org *model.Org } tests := []struct { name string @@ -517,7 +518,7 @@ func TestOrgCreatedAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, @@ -536,7 +537,7 @@ func TestOrgCreatedAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, @@ -554,7 +555,7 @@ func TestOrgCreatedAggregates(t *testing.T) { args: args{ ctx: auth.NewMockContext("org", "user"), aggCreator: es_models.NewAggregateCreator("test"), - org: &Org{ + org: &model.Org{ ObjectRoot: es_models.ObjectRoot{ AggregateID: "sdaf", Sequence: 5, diff --git a/internal/org/repository/view/org.go b/internal/org/repository/view/org.go index b6aee2cf4a..571c416d9f 100644 --- a/internal/org/repository/view/org.go +++ b/internal/org/repository/view/org.go @@ -2,12 +2,12 @@ package view import ( "encoding/json" + "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "time" "github.com/caos/logging" "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" - org_es_model "github.com/caos/zitadel/internal/org/model" org_model "github.com/caos/zitadel/internal/org/model" ) @@ -69,17 +69,17 @@ func OrgsToModel(orgs []*OrgView) []*org_model.OrgView { func (o *OrgView) AppendEvent(event *es_models.Event) (err error) { switch event.Type { - case org_es_model.OrgAdded: + case model.OrgAdded: o.CreationDate = event.CreationDate o.State = int32(org_model.ORGSTATE_ACTIVE) o.setRootData(event) err = o.SetData(event) - case org_es_model.OrgChanged: + case model.OrgChanged: o.setRootData(event) err = o.SetData(event) - case org_es_model.OrgDeactivated: + case model.OrgDeactivated: o.State = int32(org_model.ORGSTATE_INACTIVE) - case org_es_model.OrgReactivated: + case model.OrgReactivated: o.State = int32(org_model.ORGSTATE_ACTIVE) } return err diff --git a/internal/org/repository/view/org_member.go b/internal/org/repository/view/org_member.go index b4ebddcd98..0e281c3a26 100644 --- a/internal/org/repository/view/org_member.go +++ b/internal/org/repository/view/org_member.go @@ -2,6 +2,7 @@ package view import ( "encoding/json" + es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "time" "github.com/caos/logging" @@ -76,11 +77,11 @@ func (r *OrgMemberView) AppendEvent(event *models.Event) (err error) { r.Sequence = event.Sequence r.ChangeDate = event.CreationDate switch event.Type { - case model.OrgMemberAdded: + case es_model.OrgMemberAdded: r.setRootData(event) r.CreationDate = event.CreationDate err = r.SetData(event) - case model.OrgMemberChanged: + case es_model.OrgMemberChanged: err = r.SetData(event) } return err diff --git a/internal/project/model/granted_project.go b/internal/project/model/granted_project.go index 301eb538fd..ebd58c85d3 100644 --- a/internal/project/model/granted_project.go +++ b/internal/project/model/granted_project.go @@ -50,7 +50,7 @@ const ( type GrantedProjectSearchQuery struct { Key GrantedProjectSearchKey Method model.SearchMethod - Value string + Value interface{} } type GrantedProjectSearchResponse struct { diff --git a/internal/project/repository/eventsourcing/eventstore.go b/internal/project/repository/eventsourcing/eventstore.go index b87e13de53..91446bea32 100644 --- a/internal/project/repository/eventsourcing/eventstore.go +++ b/internal/project/repository/eventsourcing/eventstore.go @@ -4,18 +4,21 @@ import ( "context" "github.com/caos/zitadel/internal/cache/config" sd "github.com/caos/zitadel/internal/config/systemdefaults" + es_models "github.com/caos/zitadel/internal/eventstore/models" + "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" + "github.com/caos/zitadel/internal/crypto" caos_errs "github.com/caos/zitadel/internal/errors" es_int "github.com/caos/zitadel/internal/eventstore" es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/id" proj_model "github.com/caos/zitadel/internal/project/model" - "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" ) type ProjectEventstore struct { es_int.Eventstore projectCache *ProjectCache + passwordAlg crypto.HashAlgorithm pwGenerator crypto.Generator idGenerator id.Generator } @@ -35,6 +38,7 @@ func StartProject(conf ProjectConfig, systemDefaults sd.SystemDefaults) (*Projec return &ProjectEventstore{ Eventstore: conf.Eventstore, projectCache: projectCache, + passwordAlg: passwordAlg, pwGenerator: pwGenerator, idGenerator: id.SonyFlakeGenerator, }, nil @@ -535,6 +539,42 @@ func (es *ProjectEventstore) ChangeOIDCConfigSecret(ctx context.Context, project return nil, caos_errs.ThrowInternal(nil, "EVENT-dk87s", "Could not find app in list") } +func (es *ProjectEventstore) VerifyOIDCClientSecret(ctx context.Context, projectID, appID string, secret string) error { + if appID == "" { + return caos_errs.ThrowPreconditionFailed(nil, "EVENT-H3RT2", "some required fields missing") + } + existing, err := es.ProjectByID(ctx, projectID) + if err != nil { + return err + } + var app *proj_model.Application + if _, app = existing.GetApp(appID); app == nil { + return caos_errs.ThrowPreconditionFailed(nil, "EVENT-D6hba", "App is not in this project") + } + if app.Type != proj_model.APPTYPE_OIDC { + return caos_errs.ThrowPreconditionFailed(nil, "EVENT-huywq", "App is not an oidc application") + } + + if err := crypto.CompareHash(app.OIDCConfig.ClientSecret, []byte(secret), es.passwordAlg); err == nil { + return es.setOIDCClientSecretCheckResult(ctx, existing, app.AppID, OIDCClientSecretCheckSucceededAggregate) + } + if err := es.setOIDCClientSecretCheckResult(ctx, existing, app.AppID, OIDCClientSecretCheckFailedAggregate); err != nil { + return err + } + return caos_errs.ThrowInvalidArgument(nil, "EVENT-wg24q", "invalid client secret") +} + +func (es *ProjectEventstore) setOIDCClientSecretCheckResult(ctx context.Context, project *proj_model.Project, appID string, check func(*es_models.AggregateCreator, *model.Project, string) es_sdk.AggregateFunc) error { + repoProject := model.ProjectFromModel(project) + agg := check(es.AggregateCreator(), repoProject, appID) + err := es_sdk.Push(ctx, es.PushAggregates, repoProject.AppendEvents, agg) + if err != nil { + return err + } + es.projectCache.cacheProject(repoProject) + return nil +} + func (es *ProjectEventstore) ProjectGrantByIDs(ctx context.Context, projectID, grantID string) (*proj_model.ProjectGrant, error) { if grantID == "" { return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-e8die", "grantID missing") diff --git a/internal/project/repository/eventsourcing/model/project_grant_member.go b/internal/project/repository/eventsourcing/model/project_grant_member.go index aeeda8446f..92d9a8a528 100644 --- a/internal/project/repository/eventsourcing/model/project_grant_member.go +++ b/internal/project/repository/eventsourcing/model/project_grant_member.go @@ -59,7 +59,7 @@ func GrantMemberToModel(member *ProjectGrantMember) *model.ProjectGrantMember { func (p *Project) appendAddGrantMemberEvent(event *es_models.Event) error { member := &ProjectGrantMember{} - err := member.getData(event) + err := member.SetData(event) if err != nil { return err } @@ -73,13 +73,13 @@ func (p *Project) appendAddGrantMemberEvent(event *es_models.Event) error { func (p *Project) appendChangeGrantMemberEvent(event *es_models.Event) error { member := &ProjectGrantMember{} - err := member.getData(event) + err := member.SetData(event) if err != nil { return err } if _, g := GetProjectGrant(p.Grants, member.GrantID); g != nil { if i, m := GetProjectGrantMember(g.Members, member.UserID); m != nil { - g.Members[i].getData(event) + g.Members[i].SetData(event) } } return nil @@ -87,7 +87,7 @@ func (p *Project) appendChangeGrantMemberEvent(event *es_models.Event) error { func (p *Project) appendRemoveGrantMemberEvent(event *es_models.Event) error { member := &ProjectGrantMember{} - err := member.getData(event) + err := member.SetData(event) if err != nil { return err } @@ -102,7 +102,7 @@ func (p *Project) appendRemoveGrantMemberEvent(event *es_models.Event) error { return nil } -func (m *ProjectGrantMember) getData(event *es_models.Event) error { +func (m *ProjectGrantMember) SetData(event *es_models.Event) error { m.ObjectRoot.AppendEvent(event) if err := json.Unmarshal(event.Data, m); err != nil { logging.Log("EVEN-8die2").WithError(err).Error("could not unmarshal event data") diff --git a/internal/project/repository/eventsourcing/model/project_member.go b/internal/project/repository/eventsourcing/model/project_member.go index f04cf21b86..3f8c57dd8e 100644 --- a/internal/project/repository/eventsourcing/model/project_member.go +++ b/internal/project/repository/eventsourcing/model/project_member.go @@ -56,7 +56,7 @@ func ProjectMemberToModel(member *ProjectMember) *model.ProjectMember { func (p *Project) appendAddMemberEvent(event *es_models.Event) error { member := &ProjectMember{} - err := member.setData(event) + err := member.SetData(event) if err != nil { return err } @@ -67,7 +67,7 @@ func (p *Project) appendAddMemberEvent(event *es_models.Event) error { func (p *Project) appendChangeMemberEvent(event *es_models.Event) error { member := &ProjectMember{} - err := member.setData(event) + err := member.SetData(event) if err != nil { return err } @@ -79,7 +79,7 @@ func (p *Project) appendChangeMemberEvent(event *es_models.Event) error { func (p *Project) appendRemoveMemberEvent(event *es_models.Event) error { member := &ProjectMember{} - err := member.setData(event) + err := member.SetData(event) if err != nil { return err } @@ -91,7 +91,7 @@ func (p *Project) appendRemoveMemberEvent(event *es_models.Event) error { return nil } -func (m *ProjectMember) setData(event *es_models.Event) error { +func (m *ProjectMember) SetData(event *es_models.Event) error { m.ObjectRoot.AppendEvent(event) if err := json.Unmarshal(event.Data, m); err != nil { logging.Log("EVEN-e4dkp").WithError(err).Error("could not unmarshal event data") diff --git a/internal/project/repository/eventsourcing/model/types.go b/internal/project/repository/eventsourcing/model/types.go index 787cc23264..babaa808f1 100644 --- a/internal/project/repository/eventsourcing/model/types.go +++ b/internal/project/repository/eventsourcing/model/types.go @@ -35,7 +35,9 @@ const ( ApplicationDeactivated models.EventType = "project.application.deactivated" ApplicationReactivated models.EventType = "project.application.reactivated" - OIDCConfigAdded models.EventType = "project.application.config.oidc.added" - OIDCConfigChanged models.EventType = "project.application.config.oidc.changed" - OIDCConfigSecretChanged models.EventType = "project.application.config.oidc.secret.changed" + OIDCConfigAdded models.EventType = "project.application.config.oidc.added" + OIDCConfigChanged models.EventType = "project.application.config.oidc.changed" + OIDCConfigSecretChanged models.EventType = "project.application.config.oidc.secret.changed" + OIDCClientSecretCheckSucceeded models.EventType = "project.application.oidc.secret.check.succeeded" + OIDCClientSecretCheckFailed models.EventType = "project.application.oidc.secret.check.failed" ) diff --git a/internal/project/repository/eventsourcing/project.go b/internal/project/repository/eventsourcing/project.go index 65a31bfd2a..54c152f712 100644 --- a/internal/project/repository/eventsourcing/project.go +++ b/internal/project/repository/eventsourcing/project.go @@ -6,7 +6,8 @@ import ( "github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/eventstore/models" es_models "github.com/caos/zitadel/internal/eventstore/models" - org_model "github.com/caos/zitadel/internal/org/model" + es_sdk "github.com/caos/zitadel/internal/eventstore/sdk" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" ) @@ -290,7 +291,7 @@ func OIDCConfigSecretChangedAggregate(aggCreator *es_models.AggregateCreator, ex if err != nil { return nil, err } - changes := make(map[string]interface{}, 1) + changes := make(map[string]interface{}, 2) changes["appId"] = appID changes["clientSecret"] = secret @@ -300,6 +301,36 @@ func OIDCConfigSecretChangedAggregate(aggCreator *es_models.AggregateCreator, ex } } +func OIDCClientSecretCheckSucceededAggregate(aggCreator *es_models.AggregateCreator, existing *model.Project, appID string) es_sdk.AggregateFunc { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := ProjectAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + changes := make(map[string]interface{}, 1) + changes["appId"] = appID + + agg.AppendEvent(model.OIDCClientSecretCheckSucceeded, changes) + + return agg, nil + } +} + +func OIDCClientSecretCheckFailedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Project, appID string) es_sdk.AggregateFunc { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := ProjectAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + changes := make(map[string]interface{}, 1) + changes["appId"] = appID + + agg.AppendEvent(model.OIDCClientSecretCheckFailed, changes) + + return agg, nil + } +} + func ProjectGrantAddedAggregate(aggCreator *es_models.AggregateCreator, existing *model.Project, grant *model.ProjectGrant) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if grant == nil { @@ -310,7 +341,7 @@ func ProjectGrantAddedAggregate(aggCreator *es_models.AggregateCreator, existing return nil, err } validationQuery := es_models.NewSearchQuery(). - AggregateTypeFilter(org_model.OrgAggregate). + AggregateTypeFilter(org_es_model.OrgAggregate). AggregateIDFilter(grant.GrantedOrgID) validation := addProjectGrantValidation() @@ -475,11 +506,11 @@ func addProjectGrantValidation() func(...*es_models.Event) error { existsOrg := false for _, event := range events { switch event.AggregateType { - case org_model.OrgAggregate: + case org_es_model.OrgAggregate: switch event.Type { - case org_model.OrgAdded: + case org_es_model.OrgAdded: existsOrg = true - case org_model.OrgRemoved: + case org_es_model.OrgRemoved: existsOrg = false } } diff --git a/internal/project/repository/view/application_view.go b/internal/project/repository/view/application_view.go index 2c993e16c1..2b660f04ef 100644 --- a/internal/project/repository/view/application_view.go +++ b/internal/project/repository/view/application_view.go @@ -1,6 +1,7 @@ package view import ( + global_model "github.com/caos/zitadel/internal/model" proj_model "github.com/caos/zitadel/internal/project/model" "github.com/caos/zitadel/internal/project/repository/view/model" "github.com/caos/zitadel/internal/view" @@ -14,6 +15,23 @@ func ApplicationByID(db *gorm.DB, table, appID string) (*model.ApplicationView, return app, err } +func ApplicationByOIDCClientID(db *gorm.DB, table, clientID string) (*model.ApplicationView, error) { + app := new(model.ApplicationView) + clientIDQuery := model.ApplicationSearchQuery{Key: proj_model.APPLICATIONSEARCHKEY_OIDC_CLIENT_ID, Value: clientID, Method: global_model.SEARCHMETHOD_EQUALS} + query := view.PrepareGetByQuery(table, clientIDQuery) + err := query(db, app) + return app, err +} + +func ApplicationByProjectIDAndAppName(db *gorm.DB, table, projectID, appName string) (*model.ApplicationView, error) { + app := new(model.ApplicationView) + projectIDQuery := model.ApplicationSearchQuery{Key: proj_model.APPLICATIONSEARCHKEY_PROJECT_ID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS} + appNameQuery := model.ApplicationSearchQuery{Key: proj_model.APPLICATIONSEARCHKEY_NAME, Value: appName, Method: global_model.SEARCHMETHOD_EQUALS} + query := view.PrepareGetByQuery(table, projectIDQuery, appNameQuery) + err := query(db, app) + return app, err +} + func SearchApplications(db *gorm.DB, table string, req *proj_model.ApplicationSearchRequest) ([]*model.ApplicationView, int, error) { apps := make([]*model.ApplicationView, 0) query := view.PrepareSearchQuery(table, model.ApplicationSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries}) diff --git a/internal/project/repository/view/model/application.go b/internal/project/repository/view/model/application.go index e738855eb8..e4ced437fb 100644 --- a/internal/project/repository/view/model/application.go +++ b/internal/project/repository/view/model/application.go @@ -16,7 +16,7 @@ const ( ApplicationKeyProjectID = "project_id" ApplicationKeyResourceOwner = "resource_owner" ApplicationKeyOIDCClientID = "oidc_client_id" - ApplicationKeyName = "name" + ApplicationKeyName = "app_name" ) type ApplicationView struct { diff --git a/internal/renderer/renderer.go b/internal/renderer/renderer.go new file mode 100644 index 0000000000..c0690c028d --- /dev/null +++ b/internal/renderer/renderer.go @@ -0,0 +1,120 @@ +package renderer + +import ( + "io/ioutil" + "net/http" + "os" + "text/template" + + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/i18n" + + "github.com/caos/logging" + "golang.org/x/text/language" +) + +const ( + TranslateFn = "t" + + templatesPath = "/templates" +) + +type Renderer struct { + Templates map[string]*template.Template + i18n *i18n.Translator +} + +func NewRenderer(dir http.FileSystem, tmplMapping map[string]string, funcs map[string]interface{}, translatorConfig i18n.TranslatorConfig) (*Renderer, error) { + var err error + r := new(Renderer) + r.i18n, err = i18n.NewTranslator(dir, translatorConfig) + if err != nil { + return nil, err + } + r.loadTemplates(dir, tmplMapping, funcs) + return r, nil +} + +func (r *Renderer) RenderTemplate(w http.ResponseWriter, req *http.Request, tmpl *template.Template, data interface{}, reqFuncs map[string]interface{}) { + reqFuncs = r.registerTranslateFn(req, reqFuncs) + if err := tmpl.Funcs(reqFuncs).Execute(w, data); err != nil { + logging.Log("RENDE-lF8F6w").WithError(err).WithField("template", tmpl.Name).Error("error rendering template") + } +} + +func (r *Renderer) Localize(id string, args map[string]interface{}) string { + return r.i18n.Localize(id, args) +} + +func (r *Renderer) LocalizeFromRequest(req *http.Request, id string, args map[string]interface{}) string { + return r.i18n.LocalizeFromRequest(req, id, args) +} +func (r *Renderer) Lang(req *http.Request) language.Tag { + return r.i18n.Lang(req) +} + +func (r *Renderer) loadTemplates(dir http.FileSystem, tmplMapping map[string]string, funcs map[string]interface{}) error { + funcs = r.registerTranslateFn(nil, funcs) + funcs[TranslateFn] = func(id string, args ...interface{}) string { + return id + } + templatesDir, err := dir.Open(templatesPath) + if err != nil { + return errors.ThrowNotFound(err, "RENDE-G3aea", "path not found") + } + defer templatesDir.Close() + files, err := templatesDir.Readdir(0) + if err != nil { + return errors.ThrowNotFound(err, "RENDE-dfR33", "cannot read dir") + } + tmpl := template.New("") + for _, file := range files { + if err := r.addFileToTemplate(dir, tmpl, tmplMapping, funcs, file); err != nil { + return errors.ThrowNotFound(err, "RENDE-dfTe1", "cannot append file to templates") + } + } + r.Templates = make(map[string]*template.Template, len(tmplMapping)) + for name, file := range tmplMapping { + r.Templates[name] = tmpl.Lookup(file) + } + return nil +} + +func (r *Renderer) addFileToTemplate(dir http.FileSystem, tmpl *template.Template, tmplMapping map[string]string, funcs map[string]interface{}, file os.FileInfo) error { + f, err := dir.Open(templatesPath + "/" + file.Name()) + if err != nil { + return err + } + defer f.Close() + content, err := ioutil.ReadAll(f) + if err != nil { + return err + } + tmpl, err = tmpl.New(file.Name()).Funcs(funcs).Parse(string(content)) + if err != nil { + return err + } + return nil +} + +func (r *Renderer) registerTranslateFn(req *http.Request, funcs map[string]interface{}) map[string]interface{} { + if funcs == nil { + funcs = make(map[string]interface{}) + } + funcs[TranslateFn] = func(id string, args ...interface{}) string { + m := map[string]interface{}{} + var key string + for i, arg := range args { + if i%2 == 0 { + key = arg.(string) + continue + } + m[key] = arg + } + if r == nil { + return r.Localize(id, m) + } + return r.LocalizeFromRequest(req, id, m) + } + return funcs +} diff --git a/internal/token/model/token.go b/internal/token/model/token.go index bd8e2ff5ed..5e3b6a74d6 100644 --- a/internal/token/model/token.go +++ b/internal/token/model/token.go @@ -14,7 +14,9 @@ type Token struct { UserID string ApplicationID string UserAgentID string + Audience []string Expiration time.Time + Scopes []string Sequence uint64 } diff --git a/internal/token/repository/view/model/token.go b/internal/token/repository/view/model/token.go index 2c094322d2..1b08051a96 100644 --- a/internal/token/repository/view/model/token.go +++ b/internal/token/repository/view/model/token.go @@ -3,6 +3,8 @@ package model import ( "time" + "github.com/lib/pq" + "github.com/caos/zitadel/internal/token/model" ) @@ -16,15 +18,17 @@ const ( ) type Token struct { - ID string `json:"-" gorm:"column:id;primary_key"` - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` - ResourceOwner string `json:"-" gorm:"column:resource_owner"` - UserID string `json:"-" gorm:"column:user_id"` - ApplicationID string `json:"-" gorm:"column:application_id"` - UserAgentID string `json:"-" gorm:"column:user_agent_id"` - Expiration time.Time `json:"-" gorm:"column:expiration"` - Sequence uint64 `json:"-" gorm:"column:sequence"` + ID string `json:"-" gorm:"column:id;primary_key"` + CreationDate time.Time `json:"-" gorm:"column:creation_date"` + ChangeDate time.Time `json:"-" gorm:"column:change_date"` + ResourceOwner string `json:"-" gorm:"column:resource_owner"` + UserID string `json:"-" gorm:"column:user_id"` + ApplicationID string `json:"-" gorm:"column:application_id"` + UserAgentID string `json:"-" gorm:"column:user_agent_id"` + Audience pq.StringArray `json:"-" gorm:"column:audience"` + Scopes pq.StringArray `json:"-" gorm:"column:scopes"` + Expiration time.Time `json:"-" gorm:"column:expiration"` + Sequence uint64 `json:"-" gorm:"column:sequence"` } func TokenFromModel(token *model.Token) *Token { @@ -36,6 +40,8 @@ func TokenFromModel(token *model.Token) *Token { UserID: token.UserID, ApplicationID: token.ApplicationID, UserAgentID: token.UserAgentID, + Audience: token.Audience, + Scopes: token.Scopes, Expiration: token.Expiration, Sequence: token.Sequence, } @@ -50,6 +56,8 @@ func TokenToModel(token *Token) *model.Token { UserID: token.UserID, ApplicationID: token.ApplicationID, UserAgentID: token.UserAgentID, + Audience: token.Audience, + Scopes: token.Scopes, Expiration: token.Expiration, Sequence: token.Sequence, } diff --git a/internal/user/model/phone.go b/internal/user/model/phone.go index f83ef241f2..a6f93b237c 100644 --- a/internal/user/model/phone.go +++ b/internal/user/model/phone.go @@ -9,7 +9,6 @@ import ( ) const ( - //TODO: How do we get region? defaultRegion = "CH" ) diff --git a/internal/user/model/user_session_view.go b/internal/user/model/user_session_view.go index 8e06fc43e3..66db359b41 100644 --- a/internal/user/model/user_session_view.go +++ b/internal/user/model/user_session_view.go @@ -8,18 +8,19 @@ import ( ) type UserSessionView struct { - ID string - CreationDate time.Time - ChangeDate time.Time - State req_model.UserSessionState - ResourceOwner string - UserAgentID string - UserID string - UserName string - PasswordVerification time.Time - MfaSoftwareVerification time.Time - MfaHardwareVerification time.Time - Sequence uint64 + CreationDate time.Time + ChangeDate time.Time + State req_model.UserSessionState + ResourceOwner string + UserAgentID string + UserID string + UserName string + PasswordVerification time.Time + MfaSoftwareVerification time.Time + MfaSoftwareVerificationType req_model.MfaType + MfaHardwareVerification time.Time + MfaHardwareVerificationType req_model.MfaType + Sequence uint64 } type UserSessionSearchRequest struct { @@ -34,7 +35,6 @@ type UserSessionSearchKey int32 const ( USERSESSIONSEARCHKEY_UNSPECIFIED UserSessionSearchKey = iota - USERSESSIONSEARCHKEY_SESSION_ID USERSESSIONSEARCHKEY_USER_AGENT_ID USERSESSIONSEARCHKEY_USER_ID USERSESSIONSEARCHKEY_STATE diff --git a/internal/user/model/user_view.go b/internal/user/model/user_view.go index 111d6a071c..b93d356b40 100644 --- a/internal/user/model/user_view.go +++ b/internal/user/model/user_view.go @@ -36,6 +36,7 @@ type UserView struct { OTPState MfaState MfaMaxSetUp req_model.MfaLevel MfaInitSkipped time.Time + InitRequired bool Sequence uint64 } @@ -88,6 +89,8 @@ func (r *UserSearchRequest) AppendMyOrgQuery(orgID string) { func (u *UserView) MfaTypesSetupPossible(level req_model.MfaLevel) []req_model.MfaType { types := make([]req_model.MfaType, 0) switch level { + default: + fallthrough case req_model.MfaLevelSoftware: if u.OTPState != MFASTATE_READY { types = append(types, req_model.MfaTypeOTP) diff --git a/internal/user/repository/eventsourcing/eventstore.go b/internal/user/repository/eventsourcing/eventstore.go index 9047385fa2..1a4803f141 100644 --- a/internal/user/repository/eventsourcing/eventstore.go +++ b/internal/user/repository/eventsourcing/eventstore.go @@ -89,6 +89,14 @@ func (es *UserEventstore) UserByID(ctx context.Context, id string) (*usr_model.U return model.UserToModel(user), nil } +func (es *UserEventstore) UserEventsByID(ctx context.Context, id string, sequence uint64) ([]*es_models.Event, error) { + query, err := UserByIDQuery(id, sequence) + if err != nil { + return nil, err + } + return es.FilterEvents(ctx, query) +} + func (es *UserEventstore) PrepareCreateUser(ctx context.Context, user *usr_model.User, policy *policy_model.PasswordComplexityPolicy, resourceOwner string) (*model.User, []*es_models.Aggregate, error) { user.SetEmailAsUsername() if !user.IsValid() { @@ -317,6 +325,39 @@ func (es *UserEventstore) InitCodeSent(ctx context.Context, userID string) error return nil } +func (es *UserEventstore) VerifyInitCode(ctx context.Context, policy *policy_model.PasswordComplexityPolicy, userID, verificationCode, password string) error { + if userID == "" || verificationCode == "" { + return caos_errs.ThrowPreconditionFailed(nil, "EVENT-lo9fd", "userId or Code empty") + } + pw := &usr_model.Password{SecretString: password} + err := pw.HashPasswordIfExisting(policy, es.PasswordAlg, false) + if err != nil { + return err + } + existing, err := es.UserByID(ctx, userID) + if err != nil { + return err + } + if existing.InitCode == nil { + return caos_errs.ThrowNotFound(nil, "EVENT-spo9W", "code not found") + } + repoPassword := model.PasswordFromModel(pw) + repoExisting := model.UserFromModel(existing) + var updateAggregate func(ctx context.Context) (*es_models.Aggregate, error) + if err := crypto.VerifyCode(existing.InitCode.CreationDate, existing.InitCode.Expiry, existing.InitCode.Code, verificationCode, es.InitializeUserCode); err != nil { + updateAggregate = InitCodeCheckFailedAggregate(es.AggregateCreator(), repoExisting) + } else { + updateAggregate = InitCodeVerifiedAggregate(es.AggregateCreator(), repoExisting, repoPassword) + } + err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregate) + if err != nil { + return err + } + + es.userCache.cacheUser(repoExisting) + return nil +} + func (es *UserEventstore) SkipMfaInit(ctx context.Context, userID string) error { if userID == "" { return caos_errs.ThrowPreconditionFailed(nil, "EVENT-dic8s", "userID missing") @@ -572,17 +613,23 @@ func (es *UserEventstore) VerifyEmail(ctx context.Context, userID, verificationC if existing.EmailCode == nil { return caos_errs.ThrowNotFound(nil, "EVENT-lso9w", "code not found") } - if err := crypto.VerifyCode(existing.EmailCode.CreationDate, existing.EmailCode.Expiry, existing.EmailCode.Code, verificationCode, es.EmailVerificationCode); err != nil { + + err = crypto.VerifyCode(existing.EmailCode.CreationDate, existing.EmailCode.Expiry, existing.EmailCode.Code, verificationCode, es.EmailVerificationCode) + if err == nil { + return es.setEmailVerifyResult(ctx, existing, EmailVerifiedAggregate) + } + if err := es.setEmailVerifyResult(ctx, existing, EmailVerificationFailedAggregate); err != nil { return err } + return caos_errs.ThrowInvalidArgument(err, "EVENT-dtGaa", "invalid code") +} +func (es *UserEventstore) setEmailVerifyResult(ctx context.Context, existing *usr_model.User, check func(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc) error { repoExisting := model.UserFromModel(existing) - updateAggregate := EmailVerifiedAggregate(es.AggregateCreator(), repoExisting) - err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregate) + err := es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, check(es.AggregateCreator(), repoExisting)) if err != nil { return err } - es.userCache.cacheUser(repoExisting) return nil } @@ -693,17 +740,23 @@ func (es *UserEventstore) VerifyPhone(ctx context.Context, userID, verificationC if existing.PhoneCode == nil { return caos_errs.ThrowNotFound(nil, "EVENT-slp0s", "code not found") } - if err := crypto.VerifyCode(existing.PhoneCode.CreationDate, existing.PhoneCode.Expiry, existing.PhoneCode.Code, verificationCode, es.PhoneVerificationCode); err != nil { + + err = crypto.VerifyCode(existing.PhoneCode.CreationDate, existing.PhoneCode.Expiry, existing.PhoneCode.Code, verificationCode, es.PhoneVerificationCode) + if err == nil { + return es.setPhoneVerifyResult(ctx, existing, PhoneVerifiedAggregate) + } + if err := es.setPhoneVerifyResult(ctx, existing, PhoneVerificationFailedAggregate); err != nil { return err } + return caos_errs.ThrowInvalidArgument(err, "EVENT-dsf4G", "invalid code") +} +func (es *UserEventstore) setPhoneVerifyResult(ctx context.Context, existing *usr_model.User, check func(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc) error { repoExisting := model.UserFromModel(existing) - updateAggregate := PhoneVerifiedAggregate(es.AggregateCreator(), repoExisting) - err = es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, updateAggregate) + err := es_sdk.Push(ctx, es.PushAggregates, repoExisting.AppendEvents, check(es.AggregateCreator(), repoExisting)) if err != nil { return err } - es.userCache.cacheUser(repoExisting) return nil } diff --git a/internal/user/repository/eventsourcing/eventstore_mock_test.go b/internal/user/repository/eventsourcing/eventstore_mock_test.go index 53ac275597..3e36f0b0bb 100644 --- a/internal/user/repository/eventsourcing/eventstore_mock_test.go +++ b/internal/user/repository/eventsourcing/eventstore_mock_test.go @@ -246,13 +246,13 @@ func GetMockManipulateLockedUser(ctrl *gomock.Controller) *UserEventstore { return GetMockedEventstore(ctrl, mockEs) } -func GetMockManipulateUserWithInitCode(ctrl *gomock.Controller) *UserEventstore { - user := model.User{ - Profile: &model.Profile{ - UserName: "UserName", - }, - } - code := model.InitUserCode{Expiry: time.Hour * 30} +func GetMockManipulateUserWithInitCode(ctrl *gomock.Controller, user model.User) *UserEventstore { + code := model.InitUserCode{Code: &crypto.CryptoValue{ + CryptoType: crypto.TypeEncryption, + Algorithm: "enc", + KeyID: "id", + Crypted: []byte("code"), + }} dataUser, _ := json.Marshal(user) dataCode, _ := json.Marshal(code) events := []*es_models.Event{ @@ -263,7 +263,7 @@ func GetMockManipulateUserWithInitCode(ctrl *gomock.Controller) *UserEventstore mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST")) mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) - return GetMockedEventstore(ctrl, mockEs) + return GetMockedEventstoreWithPw(ctrl, mockEs, true, false, false, true) } func GetMockManipulateUserWithEmailCode(ctrl *gomock.Controller) *UserEventstore { @@ -362,6 +362,7 @@ func GetMockManipulateUserVerifiedPhone(ctrl *gomock.Controller) *UserEventstore mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) return GetMockedEventstore(ctrl, mockEs) } + func GetMockManipulateUserFull(ctrl *gomock.Controller) *UserEventstore { user := model.User{ Profile: &model.Profile{ @@ -446,3 +447,12 @@ func GetMockManipulateUserNoEvents(ctrl *gomock.Controller) *UserEventstore { mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) return GetMockedEventstore(ctrl, mockEs) } + +func GetMockManipulateUserNoEventsWithPw(ctrl *gomock.Controller) *UserEventstore { + events := []*es_models.Event{} + mockEs := mock.NewMockEventstore(ctrl) + mockEs.EXPECT().FilterEvents(gomock.Any(), gomock.Any()).Return(events, nil) + mockEs.EXPECT().AggregateCreator().Return(es_models.NewAggregateCreator("TEST")) + mockEs.EXPECT().PushAggregates(gomock.Any(), gomock.Any()).Return(nil) + return GetMockedEventstoreWithPw(ctrl, mockEs, false, false, false, true) +} diff --git a/internal/user/repository/eventsourcing/eventstore_test.go b/internal/user/repository/eventsourcing/eventstore_test.go index bfade59408..7802e4b72e 100644 --- a/internal/user/repository/eventsourcing/eventstore_test.go +++ b/internal/user/repository/eventsourcing/eventstore_test.go @@ -753,7 +753,13 @@ func TestGetInitCodeByID(t *testing.T) { { name: "get by id, ok", args: args{ - es: GetMockManipulateUserWithInitCode(ctrl), + es: GetMockManipulateUserWithInitCode(ctrl, + repo_model.User{ + ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, + Profile: &repo_model.Profile{ + UserName: "UserName", + }, + }), ctx: auth.NewMockContext("orgID", "userID"), existing: &model.User{ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID", Sequence: 1}}, }, @@ -791,8 +797,8 @@ func TestGetInitCodeByID(t *testing.T) { if tt.res.errFunc == nil && result.AggregateID == "" { t.Errorf("result has no id") } - if tt.res.errFunc == nil && result.Expiry != tt.res.code.Expiry { - t.Errorf("got wrong result name: expected: %v, actual: %v ", tt.res.code.Expiry, result.Expiry) + if tt.res.errFunc == nil && result == nil { + t.Error("got wrong result code should not be nil", result) } if tt.res.errFunc != nil && !tt.res.errFunc(err) { t.Errorf("got wrong err: %v ", err) @@ -858,8 +864,8 @@ func TestCreateInitCode(t *testing.T) { if tt.res.errFunc == nil && result.AggregateID == "" { t.Errorf("result has no id") } - if tt.res.errFunc == nil && result.Expiry != tt.res.code.Expiry { - t.Errorf("got wrong result expiry: expected: %v, actual: %v ", tt.res.code.Expiry, result.Expiry) + if tt.res.errFunc == nil && result == nil { + t.Errorf("got wrong result code is nil") } if tt.res.errFunc != nil && !tt.res.errFunc(err) { t.Errorf("got wrong err: %v ", err) @@ -929,6 +935,135 @@ func TestInitCodeSent(t *testing.T) { } } +func TestInitCodeVerify(t *testing.T) { + ctrl := gomock.NewController(t) + type args struct { + es *UserEventstore + ctx context.Context + policy *policy_model.PasswordComplexityPolicy + userID string + verifyCode string + password string + } + type res struct { + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "verify init code, no pw", + args: args{ + es: GetMockManipulateUserWithInitCode(ctrl, + repo_model.User{ + ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, + Email: &repo_model.Email{ + EmailAddress: "EmailAddress", + }, + }, + ), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &policy_model.PasswordComplexityPolicy{}, + verifyCode: "code", + userID: "userID", + }, + }, + { + name: "verify init code, pw", + args: args{ + es: GetMockManipulateUserWithInitCode(ctrl, + repo_model.User{ + ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, + Email: &repo_model.Email{ + EmailAddress: "EmailAddress", + IsEmailVerified: true, + }, + }, + ), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &policy_model.PasswordComplexityPolicy{}, + userID: "userID", + verifyCode: "code", + password: "password", + }, + }, + { + name: "verify init code, email and pw", + args: args{ + es: GetMockManipulateUserWithInitCode(ctrl, + repo_model.User{ + ObjectRoot: es_models.ObjectRoot{AggregateID: "AggregateID"}, + Email: &repo_model.Email{ + EmailAddress: "EmailAddress", + }, + }, + ), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &policy_model.PasswordComplexityPolicy{}, + userID: "userID", + verifyCode: "code", + password: "password", + }, + }, + { + name: "empty userid", + args: args{ + es: GetMockManipulateUser(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &policy_model.PasswordComplexityPolicy{}, + userID: "", + verifyCode: "code", + password: "password", + }, + res: res{ + errFunc: caos_errs.IsPreconditionFailed, + }, + }, + { + name: "password policy not matched", + args: args{ + es: GetMockManipulateUser(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &policy_model.PasswordComplexityPolicy{HasNumber: true}, + userID: "userID", + verifyCode: "code", + password: "password", + }, + res: res{ + errFunc: caos_errs.IsErrorInvalidArgument, + }, + }, + { + name: "existing user not found", + args: args{ + es: GetMockManipulateUserNoEventsWithPw(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + policy: &policy_model.PasswordComplexityPolicy{}, + userID: "userID", + password: "password", + verifyCode: "code", + }, + res: res{ + errFunc: caos_errs.IsNotFound, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := tt.args.es.VerifyInitCode(tt.args.ctx, tt.args.policy, tt.args.userID, tt.args.verifyCode, tt.args.password) + + if tt.res.errFunc == nil && err != nil { + t.Errorf("should not have err: %v", err) + } + if tt.res.errFunc != nil && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v", err) + } + }) + } +} + func TestSkipMfaInit(t *testing.T) { ctrl := gomock.NewController(t) type args struct { @@ -1980,12 +2115,24 @@ func TestVerifyEmail(t *testing.T) { }, res: res{}, }, + { + name: "verify email code wrong", + args: args{ + es: GetMockManipulateUserWithEmailCode(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + userID: "AggregateID", + code: "wrong", + }, + res: res{ + errFunc: caos_errs.IsErrorInvalidArgument, + }, + }, { name: "empty userid", args: args{ es: GetMockManipulateUser(ctrl), ctx: auth.NewMockContext("orgID", "userID"), - code: "Code", + code: "code", }, res: res{ errFunc: caos_errs.IsPreconditionFailed, @@ -2008,7 +2155,7 @@ func TestVerifyEmail(t *testing.T) { es: GetMockManipulateUserNoEvents(ctrl), ctx: auth.NewMockContext("orgID", "userID"), userID: "AggregateID", - code: "Code", + code: "code", }, res: res{ errFunc: caos_errs.IsNotFound, @@ -2346,6 +2493,18 @@ func TestVerifyPhone(t *testing.T) { }, res: res{}, }, + { + name: "verify code wrong", + args: args{ + es: GetMockManipulateUserWithPhoneCode(ctrl), + ctx: auth.NewMockContext("orgID", "userID"), + userID: "AggregateID", + code: "wrong", + }, + res: res{ + errFunc: caos_errs.IsErrorInvalidArgument, + }, + }, { name: "empty userid", args: args{ diff --git a/internal/user/repository/eventsourcing/model/email.go b/internal/user/repository/eventsourcing/model/email.go index 734ac257ab..099365953a 100644 --- a/internal/user/repository/eventsourcing/model/email.go +++ b/internal/user/repository/eventsourcing/model/email.go @@ -94,6 +94,7 @@ func (a *Email) setData(event *es_models.Event) error { func (a *EmailCode) SetData(event *es_models.Event) error { a.ObjectRoot.AppendEvent(event) + a.CreationDate = event.CreationDate if err := json.Unmarshal(event.Data, a); err != nil { logging.Log("EVEN-lo9s").WithError(err).Error("could not unmarshal event data") return caos_errs.ThrowInternal(err, "MODEL-s8uws", "could not unmarshal event") diff --git a/internal/user/repository/eventsourcing/model/password.go b/internal/user/repository/eventsourcing/model/password.go index 6273a79374..591f68a574 100644 --- a/internal/user/repository/eventsourcing/model/password.go +++ b/internal/user/repository/eventsourcing/model/password.go @@ -74,9 +74,10 @@ func (pw *Password) setData(event *es_models.Event) error { return nil } -func (a *PasswordCode) SetData(event *es_models.Event) error { - a.ObjectRoot.AppendEvent(event) - if err := json.Unmarshal(event.Data, a); err != nil { +func (c *PasswordCode) SetData(event *es_models.Event) error { + c.ObjectRoot.AppendEvent(event) + c.CreationDate = event.CreationDate + if err := json.Unmarshal(event.Data, c); err != nil { logging.Log("EVEN-lo0y2").WithError(err).Error("could not unmarshal event data") return caos_errs.ThrowInternal(err, "MODEL-q21dr", "could not unmarshal event") } diff --git a/internal/user/repository/eventsourcing/model/phone.go b/internal/user/repository/eventsourcing/model/phone.go index ed806158c7..2416690c5c 100644 --- a/internal/user/repository/eventsourcing/model/phone.go +++ b/internal/user/repository/eventsourcing/model/phone.go @@ -90,9 +90,10 @@ func (p *Phone) setData(event *es_models.Event) error { return nil } -func (a *PhoneCode) SetData(event *es_models.Event) error { - a.ObjectRoot.AppendEvent(event) - if err := json.Unmarshal(event.Data, a); err != nil { +func (c *PhoneCode) SetData(event *es_models.Event) error { + c.ObjectRoot.AppendEvent(event) + c.CreationDate = event.CreationDate + if err := json.Unmarshal(event.Data, c); err != nil { logging.Log("EVEN-sk8ws").WithError(err).Error("could not unmarshal event data") return caos_errs.ThrowInternal(err, "MODEL-7hdj3", "could not unmarshal event") } diff --git a/internal/user/repository/eventsourcing/model/types.go b/internal/user/repository/eventsourcing/model/types.go index f2cbe799b0..e9d03fccae 100644 --- a/internal/user/repository/eventsourcing/model/types.go +++ b/internal/user/repository/eventsourcing/model/types.go @@ -7,10 +7,12 @@ const ( UserUserNameAggregate models.AggregateType = "user.username" UserEmailAggregate models.AggregateType = "user.email" - UserAdded models.EventType = "user.added" - UserRegistered models.EventType = "user.selfregistered" - InitializedUserCodeAdded models.EventType = "user.initialization.code.added" - InitializedUserCodeSent models.EventType = "user.initialization.code.sent" + UserAdded models.EventType = "user.added" + UserRegistered models.EventType = "user.selfregistered" + InitializedUserCodeAdded models.EventType = "user.initialization.code.added" + InitializedUserCodeSent models.EventType = "user.initialization.code.sent" + InitializedUserCheckSucceeded models.EventType = "user.initialization.check.succeeded" + InitializedUserCheckFailed models.EventType = "user.initialization.check.failed" UserUserNameReserved models.EventType = "user.username.reserved" UserUserNameReleased models.EventType = "user.username.released" @@ -29,15 +31,17 @@ const ( UserPasswordCheckSucceeded models.EventType = "user.password.check.succeeded" UserPasswordCheckFailed models.EventType = "user.password.check.failed" - UserEmailChanged models.EventType = "user.email.changed" - UserEmailVerified models.EventType = "user.email.verified" - UserEmailCodeAdded models.EventType = "user.email.code.added" - UserEmailCodeSent models.EventType = "user.email.code.sent" + UserEmailChanged models.EventType = "user.email.changed" + UserEmailVerified models.EventType = "user.email.verified" + UserEmailVerificationFailed models.EventType = "user.email.verification.failed" + UserEmailCodeAdded models.EventType = "user.email.code.added" + UserEmailCodeSent models.EventType = "user.email.code.sent" - UserPhoneChanged models.EventType = "user.phone.changed" - UserPhoneVerified models.EventType = "user.phone.verified" - UserPhoneCodeAdded models.EventType = "user.phone.code.added" - UserPhoneCodeSent models.EventType = "user.phone.code.sent" + UserPhoneChanged models.EventType = "user.phone.changed" + UserPhoneVerified models.EventType = "user.phone.verified" + UserPhoneVerificationFailed models.EventType = "user.phone.verification.failed" + UserPhoneCodeAdded models.EventType = "user.phone.code.added" + UserPhoneCodeSent models.EventType = "user.phone.code.sent" UserProfileChanged models.EventType = "user.profile.changed" UserAddressChanged models.EventType = "user.address.changed" diff --git a/internal/user/repository/eventsourcing/user.go b/internal/user/repository/eventsourcing/user.go index 97d8870f49..ebb568340b 100644 --- a/internal/user/repository/eventsourcing/user.go +++ b/internal/user/repository/eventsourcing/user.go @@ -248,6 +248,38 @@ func UserInitCodeSentAggregate(aggCreator *es_models.AggregateCreator, existing } } +func InitCodeVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, password *model.Password) func(ctx context.Context) (*es_models.Aggregate, error) { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := UserAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + if existing.Email != nil && !existing.Email.IsEmailVerified { + agg, err = agg.AppendEvent(model.UserEmailVerified, nil) + if err != nil { + return nil, err + } + } + if password != nil { + agg, err = agg.AppendEvent(model.UserPasswordChanged, password) + if err != nil { + return nil, err + } + } + return agg.AppendEvent(model.InitializedUserCheckSucceeded, nil) + } +} + +func InitCodeCheckFailedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := UserAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + return agg.AppendEvent(model.InitializedUserCheckFailed, nil) + } +} + func SkipMfaAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { agg, err := UserAggregate(ctx, aggCreator, existing) @@ -378,7 +410,7 @@ func EmailChangeAggregate(ctx context.Context, aggCreator *es_models.AggregateCr return append(aggregates, agg), nil } -func EmailVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) { +func EmailVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc { return func(ctx context.Context) (*es_models.Aggregate, error) { agg, err := UserAggregate(ctx, aggCreator, existing) if err != nil { @@ -388,6 +420,16 @@ func EmailVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *mo } } +func EmailVerificationFailedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := UserAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + return agg.AppendEvent(model.UserEmailVerificationFailed, nil) + } +} + func EmailVerificationCodeAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, code *model.EmailCode) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if code == nil { @@ -443,7 +485,8 @@ func PhoneChangeAggregate(aggCreator *es_models.AggregateCreator, existing *mode return agg, nil } } -func PhoneVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) func(ctx context.Context) (*es_models.Aggregate, error) { + +func PhoneVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc { return func(ctx context.Context) (*es_models.Aggregate, error) { agg, err := UserAggregate(ctx, aggCreator, existing) if err != nil { @@ -453,6 +496,16 @@ func PhoneVerifiedAggregate(aggCreator *es_models.AggregateCreator, existing *mo } } +func PhoneVerificationFailedAggregate(aggCreator *es_models.AggregateCreator, existing *model.User) es_sdk.AggregateFunc { + return func(ctx context.Context) (*es_models.Aggregate, error) { + agg, err := UserAggregate(ctx, aggCreator, existing) + if err != nil { + return nil, err + } + return agg.AppendEvent(model.UserPhoneVerificationFailed, nil) + } +} + func PhoneVerificationCodeAggregate(aggCreator *es_models.AggregateCreator, existing *model.User, code *model.PhoneCode) func(ctx context.Context) (*es_models.Aggregate, error) { return func(ctx context.Context) (*es_models.Aggregate, error) { if code == nil { diff --git a/internal/user/repository/eventsourcing/user_test.go b/internal/user/repository/eventsourcing/user_test.go index a7369b744c..cb5ef9f048 100644 --- a/internal/user/repository/eventsourcing/user_test.go +++ b/internal/user/repository/eventsourcing/user_test.go @@ -716,7 +716,91 @@ func TestInitCodeSentAggregate(t *testing.T) { } } -func TestSkipMfaAggregate(t *testing.T) { +func TestInitCodeVerifiedAggregate(t *testing.T) { + type args struct { + ctx context.Context + existing *model.User + password *model.Password + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventTypes []models.EventType + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "user init code only email verify", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &model.User{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, + Profile: &model.Profile{UserName: "UserName"}, + Email: &model.Email{EmailAddress: "EmailAddress"}, + }, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 2, + eventTypes: []models.EventType{model.UserEmailVerified, model.InitializedUserCheckSucceeded}, + }, + }, + { + name: "user init code only password", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &model.User{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, + Profile: &model.Profile{UserName: "UserName"}, + Email: &model.Email{EmailAddress: "EmailAddress", IsEmailVerified: true}, + }, + password: &model.Password{ChangeRequired: false}, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 2, + eventTypes: []models.EventType{model.UserPasswordChanged, model.InitializedUserCheckSucceeded}, + }, + }, + { + name: "user init code email and pw", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &model.User{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, + Profile: &model.Profile{UserName: "UserName"}, + Email: &model.Email{EmailAddress: "EmailAddress"}, + }, + password: &model.Password{ChangeRequired: false}, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 3, + eventTypes: []models.EventType{model.UserEmailVerified, model.UserPasswordChanged, model.InitializedUserCheckSucceeded}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := InitCodeVerifiedAggregate(tt.args.aggCreator, tt.args.existing, tt.args.password)(tt.args.ctx) + + if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + for i := 0; i < tt.res.eventLen; i++ { + if tt.res.errFunc == nil && agg.Events[i].Type != tt.res.eventTypes[i] { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) + } + } + if tt.res.errFunc != nil && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + +func TestInitCodeCheckFailedAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.User @@ -764,6 +848,54 @@ func TestSkipMfaAggregate(t *testing.T) { } } +func TestSkipMfaAggregate(t *testing.T) { + type args struct { + ctx context.Context + existing *model.User + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventType models.EventType + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "init code check failed", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &model.User{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, + Profile: &model.Profile{UserName: "UserName"}, + }, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventType: model.InitializedUserCheckFailed, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := InitCodeCheckFailedAggregate(tt.args.aggCreator, tt.args.existing)(tt.args.ctx) + + if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + if tt.res.errFunc == nil && agg.Events[0].Type != tt.res.eventType { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventType, agg.Events[0].Type.String()) + } + if tt.res.errFunc != nil && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + func TestChangePasswordAggregate(t *testing.T) { type args struct { ctx context.Context @@ -1113,7 +1245,7 @@ func TestChangeEmailAggregate(t *testing.T) { } } -func TestVerifiyEmailAggregate(t *testing.T) { +func TestVerifyEmailAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.User @@ -1161,6 +1293,54 @@ func TestVerifiyEmailAggregate(t *testing.T) { } } +func TestVerificationFailedEmailAggregate(t *testing.T) { + type args struct { + ctx context.Context + existing *model.User + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventTypes []models.EventType + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "user email verification failed aggregate ok", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &model.User{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}}, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventTypes: []models.EventType{model.UserEmailVerificationFailed}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := EmailVerificationFailedAggregate(tt.args.aggCreator, tt.args.existing)(tt.args.ctx) + + if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + for i := 0; i < tt.res.eventLen; i++ { + if tt.res.errFunc == nil && agg.Events[i].Type != tt.res.eventTypes[i] { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) + } + } + if tt.res.errFunc != nil && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + func TestCreateEmailCodeAggregate(t *testing.T) { type args struct { ctx context.Context @@ -1391,7 +1571,7 @@ func TestChangePhoneAggregate(t *testing.T) { } } -func TestVerifiyPhoneAggregate(t *testing.T) { +func TestVerifyPhoneAggregate(t *testing.T) { type args struct { ctx context.Context existing *model.User @@ -1441,6 +1621,56 @@ func TestVerifiyPhoneAggregate(t *testing.T) { } } +func TestVerificationFailedPhoneAggregate(t *testing.T) { + type args struct { + ctx context.Context + existing *model.User + aggCreator *models.AggregateCreator + } + type res struct { + eventLen int + eventTypes []models.EventType + errFunc func(err error) bool + } + tests := []struct { + name string + args args + res res + }{ + { + name: "user phone verification failed aggregate ok", + args: args{ + ctx: auth.NewMockContext("orgID", "userID"), + existing: &model.User{ObjectRoot: models.ObjectRoot{AggregateID: "ID"}, + Phone: &model.Phone{PhoneNumber: "PhoneNumber"}, + }, + aggCreator: models.NewAggregateCreator("Test"), + }, + res: res{ + eventLen: 1, + eventTypes: []models.EventType{model.UserPhoneVerificationFailed}, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + agg, err := PhoneVerificationFailedAggregate(tt.args.aggCreator, tt.args.existing)(tt.args.ctx) + + if tt.res.errFunc == nil && len(agg.Events) != tt.res.eventLen { + t.Errorf("got wrong event len: expected: %v, actual: %v ", tt.res.eventLen, len(agg.Events)) + } + for i := 0; i < tt.res.eventLen; i++ { + if tt.res.errFunc == nil && agg.Events[i].Type != tt.res.eventTypes[i] { + t.Errorf("got wrong event type: expected: %v, actual: %v ", tt.res.eventTypes[i], agg.Events[i].Type.String()) + } + } + if tt.res.errFunc != nil && !tt.res.errFunc(err) { + t.Errorf("got wrong err: %v ", err) + } + }) + } +} + func TestCreatePhoneCodeAggregate(t *testing.T) { type args struct { ctx context.Context diff --git a/internal/user/repository/view/model/user.go b/internal/user/repository/view/model/user.go index 7ed99e0f9c..a3a9d0da7a 100644 --- a/internal/user/repository/view/model/user.go +++ b/internal/user/repository/view/model/user.go @@ -54,6 +54,7 @@ type UserView struct { OTPState int32 `json:"-" gorm:"column:otp_state"` MfaMaxSetUp int32 `json:"-" gorm:"column:mfa_max_set_up"` MfaInitSkipped time.Time `json:"-" gorm:"column:mfa_init_skipped"` + InitRequired bool `json:"-" gorm:"column:init_required"` Sequence uint64 `json:"-" gorm:"column:sequence"` } @@ -87,6 +88,7 @@ func UserFromModel(user *model.UserView) *UserView { OTPState: int32(user.OTPState), MfaMaxSetUp: int32(user.MfaMaxSetUp), MfaInitSkipped: user.MfaInitSkipped, + InitRequired: user.InitRequired, Sequence: user.Sequence, } } @@ -121,6 +123,7 @@ func UserToModel(user *UserView) *model.UserView { OTPState: model.MfaState(user.OTPState), MfaMaxSetUp: req_model.MfaLevel(user.MfaMaxSetUp), MfaInitSkipped: user.MfaInitSkipped, + InitRequired: user.InitRequired, Sequence: user.Sequence, } } @@ -177,6 +180,10 @@ func (u *UserView) AppendEvent(event *models.Event) (err error) { u.OTPState = int32(model.MFASTATE_UNSPECIFIED) case es_model.MfaInitSkipped: u.MfaInitSkipped = event.CreationDate + case es_model.InitializedUserCodeAdded: + u.InitRequired = true + case es_model.InitializedUserCheckSucceeded: + u.InitRequired = false } u.ComputeObject() return err @@ -203,6 +210,7 @@ func (u *UserView) setPasswordData(event *models.Event) error { } u.PasswordSet = password.Secret != nil u.PasswordChangeRequired = password.ChangeRequired + u.PasswordChanged = event.CreationDate return nil } diff --git a/internal/user/repository/view/model/user_session.go b/internal/user/repository/view/model/user_session.go index f4a1e6158f..d5c0a7ff48 100644 --- a/internal/user/repository/view/model/user_session.go +++ b/internal/user/repository/view/model/user_session.go @@ -14,7 +14,6 @@ import ( ) const ( - UserSessionKeySessionID = "id" UserSessionKeyUserAgentID = "user_agent_id" UserSessionKeyUserID = "user_id" UserSessionKeyState = "state" @@ -22,18 +21,19 @@ const ( ) type UserSessionView struct { - ID string `json:"-" gorm:"column:id;primary_key"` - CreationDate time.Time `json:"-" gorm:"column:creation_date"` - ChangeDate time.Time `json:"-" gorm:"column:change_date"` - ResourceOwner string `json:"-" gorm:"column:resource_owner"` - State int32 `json:"-" gorm:"column:state"` - UserAgentID string `json:"userAgentID" gorm:"column:user_agent_id"` - UserID string `json:"userID" gorm:"column:user_id"` - UserName string `json:"userName" gorm:"column:user_name"` - PasswordVerification time.Time `json:"-" gorm:"column:password_verification"` - MfaSoftwareVerification time.Time `json:"-" gorm:"column:mfa_software_verification"` - MfaHardwareVerification time.Time `json:"-" gorm:"column:mfa_hardware_verification"` - Sequence uint64 `json:"-" gorm:"column:sequence"` + CreationDate time.Time `json:"-" gorm:"column:creation_date"` + ChangeDate time.Time `json:"-" gorm:"column:change_date"` + ResourceOwner string `json:"-" gorm:"column:resource_owner"` + State int32 `json:"-" gorm:"column:state"` + UserAgentID string `json:"userAgentID" gorm:"column:user_agent_id;primary_key"` + UserID string `json:"userID" gorm:"column:user_id;primary_key"` + UserName string `json:"userName" gorm:"column:user_name"` + PasswordVerification time.Time `json:"-" gorm:"column:password_verification"` + MfaSoftwareVerification time.Time `json:"-" gorm:"column:mfa_software_verification"` + MfaSoftwareVerificationType int32 `json:"-" gorm:"column:mfa_software_verification_type"` + MfaHardwareVerification time.Time `json:"-" gorm:"column:mfa_hardware_verification"` + MfaHardwareVerificationType int32 `json:"-" gorm:"column:mfa_hardware_verification_type"` + Sequence uint64 `json:"-" gorm:"column:sequence"` } func UserSessionFromEvent(event *models.Event) (*UserSessionView, error) { @@ -47,18 +47,19 @@ func UserSessionFromEvent(event *models.Event) (*UserSessionView, error) { func UserSessionToModel(userSession *UserSessionView) *model.UserSessionView { return &model.UserSessionView{ - ID: userSession.ID, - ChangeDate: userSession.ChangeDate, - CreationDate: userSession.CreationDate, - ResourceOwner: userSession.ResourceOwner, - State: req_model.UserSessionState(userSession.State), - UserAgentID: userSession.UserAgentID, - UserID: userSession.UserID, - UserName: userSession.UserName, - PasswordVerification: userSession.PasswordVerification, - MfaSoftwareVerification: userSession.MfaSoftwareVerification, - MfaHardwareVerification: userSession.MfaHardwareVerification, - Sequence: userSession.Sequence, + ChangeDate: userSession.ChangeDate, + CreationDate: userSession.CreationDate, + ResourceOwner: userSession.ResourceOwner, + State: req_model.UserSessionState(userSession.State), + UserAgentID: userSession.UserAgentID, + UserID: userSession.UserID, + UserName: userSession.UserName, + PasswordVerification: userSession.PasswordVerification, + MfaSoftwareVerification: userSession.MfaSoftwareVerification, + MfaSoftwareVerificationType: req_model.MfaType(userSession.MfaSoftwareVerificationType), + MfaHardwareVerification: userSession.MfaHardwareVerification, + MfaHardwareVerificationType: req_model.MfaType(userSession.MfaHardwareVerificationType), + Sequence: userSession.Sequence, } } @@ -80,6 +81,7 @@ func (v *UserSessionView) AppendEvent(event *models.Event) { v.PasswordVerification = time.Time{} case es_model.MfaOtpCheckSucceeded: v.MfaSoftwareVerification = event.CreationDate + v.MfaSoftwareVerificationType = int32(req_model.MfaTypeOTP) case es_model.MfaOtpCheckFailed, es_model.MfaOtpRemoved: v.MfaSoftwareVerification = time.Time{} diff --git a/internal/user/repository/view/model/user_session_query.go b/internal/user/repository/view/model/user_session_query.go index ca7fef4733..897648cabb 100644 --- a/internal/user/repository/view/model/user_session_query.go +++ b/internal/user/repository/view/model/user_session_query.go @@ -51,8 +51,6 @@ func (req UserSessionSearchQuery) GetValue() interface{} { func (key UserSessionSearchKey) ToColumnName() string { switch usr_model.UserSessionSearchKey(key) { - case usr_model.USERSESSIONSEARCHKEY_SESSION_ID: - return UserSessionKeySessionID case usr_model.USERSESSIONSEARCHKEY_USER_AGENT_ID: return UserSessionKeyUserAgentID case usr_model.USERSESSIONSEARCHKEY_USER_ID: diff --git a/internal/user/repository/view/user_session_view.go b/internal/user/repository/view/user_session_view.go index 652ba6d40a..09f68ed01c 100644 --- a/internal/user/repository/view/user_session_view.go +++ b/internal/user/repository/view/user_session_view.go @@ -9,13 +9,6 @@ import ( "github.com/caos/zitadel/internal/view" ) -func UserSessionByID(db *gorm.DB, table, sessionID string) (*model.UserSessionView, error) { - userSession := new(model.UserSessionView) - query := view.PrepareGetByKey(table, model.UserSessionSearchKey(usr_model.USERSESSIONSEARCHKEY_SESSION_ID), sessionID) - err := query(db, userSession) - return userSession, err -} - func UserSessionByIDs(db *gorm.DB, table, agentID, userID string) (*model.UserSessionView, error) { userSession := new(model.UserSessionView) userAgentQuery := model.UserSessionSearchQuery{ @@ -33,6 +26,20 @@ func UserSessionByIDs(db *gorm.DB, table, agentID, userID string) (*model.UserSe return userSession, err } +func UserSessionsByUserID(db *gorm.DB, table, userID string) ([]*model.UserSessionView, error) { + userSessions := make([]*model.UserSessionView, 0) + userAgentQuery := &usr_model.UserSessionSearchQuery{ + Key: usr_model.USERSESSIONSEARCHKEY_USER_ID, + Method: global_model.SEARCHMETHOD_EQUALS, + Value: userID, + } + query := view.PrepareSearchQuery(table, model.UserSessionSearchRequest{ + Queries: []*usr_model.UserSessionSearchQuery{userAgentQuery}, + }) + _, err := query(db, &userSessions) + return userSessions, err +} + func UserSessionsByAgentID(db *gorm.DB, table, agentID string) ([]*model.UserSessionView, error) { userSessions := make([]*model.UserSessionView, 0) userAgentQuery := &usr_model.UserSessionSearchQuery{ @@ -43,7 +50,7 @@ func UserSessionsByAgentID(db *gorm.DB, table, agentID string) ([]*model.UserSes query := view.PrepareSearchQuery(table, model.UserSessionSearchRequest{ Queries: []*usr_model.UserSessionSearchQuery{userAgentQuery}, }) - _, err := query(db, userSessions) + _, err := query(db, &userSessions) return userSessions, err } diff --git a/internal/usergrant/model/project_org.go b/internal/usergrant/model/project_org.go new file mode 100644 index 0000000000..792b923474 --- /dev/null +++ b/internal/usergrant/model/project_org.go @@ -0,0 +1,13 @@ +package model + +type ProjectOrgSearchResponse struct { + Offset uint64 + Limit uint64 + TotalResult uint64 + Result []*Org +} + +type Org struct { + OrgID string + OrgName string +} diff --git a/internal/usergrant/model/user_grant_view.go b/internal/usergrant/model/user_grant_view.go index f4636d3601..d8509f705a 100644 --- a/internal/usergrant/model/user_grant_view.go +++ b/internal/usergrant/model/user_grant_view.go @@ -43,6 +43,7 @@ const ( USERGRANTSEARCHKEY_RESOURCEOWNER USERGRANTSEARCHKEY_STATE USERGRANTSEARCHKEY_GRANT_ID + USERGRANTSEARCHKEY_ORG_NAME ) type UserGrantSearchQuery struct { diff --git a/internal/usergrant/model/zitadel_permission.go b/internal/usergrant/model/zitadel_permission.go new file mode 100644 index 0000000000..072791dc95 --- /dev/null +++ b/internal/usergrant/model/zitadel_permission.go @@ -0,0 +1,23 @@ +package model + +type Permissions struct { + Permissions []string +} + +func (p *Permissions) AppendPermissions(ctxID string, permissions ...string) { + for _, permission := range permissions { + p.appendPermission(ctxID, permission) + } +} + +func (p *Permissions) appendPermission(ctxID, permission string) { + if ctxID != "" { + permission = permission + ":" + ctxID + } + for _, existingPermission := range p.Permissions { + if existingPermission == permission { + return + } + } + p.Permissions = append(p.Permissions, permission) +} diff --git a/internal/usergrant/repository/eventsourcing/eventstore.go b/internal/usergrant/repository/eventsourcing/eventstore.go index 171511d62e..3e8450352c 100644 --- a/internal/usergrant/repository/eventsourcing/eventstore.go +++ b/internal/usergrant/repository/eventsourcing/eventstore.go @@ -57,7 +57,6 @@ func (es *UserGrantEventStore) AddUserGrant(ctx context.Context, grant *grant_mo if grant == nil || !grant.IsValid() { return nil, caos_errs.ThrowPreconditionFailed(nil, "EVENT-sdiw3", "User grant invalid") } - //TODO: Check Uniqueness id, err := es.idGenerator.Next() if err != nil { return nil, err diff --git a/internal/usergrant/repository/eventsourcing/user_grant.go b/internal/usergrant/repository/eventsourcing/user_grant.go index 15ae30a684..d1791621f5 100644 --- a/internal/usergrant/repository/eventsourcing/user_grant.go +++ b/internal/usergrant/repository/eventsourcing/user_grant.go @@ -5,7 +5,7 @@ import ( "github.com/caos/zitadel/internal/api/auth" "github.com/caos/zitadel/internal/errors" es_models "github.com/caos/zitadel/internal/eventstore/models" - org_model "github.com/caos/zitadel/internal/org/model" + org_es_model "github.com/caos/zitadel/internal/org/repository/eventsourcing/model" proj_model "github.com/caos/zitadel/internal/project/model" proj_es_model "github.com/caos/zitadel/internal/project/repository/eventsourcing/model" usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" @@ -48,7 +48,7 @@ func UserGrantAddedAggregate(ctx context.Context, aggCreator *es_models.Aggregat return nil, err } validationQuery := es_models.NewSearchQuery(). - AggregateTypeFilter(usr_model.UserAggregate, org_model.OrgAggregate, proj_es_model.ProjectAggregate). + AggregateTypeFilter(usr_model.UserAggregate, org_es_model.OrgAggregate, proj_es_model.ProjectAggregate). AggregateIDsFilter(grant.UserID, auth.GetCtxData(ctx).OrgID, grant.ProjectID) validation := addUserGrantValidation(auth.GetCtxData(ctx).OrgID, grant) @@ -185,11 +185,11 @@ func addUserGrantValidation(resourceOwner string, grant *model.UserGrant) func(. case usr_model.UserRemoved: existsUser = false } - case org_model.OrgAggregate: + case org_es_model.OrgAggregate: switch event.Type { - case org_model.OrgAdded: + case org_es_model.OrgAdded: existsOrg = true - case org_model.OrgRemoved: + case org_es_model.OrgRemoved: existsOrg = false } case proj_es_model.ProjectAggregate: diff --git a/internal/usergrant/repository/view/model/user_grant.go b/internal/usergrant/repository/view/model/user_grant.go index 3ea8518755..c81f613b62 100644 --- a/internal/usergrant/repository/view/model/user_grant.go +++ b/internal/usergrant/repository/view/model/user_grant.go @@ -18,6 +18,7 @@ const ( UserGrantKeyProjectID = "project_id" UserGrantKeyResourceOwner = "resource_owner" UserGrantKeyState = "state" + UserGrantKeyOrgName = "org_name" ) type UserGrantView struct { diff --git a/internal/usergrant/repository/view/model/user_grant_query.go b/internal/usergrant/repository/view/model/user_grant_query.go index 2d69fd6555..c76114bedb 100644 --- a/internal/usergrant/repository/view/model/user_grant_query.go +++ b/internal/usergrant/repository/view/model/user_grant_query.go @@ -61,6 +61,8 @@ func (key UserGrantSearchKey) ToColumnName() string { return UserGrantKeyResourceOwner case grant_model.USERGRANTSEARCHKEY_GRANT_ID: return UserGrantKeyID + case grant_model.USERGRANTSEARCHKEY_ORG_NAME: + return UserGrantKeyOrgName default: return "" } diff --git a/internal/usergrant/repository/view/user_grant_view.go b/internal/usergrant/repository/view/user_grant_view.go index 3d9a5fee3f..c5ca4ec466 100644 --- a/internal/usergrant/repository/view/user_grant_view.go +++ b/internal/usergrant/repository/view/user_grant_view.go @@ -15,6 +15,17 @@ func UserGrantByID(db *gorm.DB, table, grantID string) (*model.UserGrantView, er return user, err } +func UserGrantByIDs(db *gorm.DB, table, resourceOwnerID, projectID, userID string) (*model.UserGrantView, error) { + user := new(model.UserGrantView) + + resourceOwnerIDQuery := model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_RESOURCEOWNER, Value: resourceOwnerID, Method: global_model.SEARCHMETHOD_EQUALS} + projectIDQuery := model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_PROJECT_ID, Value: projectID, Method: global_model.SEARCHMETHOD_EQUALS} + userIDQuery := model.UserGrantSearchQuery{Key: grant_model.USERGRANTSEARCHKEY_USER_ID, Value: userID, Method: global_model.SEARCHMETHOD_EQUALS} + query := view.PrepareGetByQuery(table, resourceOwnerIDQuery, projectIDQuery, userIDQuery) + err := query(db, user) + return user, err +} + func SearchUserGrants(db *gorm.DB, table string, req *grant_model.UserGrantSearchRequest) ([]*model.UserGrantView, int, error) { users := make([]*model.UserGrantView, 0) query := view.PrepareSearchQuery(table, model.UserGrantSearchRequest{Limit: req.Limit, Offset: req.Offset, Queries: req.Queries}) diff --git a/internal/view/query.go b/internal/view/query.go index 26829e1122..90f3dc4ce3 100644 --- a/internal/view/query.go +++ b/internal/view/query.go @@ -98,6 +98,12 @@ func SetQuery(query *gorm.DB, key ColumnKey, value interface{}, method model.Sea query = query.Where("LOWER("+column+") LIKE LOWER(?)", "%"+valueText+"%") case model.SEARCHMETHOD_NOT_EQUALS: query = query.Where(""+column+" <> ?", value) + case model.SEARCHMETHOD_GREATER_THAN: + query = query.Where(column+" > ?", value) + case model.SEARCHMETHOD_LESS_THAN: + query = query.Where(column+" < ?", value) + case model.SEARCHMETHOD_IN: + query = query.Where(column+" IN (?)", value) default: return nil, nil } diff --git a/internal/view/requests.go b/internal/view/requests.go index 22276138a4..2a888efd24 100644 --- a/internal/view/requests.go +++ b/internal/view/requests.go @@ -75,7 +75,7 @@ func PrepareDeleteByKey(table string, key ColumnKey, id string) func(db *gorm.DB type Key struct { Key ColumnKey - Value string + Value interface{} } func PrepareDeleteByKeys(table string, keys ...Key) func(db *gorm.DB) error { diff --git a/k8s/base/deployment.yaml b/k8s/base/deployment.yaml index 05777d819f..d24e32c39a 100644 --- a/k8s/base/deployment.yaml +++ b/k8s/base/deployment.yaml @@ -20,26 +20,26 @@ spec: - name: zitadel image: docker.pkg.github.com/caos/zitadel/zitadel:latest imagePullPolicy: IfNotPresent - args: ["-login=false", "-console=false"] + args: [] ports: - name: management-rest - containerPort: 60021 + containerPort: 50011 - name: management-grpc - containerPort: 60020 + containerPort: 50010 - name: auth-rest - containerPort: 60051 + containerPort: 50021 - name: issuer-rest - containerPort: 60052 + containerPort: 50022 - name: auth-grpc - containerPort: 60050 + containerPort: 50020 - name: admin-rest - containerPort: 60091 + containerPort: 50041 - name: admin-grpc - containerPort: 60090 + containerPort: 50040 - name: console-http - containerPort: 9090 + containerPort: 50050 - name: accounts-http - containerPort: 61121 + containerPort: 50031 env: - name: ZITADEL_GOOGLE_CHAT_URL valueFrom: diff --git a/migrations/cockroach/V1.11__auth_oidc.sql b/migrations/cockroach/V1.11__auth_oidc.sql new file mode 100644 index 0000000000..de38f0d349 --- /dev/null +++ b/migrations/cockroach/V1.11__auth_oidc.sql @@ -0,0 +1,56 @@ +BEGIN; + +CREATE TABLE auth.keys ( + id TEXT, + + creation_date TIMESTAMPTZ, + change_date TIMESTAMPTZ, + + resource_owner TEXT, + private BOOLEAN, + expiry TIMESTAMPTZ, + algorithm TEXT, + usage SMALLINT, + key JSONB, + sequence BIGINT, + + PRIMARY KEY (id, private) +); + +CREATE TABLE auth.applications ( + id TEXT, + + creation_date TIMESTAMPTZ, + change_date TIMESTAMPTZ, + sequence BIGINT, + + app_state SMALLINT, + resource_owner TEXT, + app_name TEXT, + project_id TEXT, + app_type SMALLINT, + is_oidc BOOLEAN, + oidc_client_id TEXT, + oidc_redirect_uris TEXT ARRAY, + oidc_response_types SMALLINT ARRAY, + oidc_grant_types SMALLINT ARRAY, + oidc_application_type SMALLINT, + oidc_auth_method_type SMALLINT, + oidc_post_logout_redirect_uris TEXT ARRAY, + + PRIMARY KEY (id) +); + +ALTER TABLE auth.tokens ADD COLUMN scopes TEXT ARRAY; +ALTER TABLE auth.tokens ADD COLUMN audience TEXT ARRAY; + +ALTER TABLE auth.users ADD COLUMN init_required BOOLEAN; +ALTER TABLE management.users ADD COLUMN init_required BOOLEAN; + +ALTER TABLE auth.auth_requests ADD COLUMN code TEXT; +ALTER TABLE auth.auth_requests ADD COLUMN request_type smallint; + +ALTER TABLE auth.user_sessions ADD COLUMN mfa_software_verification_type smallint; +ALTER TABLE auth.user_sessions ADD COLUMN mfa_hardware_verification_type smallint; + +COMMIT; \ No newline at end of file diff --git a/migrations/cockroach/V1.12__auth_user_grant_view.sql b/migrations/cockroach/V1.12__auth_user_grant_view.sql new file mode 100644 index 0000000000..307f5fb6d0 --- /dev/null +++ b/migrations/cockroach/V1.12__auth_user_grant_view.sql @@ -0,0 +1,25 @@ +BEGIN; + +CREATE TABLE auth.user_grants ( + id TEXT, + resource_owner TEXT, + project_id TEXT, + user_id TEXT, + org_name TEXT, + org_domain TEXT, + project_name TEXT, + user_name TEXT, + first_name TEXT, + last_name TEXT, + email TEXT, + role_keys TEXT Array, + + grant_state SMALLINT, + creation_date TIMESTAMPTZ, + change_date TIMESTAMPTZ, + sequence BIGINT, + + PRIMARY KEY (id) +); + +COMMIT; diff --git a/migrations/cockroach/V1.13__auth_org_view.sql b/migrations/cockroach/V1.13__auth_org_view.sql new file mode 100644 index 0000000000..9cdb2da0fc --- /dev/null +++ b/migrations/cockroach/V1.13__auth_org_view.sql @@ -0,0 +1,17 @@ +BEGIN; + +CREATE TABLE auth.orgs ( + id TEXT, + creation_date TIMESTAMPTZ, + change_date TIMESTAMPTZ, + resource_owner TEXT, + org_state SMALLINT, + sequence BIGINT, + + domain TEXT, + name TEXT, + + PRIMARY KEY (id) +); + +COMMIT; diff --git a/migrations/cockroach/V1.14__authz.sql b/migrations/cockroach/V1.14__authz.sql new file mode 100644 index 0000000000..3e38e2ee6b --- /dev/null +++ b/migrations/cockroach/V1.14__authz.sql @@ -0,0 +1,94 @@ +BEGIN; + +CREATE DATABASE authz; + + +COMMIT; + +BEGIN; + +CREATE USER authz; + +GRANT SELECT, INSERT, UPDATE, DELETE ON DATABASE authz TO authz; +GRANT SELECT, INSERT, UPDATE ON DATABASE eventstore TO authz; +GRANT SELECT, INSERT, UPDATE ON TABLE eventstore.* TO authz; +GRANT SELECT, INSERT, UPDATE ON DATABASE auth TO authz; +GRANT SELECT, INSERT, UPDATE ON TABLE auth.* TO authz; + +COMMIT; + +BEGIN; + +CREATE TABLE authz.locks ( + locker_id TEXT, + locked_until TIMESTAMPTZ, + object_type TEXT, + + PRIMARY KEY (object_type) +); + +CREATE TABLE authz.current_sequences ( + view_name TEXT, + + current_sequence BIGINT, + + PRIMARY KEY (view_name) +); + +CREATE TABLE authz.failed_event ( + view_name TEXT, + failed_sequence BIGINT, + failure_count SMALLINT, + err_msg TEXT, + + PRIMARY KEY (view_name, failed_sequence) +); + +CREATE TABLE authz.user_grants ( + id TEXT, + resource_owner TEXT, + project_id TEXT, + user_id TEXT, + org_name TEXT, + org_domain TEXT, + project_name TEXT, + user_name TEXT, + first_name TEXT, + last_name TEXT, + email TEXT, + role_keys TEXT Array, + + grant_state SMALLINT, + creation_date TIMESTAMPTZ, + change_date TIMESTAMPTZ, + sequence BIGINT, + + PRIMARY KEY (id) +); + +CREATE TABLE authz.applications ( + id TEXT, + + creation_date TIMESTAMPTZ, + change_date TIMESTAMPTZ, + sequence BIGINT, + + app_state SMALLINT, + resource_owner TEXT, + app_name TEXT, + project_id TEXT, + app_type SMALLINT, + is_oidc BOOLEAN, + oidc_client_id TEXT, + oidc_redirect_uris TEXT ARRAY, + oidc_response_types SMALLINT ARRAY, + oidc_grant_types SMALLINT ARRAY, + oidc_application_type SMALLINT, + oidc_auth_method_type SMALLINT, + oidc_post_logout_redirect_uris TEXT ARRAY, + + PRIMARY KEY (id) +); + +COMMIT; + diff --git a/pkg/admin/admin.go b/pkg/admin/admin.go index e4807186e7..526abea3a9 100644 --- a/pkg/admin/admin.go +++ b/pkg/admin/admin.go @@ -2,6 +2,7 @@ package admin import ( "context" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" sd "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/logging" @@ -15,9 +16,9 @@ type Config struct { API api.Config } -func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) { +func Start(ctx context.Context, config Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, systemDefaults sd.SystemDefaults) { repo, err := eventsourcing.Start(ctx, config.Repository, systemDefaults) logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app") - api.Start(ctx, config.API, authZ, repo) + api.Start(ctx, config.API, authZRepo, authZ, repo) } diff --git a/pkg/admin/api/api.go b/pkg/admin/api/api.go index 3272ef5ea8..4aaf4e1843 100644 --- a/pkg/admin/api/api.go +++ b/pkg/admin/api/api.go @@ -2,6 +2,7 @@ package api import ( "context" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" "github.com/caos/zitadel/internal/admin/repository" "github.com/caos/zitadel/internal/api/auth" @@ -14,8 +15,8 @@ type Config struct { GRPC grpc_util.Config } -func Start(ctx context.Context, conf Config, authZ auth.Config, repo repository.Repository) { - grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZ, repo) +func Start(ctx context.Context, conf Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) { + grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZRepo, authZ, repo) grpcGateway := grpc.StartGateway(conf.GRPC.ToGatewayConfig()) server.StartServer(ctx, grpcServer) diff --git a/pkg/admin/api/grpc/server.go b/pkg/admin/api/grpc/server.go index a82832f532..0349117cca 100644 --- a/pkg/admin/api/grpc/server.go +++ b/pkg/admin/api/grpc/server.go @@ -6,6 +6,7 @@ import ( "github.com/caos/zitadel/internal/api/auth" grpc_util "github.com/caos/zitadel/internal/api/grpc" "github.com/caos/zitadel/internal/api/grpc/server/middleware" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" "google.golang.org/grpc" ) @@ -20,13 +21,13 @@ type Server struct { repo repository.Repository } -func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository.Repository) *Server { +func StartServer(conf grpc_util.ServerConfig, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) *Server { return &Server{ port: conf.Port, org: repo, repo: repo, authZ: authZ, - verifier: admin_auth.Start(), + verifier: admin_auth.Start(authZRepo), } } diff --git a/pkg/auth/api/api.go b/pkg/auth/api/api.go index 737af9eb8b..8240b0c091 100644 --- a/pkg/auth/api/api.go +++ b/pkg/auth/api/api.go @@ -2,22 +2,29 @@ package api import ( "context" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" + + "github.com/caos/oidc/pkg/op" auth_util "github.com/caos/zitadel/internal/api/auth" grpc_util "github.com/caos/zitadel/internal/api/grpc" "github.com/caos/zitadel/internal/api/grpc/server" "github.com/caos/zitadel/internal/auth/repository" "github.com/caos/zitadel/pkg/auth/api/grpc" + "github.com/caos/zitadel/pkg/auth/api/oidc" ) type Config struct { GRPC grpc_util.Config + OIDC oidc.OPHandlerConfig } -func Start(ctx context.Context, conf Config, authZ auth_util.Config, repo repository.Repository) { - grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZ, repo) +func Start(ctx context.Context, conf Config, authZRepo *authz_repo.EsRepository, authZ auth_util.Config, authRepo repository.Repository) { + grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZRepo, authZ, authRepo) grpcGateway := grpc.StartGateway(conf.GRPC.ToGatewayConfig()) + oidcHandler := oidc.NewProvider(ctx, conf.OIDC, authRepo) server.StartServer(ctx, grpcServer) server.StartGateway(ctx, grpcGateway) + op.Start(ctx, oidcHandler) } diff --git a/pkg/auth/api/grpc/auth.pb.authoptions.go b/pkg/auth/api/grpc/auth.pb.authoptions.go index ee4700c496..5b53bf70fa 100644 --- a/pkg/auth/api/grpc/auth.pb.authoptions.go +++ b/pkg/auth/api/grpc/auth.pb.authoptions.go @@ -105,12 +105,12 @@ var AuthService_AuthMethods = utils_auth.MethodMapping{ CheckParam: "", }, - "/zitadel.auth.api.v1.AuthService/SearchMyProjectOrgs": utils_auth.Option{ + "/zitadel.auth.api.v1.AuthService/SearchMyUserGrant": utils_auth.Option{ Permission: "authenticated", CheckParam: "", }, - "/zitadel.auth.api.v1.AuthService/IsIamAdmin": utils_auth.Option{ + "/zitadel.auth.api.v1.AuthService/SearchMyProjectOrgs": utils_auth.Option{ Permission: "authenticated", CheckParam: "", }, diff --git a/pkg/auth/api/grpc/auth.pb.go b/pkg/auth/api/grpc/auth.pb.go index 2eae69dd91..fad9bc28a2 100644 --- a/pkg/auth/api/grpc/auth.pb.go +++ b/pkg/auth/api/grpc/auth.pb.go @@ -1,11 +1,13 @@ // Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.20.1 +// protoc v3.11.3 // source: auth.proto package grpc import ( context "context" - fmt "fmt" _ "github.com/caos/zitadel/internal/protoc/protoc-gen-authoption/authoption" _ "github.com/envoyproxy/protoc-gen-validate/validate" proto "github.com/golang/protobuf/proto" @@ -17,19 +19,22 @@ import ( grpc "google.golang.org/grpc" codes "google.golang.org/grpc/codes" status "google.golang.org/grpc/status" - math "math" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" ) -// Reference imports to suppress errors if they are not otherwise used. -var _ = proto.Marshal -var _ = fmt.Errorf -var _ = math.Inf +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) -// This is a compile-time assertion to ensure that this generated file -// is compatible with the proto package it is being compiled against. -// A compilation error at this line likely means your copy of the -// proto package needs to be updated. -const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 type UserSessionState int32 @@ -39,24 +44,45 @@ const ( UserSessionState_USERSESSIONSTATE_TERMINATED UserSessionState = 2 ) -var UserSessionState_name = map[int32]string{ - 0: "USERSESSIONSTATE_UNSPECIFIED", - 1: "USERSESSIONSTATE_ACTIVE", - 2: "USERSESSIONSTATE_TERMINATED", -} +// Enum value maps for UserSessionState. +var ( + UserSessionState_name = map[int32]string{ + 0: "USERSESSIONSTATE_UNSPECIFIED", + 1: "USERSESSIONSTATE_ACTIVE", + 2: "USERSESSIONSTATE_TERMINATED", + } + UserSessionState_value = map[string]int32{ + "USERSESSIONSTATE_UNSPECIFIED": 0, + "USERSESSIONSTATE_ACTIVE": 1, + "USERSESSIONSTATE_TERMINATED": 2, + } +) -var UserSessionState_value = map[string]int32{ - "USERSESSIONSTATE_UNSPECIFIED": 0, - "USERSESSIONSTATE_ACTIVE": 1, - "USERSESSIONSTATE_TERMINATED": 2, +func (x UserSessionState) Enum() *UserSessionState { + p := new(UserSessionState) + *p = x + return p } func (x UserSessionState) String() string { - return proto.EnumName(UserSessionState_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (UserSessionState) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[0].Descriptor() +} + +func (UserSessionState) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[0] +} + +func (x UserSessionState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use UserSessionState.Descriptor instead. func (UserSessionState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{0} + return file_auth_proto_rawDescGZIP(), []int{0} } type OIDCResponseType int32 @@ -67,24 +93,45 @@ const ( OIDCResponseType_OIDCRESPONSETYPE_ID_TOKEN_TOKEN OIDCResponseType = 2 ) -var OIDCResponseType_name = map[int32]string{ - 0: "OIDCRESPONSETYPE_CODE", - 1: "OIDCRESPONSETYPE_ID_TOKEN", - 2: "OIDCRESPONSETYPE_ID_TOKEN_TOKEN", -} +// Enum value maps for OIDCResponseType. +var ( + OIDCResponseType_name = map[int32]string{ + 0: "OIDCRESPONSETYPE_CODE", + 1: "OIDCRESPONSETYPE_ID_TOKEN", + 2: "OIDCRESPONSETYPE_ID_TOKEN_TOKEN", + } + OIDCResponseType_value = map[string]int32{ + "OIDCRESPONSETYPE_CODE": 0, + "OIDCRESPONSETYPE_ID_TOKEN": 1, + "OIDCRESPONSETYPE_ID_TOKEN_TOKEN": 2, + } +) -var OIDCResponseType_value = map[string]int32{ - "OIDCRESPONSETYPE_CODE": 0, - "OIDCRESPONSETYPE_ID_TOKEN": 1, - "OIDCRESPONSETYPE_ID_TOKEN_TOKEN": 2, +func (x OIDCResponseType) Enum() *OIDCResponseType { + p := new(OIDCResponseType) + *p = x + return p } func (x OIDCResponseType) String() string { - return proto.EnumName(OIDCResponseType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (OIDCResponseType) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[1].Descriptor() +} + +func (OIDCResponseType) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[1] +} + +func (x OIDCResponseType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use OIDCResponseType.Descriptor instead. func (OIDCResponseType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{1} + return file_auth_proto_rawDescGZIP(), []int{1} } type UserState int32 @@ -99,32 +146,53 @@ const ( UserState_USERSTATE_INITIAL UserState = 6 ) -var UserState_name = map[int32]string{ - 0: "USERSTATE_UNSPECIEFIED", - 1: "USERSTATE_ACTIVE", - 2: "USERSTATE_INACTIVE", - 3: "USERSTATE_DELETED", - 4: "USERSTATE_LOCKED", - 5: "USERSTATE_SUSPEND", - 6: "USERSTATE_INITIAL", -} +// Enum value maps for UserState. +var ( + UserState_name = map[int32]string{ + 0: "USERSTATE_UNSPECIEFIED", + 1: "USERSTATE_ACTIVE", + 2: "USERSTATE_INACTIVE", + 3: "USERSTATE_DELETED", + 4: "USERSTATE_LOCKED", + 5: "USERSTATE_SUSPEND", + 6: "USERSTATE_INITIAL", + } + UserState_value = map[string]int32{ + "USERSTATE_UNSPECIEFIED": 0, + "USERSTATE_ACTIVE": 1, + "USERSTATE_INACTIVE": 2, + "USERSTATE_DELETED": 3, + "USERSTATE_LOCKED": 4, + "USERSTATE_SUSPEND": 5, + "USERSTATE_INITIAL": 6, + } +) -var UserState_value = map[string]int32{ - "USERSTATE_UNSPECIEFIED": 0, - "USERSTATE_ACTIVE": 1, - "USERSTATE_INACTIVE": 2, - "USERSTATE_DELETED": 3, - "USERSTATE_LOCKED": 4, - "USERSTATE_SUSPEND": 5, - "USERSTATE_INITIAL": 6, +func (x UserState) Enum() *UserState { + p := new(UserState) + *p = x + return p } func (x UserState) String() string { - return proto.EnumName(UserState_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (UserState) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[2].Descriptor() +} + +func (UserState) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[2] +} + +func (x UserState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use UserState.Descriptor instead. func (UserState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{2} + return file_auth_proto_rawDescGZIP(), []int{2} } type Gender int32 @@ -136,26 +204,47 @@ const ( Gender_GENDER_DIVERSE Gender = 3 ) -var Gender_name = map[int32]string{ - 0: "GENDER_UNSPECIFIED", - 1: "GENDER_FEMALE", - 2: "GENDER_MALE", - 3: "GENDER_DIVERSE", -} +// Enum value maps for Gender. +var ( + Gender_name = map[int32]string{ + 0: "GENDER_UNSPECIFIED", + 1: "GENDER_FEMALE", + 2: "GENDER_MALE", + 3: "GENDER_DIVERSE", + } + Gender_value = map[string]int32{ + "GENDER_UNSPECIFIED": 0, + "GENDER_FEMALE": 1, + "GENDER_MALE": 2, + "GENDER_DIVERSE": 3, + } +) -var Gender_value = map[string]int32{ - "GENDER_UNSPECIFIED": 0, - "GENDER_FEMALE": 1, - "GENDER_MALE": 2, - "GENDER_DIVERSE": 3, +func (x Gender) Enum() *Gender { + p := new(Gender) + *p = x + return p } func (x Gender) String() string { - return proto.EnumName(Gender_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (Gender) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[3].Descriptor() +} + +func (Gender) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[3] +} + +func (x Gender) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Gender.Descriptor instead. func (Gender) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{3} + return file_auth_proto_rawDescGZIP(), []int{3} } type MfaType int32 @@ -166,24 +255,45 @@ const ( MfaType_MFATYPE_OTP MfaType = 2 ) -var MfaType_name = map[int32]string{ - 0: "MFATYPE_UNSPECIFIED", - 1: "MFATYPE_SMS", - 2: "MFATYPE_OTP", -} +// Enum value maps for MfaType. +var ( + MfaType_name = map[int32]string{ + 0: "MFATYPE_UNSPECIFIED", + 1: "MFATYPE_SMS", + 2: "MFATYPE_OTP", + } + MfaType_value = map[string]int32{ + "MFATYPE_UNSPECIFIED": 0, + "MFATYPE_SMS": 1, + "MFATYPE_OTP": 2, + } +) -var MfaType_value = map[string]int32{ - "MFATYPE_UNSPECIFIED": 0, - "MFATYPE_SMS": 1, - "MFATYPE_OTP": 2, +func (x MfaType) Enum() *MfaType { + p := new(MfaType) + *p = x + return p } func (x MfaType) String() string { - return proto.EnumName(MfaType_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (MfaType) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[4].Descriptor() +} + +func (MfaType) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[4] +} + +func (x MfaType) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use MfaType.Descriptor instead. func (MfaType) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{4} + return file_auth_proto_rawDescGZIP(), []int{4} } type MFAState int32 @@ -195,26 +305,96 @@ const ( MFAState_MFASTATE_REMOVED MFAState = 3 ) -var MFAState_name = map[int32]string{ - 0: "MFASTATE_UNSPECIFIED", - 1: "MFASTATE_NOT_READY", - 2: "MFASTATE_READY", - 3: "MFASTATE_REMOVED", -} +// Enum value maps for MFAState. +var ( + MFAState_name = map[int32]string{ + 0: "MFASTATE_UNSPECIFIED", + 1: "MFASTATE_NOT_READY", + 2: "MFASTATE_READY", + 3: "MFASTATE_REMOVED", + } + MFAState_value = map[string]int32{ + "MFASTATE_UNSPECIFIED": 0, + "MFASTATE_NOT_READY": 1, + "MFASTATE_READY": 2, + "MFASTATE_REMOVED": 3, + } +) -var MFAState_value = map[string]int32{ - "MFASTATE_UNSPECIFIED": 0, - "MFASTATE_NOT_READY": 1, - "MFASTATE_READY": 2, - "MFASTATE_REMOVED": 3, +func (x MFAState) Enum() *MFAState { + p := new(MFAState) + *p = x + return p } func (x MFAState) String() string { - return proto.EnumName(MFAState_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (MFAState) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[5].Descriptor() +} + +func (MFAState) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[5] +} + +func (x MFAState) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use MFAState.Descriptor instead. func (MFAState) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{5} + return file_auth_proto_rawDescGZIP(), []int{5} +} + +type UserGrantSearchKey int32 + +const ( + UserGrantSearchKey_UserGrantSearchKey_UNKNOWN UserGrantSearchKey = 0 + UserGrantSearchKey_UserGrantSearchKey_ORG_ID UserGrantSearchKey = 1 + UserGrantSearchKey_UserGrantSearchKey_PROJECT_ID UserGrantSearchKey = 2 +) + +// Enum value maps for UserGrantSearchKey. +var ( + UserGrantSearchKey_name = map[int32]string{ + 0: "UserGrantSearchKey_UNKNOWN", + 1: "UserGrantSearchKey_ORG_ID", + 2: "UserGrantSearchKey_PROJECT_ID", + } + UserGrantSearchKey_value = map[string]int32{ + "UserGrantSearchKey_UNKNOWN": 0, + "UserGrantSearchKey_ORG_ID": 1, + "UserGrantSearchKey_PROJECT_ID": 2, + } +) + +func (x UserGrantSearchKey) Enum() *UserGrantSearchKey { + p := new(UserGrantSearchKey) + *p = x + return p +} + +func (x UserGrantSearchKey) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (UserGrantSearchKey) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[6].Descriptor() +} + +func (UserGrantSearchKey) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[6] +} + +func (x UserGrantSearchKey) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use UserGrantSearchKey.Descriptor instead. +func (UserGrantSearchKey) EnumDescriptor() ([]byte, []int) { + return file_auth_proto_rawDescGZIP(), []int{6} } type MyProjectOrgSearchKey int32 @@ -224,171 +404,242 @@ const ( MyProjectOrgSearchKey_MYPROJECTORGSEARCHKEY_ORG_NAME MyProjectOrgSearchKey = 1 ) -var MyProjectOrgSearchKey_name = map[int32]string{ - 0: "MYPROJECTORGSEARCHKEY_UNSPECIFIED", - 1: "MYPROJECTORGSEARCHKEY_ORG_NAME", -} +// Enum value maps for MyProjectOrgSearchKey. +var ( + MyProjectOrgSearchKey_name = map[int32]string{ + 0: "MYPROJECTORGSEARCHKEY_UNSPECIFIED", + 1: "MYPROJECTORGSEARCHKEY_ORG_NAME", + } + MyProjectOrgSearchKey_value = map[string]int32{ + "MYPROJECTORGSEARCHKEY_UNSPECIFIED": 0, + "MYPROJECTORGSEARCHKEY_ORG_NAME": 1, + } +) -var MyProjectOrgSearchKey_value = map[string]int32{ - "MYPROJECTORGSEARCHKEY_UNSPECIFIED": 0, - "MYPROJECTORGSEARCHKEY_ORG_NAME": 1, +func (x MyProjectOrgSearchKey) Enum() *MyProjectOrgSearchKey { + p := new(MyProjectOrgSearchKey) + *p = x + return p } func (x MyProjectOrgSearchKey) String() string { - return proto.EnumName(MyProjectOrgSearchKey_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (MyProjectOrgSearchKey) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[7].Descriptor() +} + +func (MyProjectOrgSearchKey) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[7] +} + +func (x MyProjectOrgSearchKey) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use MyProjectOrgSearchKey.Descriptor instead. func (MyProjectOrgSearchKey) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{6} + return file_auth_proto_rawDescGZIP(), []int{7} } type SearchMethod int32 const ( - SearchMethod_SEARCHMETHOD_EQUALS SearchMethod = 0 - SearchMethod_SEARCHMETHOD_STARTS_WITH SearchMethod = 1 - SearchMethod_SEARCHMETHOD_CONTAINS SearchMethod = 2 + SearchMethod_SEARCHMETHOD_EQUALS SearchMethod = 0 + SearchMethod_SEARCHMETHOD_STARTS_WITH SearchMethod = 1 + SearchMethod_SEARCHMETHOD_CONTAINS SearchMethod = 2 + SearchMethod_SEARCHMETHOD_EQUALS_IGNORE_CASE SearchMethod = 3 + SearchMethod_SEARCHMETHOD_STARTS_WITH_IGNORE_CASE SearchMethod = 4 + SearchMethod_SEARCHMETHOD_CONTAINS_IGNORE_CASE SearchMethod = 5 ) -var SearchMethod_name = map[int32]string{ - 0: "SEARCHMETHOD_EQUALS", - 1: "SEARCHMETHOD_STARTS_WITH", - 2: "SEARCHMETHOD_CONTAINS", -} +// Enum value maps for SearchMethod. +var ( + SearchMethod_name = map[int32]string{ + 0: "SEARCHMETHOD_EQUALS", + 1: "SEARCHMETHOD_STARTS_WITH", + 2: "SEARCHMETHOD_CONTAINS", + 3: "SEARCHMETHOD_EQUALS_IGNORE_CASE", + 4: "SEARCHMETHOD_STARTS_WITH_IGNORE_CASE", + 5: "SEARCHMETHOD_CONTAINS_IGNORE_CASE", + } + SearchMethod_value = map[string]int32{ + "SEARCHMETHOD_EQUALS": 0, + "SEARCHMETHOD_STARTS_WITH": 1, + "SEARCHMETHOD_CONTAINS": 2, + "SEARCHMETHOD_EQUALS_IGNORE_CASE": 3, + "SEARCHMETHOD_STARTS_WITH_IGNORE_CASE": 4, + "SEARCHMETHOD_CONTAINS_IGNORE_CASE": 5, + } +) -var SearchMethod_value = map[string]int32{ - "SEARCHMETHOD_EQUALS": 0, - "SEARCHMETHOD_STARTS_WITH": 1, - "SEARCHMETHOD_CONTAINS": 2, +func (x SearchMethod) Enum() *SearchMethod { + p := new(SearchMethod) + *p = x + return p } func (x SearchMethod) String() string { - return proto.EnumName(SearchMethod_name, int32(x)) + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) } +func (SearchMethod) Descriptor() protoreflect.EnumDescriptor { + return file_auth_proto_enumTypes[8].Descriptor() +} + +func (SearchMethod) Type() protoreflect.EnumType { + return &file_auth_proto_enumTypes[8] +} + +func (x SearchMethod) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use SearchMethod.Descriptor instead. func (SearchMethod) EnumDescriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{7} + return file_auth_proto_rawDescGZIP(), []int{8} } type UserSessionViews struct { - UserSessions []*UserSessionView `protobuf:"bytes,1,rep,name=user_sessions,json=userSessions,proto3" json:"user_sessions,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserSessions []*UserSessionView `protobuf:"bytes,1,rep,name=user_sessions,json=userSessions,proto3" json:"user_sessions,omitempty"` } -func (m *UserSessionViews) Reset() { *m = UserSessionViews{} } -func (m *UserSessionViews) String() string { return proto.CompactTextString(m) } -func (*UserSessionViews) ProtoMessage() {} +func (x *UserSessionViews) Reset() { + *x = UserSessionViews{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserSessionViews) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserSessionViews) ProtoMessage() {} + +func (x *UserSessionViews) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserSessionViews.ProtoReflect.Descriptor instead. func (*UserSessionViews) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{0} + return file_auth_proto_rawDescGZIP(), []int{0} } -func (m *UserSessionViews) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserSessionViews.Unmarshal(m, b) -} -func (m *UserSessionViews) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserSessionViews.Marshal(b, m, deterministic) -} -func (m *UserSessionViews) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserSessionViews.Merge(m, src) -} -func (m *UserSessionViews) XXX_Size() int { - return xxx_messageInfo_UserSessionViews.Size(m) -} -func (m *UserSessionViews) XXX_DiscardUnknown() { - xxx_messageInfo_UserSessionViews.DiscardUnknown(m) -} - -var xxx_messageInfo_UserSessionViews proto.InternalMessageInfo - -func (m *UserSessionViews) GetUserSessions() []*UserSessionView { - if m != nil { - return m.UserSessions +func (x *UserSessionViews) GetUserSessions() []*UserSessionView { + if x != nil { + return x.UserSessions } return nil } type UserSessionView struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - AgentId string `protobuf:"bytes,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` - AuthState UserSessionState `protobuf:"varint,3,opt,name=auth_state,json=authState,proto3,enum=zitadel.auth.api.v1.UserSessionState" json:"auth_state,omitempty"` - UserId string `protobuf:"bytes,4,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - UserName string `protobuf:"bytes,5,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"` - Sequence uint64 `protobuf:"varint,6,opt,name=sequence,proto3" json:"sequence,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + AgentId string `protobuf:"bytes,2,opt,name=agent_id,json=agentId,proto3" json:"agent_id,omitempty"` + AuthState UserSessionState `protobuf:"varint,3,opt,name=auth_state,json=authState,proto3,enum=zitadel.auth.api.v1.UserSessionState" json:"auth_state,omitempty"` + UserId string `protobuf:"bytes,4,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + UserName string `protobuf:"bytes,5,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"` + Sequence uint64 `protobuf:"varint,6,opt,name=sequence,proto3" json:"sequence,omitempty"` } -func (m *UserSessionView) Reset() { *m = UserSessionView{} } -func (m *UserSessionView) String() string { return proto.CompactTextString(m) } -func (*UserSessionView) ProtoMessage() {} +func (x *UserSessionView) Reset() { + *x = UserSessionView{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserSessionView) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserSessionView) ProtoMessage() {} + +func (x *UserSessionView) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserSessionView.ProtoReflect.Descriptor instead. func (*UserSessionView) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{1} + return file_auth_proto_rawDescGZIP(), []int{1} } -func (m *UserSessionView) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserSessionView.Unmarshal(m, b) -} -func (m *UserSessionView) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserSessionView.Marshal(b, m, deterministic) -} -func (m *UserSessionView) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserSessionView.Merge(m, src) -} -func (m *UserSessionView) XXX_Size() int { - return xxx_messageInfo_UserSessionView.Size(m) -} -func (m *UserSessionView) XXX_DiscardUnknown() { - xxx_messageInfo_UserSessionView.DiscardUnknown(m) -} - -var xxx_messageInfo_UserSessionView proto.InternalMessageInfo - -func (m *UserSessionView) GetId() string { - if m != nil { - return m.Id +func (x *UserSessionView) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *UserSessionView) GetAgentId() string { - if m != nil { - return m.AgentId +func (x *UserSessionView) GetAgentId() string { + if x != nil { + return x.AgentId } return "" } -func (m *UserSessionView) GetAuthState() UserSessionState { - if m != nil { - return m.AuthState +func (x *UserSessionView) GetAuthState() UserSessionState { + if x != nil { + return x.AuthState } return UserSessionState_USERSESSIONSTATE_UNSPECIFIED } -func (m *UserSessionView) GetUserId() string { - if m != nil { - return m.UserId +func (x *UserSessionView) GetUserId() string { + if x != nil { + return x.UserId } return "" } -func (m *UserSessionView) GetUserName() string { - if m != nil { - return m.UserName +func (x *UserSessionView) GetUserName() string { + if x != nil { + return x.UserName } return "" } -func (m *UserSessionView) GetSequence() uint64 { - if m != nil { - return m.Sequence +func (x *UserSessionView) GetSequence() uint64 { + if x != nil { + return x.Sequence } return 0 } type User struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` State UserState `protobuf:"varint,2,opt,name=state,proto3,enum=zitadel.auth.api.v1.UserState" json:"state,omitempty"` CreationDate *timestamp.Timestamp `protobuf:"bytes,3,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` @@ -414,1827 +665,3245 @@ type User struct { StreetAddress string `protobuf:"bytes,23,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` PasswordChangeRequired bool `protobuf:"varint,24,opt,name=password_change_required,json=passwordChangeRequired,proto3" json:"password_change_required,omitempty"` Sequence uint64 `protobuf:"varint,25,opt,name=sequence,proto3" json:"sequence,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` } -func (m *User) Reset() { *m = User{} } -func (m *User) String() string { return proto.CompactTextString(m) } -func (*User) ProtoMessage() {} +func (x *User) Reset() { + *x = User{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *User) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*User) ProtoMessage() {} + +func (x *User) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use User.ProtoReflect.Descriptor instead. func (*User) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{2} + return file_auth_proto_rawDescGZIP(), []int{2} } -func (m *User) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_User.Unmarshal(m, b) -} -func (m *User) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_User.Marshal(b, m, deterministic) -} -func (m *User) XXX_Merge(src proto.Message) { - xxx_messageInfo_User.Merge(m, src) -} -func (m *User) XXX_Size() int { - return xxx_messageInfo_User.Size(m) -} -func (m *User) XXX_DiscardUnknown() { - xxx_messageInfo_User.DiscardUnknown(m) -} - -var xxx_messageInfo_User proto.InternalMessageInfo - -func (m *User) GetId() string { - if m != nil { - return m.Id +func (x *User) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *User) GetState() UserState { - if m != nil { - return m.State +func (x *User) GetState() UserState { + if x != nil { + return x.State } return UserState_USERSTATE_UNSPECIEFIED } -func (m *User) GetCreationDate() *timestamp.Timestamp { - if m != nil { - return m.CreationDate +func (x *User) GetCreationDate() *timestamp.Timestamp { + if x != nil { + return x.CreationDate } return nil } -func (m *User) GetActivationDate() *timestamp.Timestamp { - if m != nil { - return m.ActivationDate +func (x *User) GetActivationDate() *timestamp.Timestamp { + if x != nil { + return x.ActivationDate } return nil } -func (m *User) GetChangeDate() *timestamp.Timestamp { - if m != nil { - return m.ChangeDate +func (x *User) GetChangeDate() *timestamp.Timestamp { + if x != nil { + return x.ChangeDate } return nil } -func (m *User) GetLastLogin() *timestamp.Timestamp { - if m != nil { - return m.LastLogin +func (x *User) GetLastLogin() *timestamp.Timestamp { + if x != nil { + return x.LastLogin } return nil } -func (m *User) GetPasswordChanged() *timestamp.Timestamp { - if m != nil { - return m.PasswordChanged +func (x *User) GetPasswordChanged() *timestamp.Timestamp { + if x != nil { + return x.PasswordChanged } return nil } -func (m *User) GetUserName() string { - if m != nil { - return m.UserName +func (x *User) GetUserName() string { + if x != nil { + return x.UserName } return "" } -func (m *User) GetFirstName() string { - if m != nil { - return m.FirstName +func (x *User) GetFirstName() string { + if x != nil { + return x.FirstName } return "" } -func (m *User) GetLastName() string { - if m != nil { - return m.LastName +func (x *User) GetLastName() string { + if x != nil { + return x.LastName } return "" } -func (m *User) GetNickName() string { - if m != nil { - return m.NickName +func (x *User) GetNickName() string { + if x != nil { + return x.NickName } return "" } -func (m *User) GetDisplayName() string { - if m != nil { - return m.DisplayName +func (x *User) GetDisplayName() string { + if x != nil { + return x.DisplayName } return "" } -func (m *User) GetPreferredLanguage() string { - if m != nil { - return m.PreferredLanguage +func (x *User) GetPreferredLanguage() string { + if x != nil { + return x.PreferredLanguage } return "" } -func (m *User) GetGender() Gender { - if m != nil { - return m.Gender +func (x *User) GetGender() Gender { + if x != nil { + return x.Gender } return Gender_GENDER_UNSPECIFIED } -func (m *User) GetEmail() string { - if m != nil { - return m.Email +func (x *User) GetEmail() string { + if x != nil { + return x.Email } return "" } -func (m *User) GetIsEmailVerified() bool { - if m != nil { - return m.IsEmailVerified +func (x *User) GetIsEmailVerified() bool { + if x != nil { + return x.IsEmailVerified } return false } -func (m *User) GetPhone() string { - if m != nil { - return m.Phone +func (x *User) GetPhone() string { + if x != nil { + return x.Phone } return "" } -func (m *User) GetIsPhoneVerified() bool { - if m != nil { - return m.IsPhoneVerified +func (x *User) GetIsPhoneVerified() bool { + if x != nil { + return x.IsPhoneVerified } return false } -func (m *User) GetCountry() string { - if m != nil { - return m.Country +func (x *User) GetCountry() string { + if x != nil { + return x.Country } return "" } -func (m *User) GetLocality() string { - if m != nil { - return m.Locality +func (x *User) GetLocality() string { + if x != nil { + return x.Locality } return "" } -func (m *User) GetPostalCode() string { - if m != nil { - return m.PostalCode +func (x *User) GetPostalCode() string { + if x != nil { + return x.PostalCode } return "" } -func (m *User) GetRegion() string { - if m != nil { - return m.Region +func (x *User) GetRegion() string { + if x != nil { + return x.Region } return "" } -func (m *User) GetStreetAddress() string { - if m != nil { - return m.StreetAddress +func (x *User) GetStreetAddress() string { + if x != nil { + return x.StreetAddress } return "" } -func (m *User) GetPasswordChangeRequired() bool { - if m != nil { - return m.PasswordChangeRequired +func (x *User) GetPasswordChangeRequired() bool { + if x != nil { + return x.PasswordChangeRequired } return false } -func (m *User) GetSequence() uint64 { - if m != nil { - return m.Sequence +func (x *User) GetSequence() uint64 { + if x != nil { + return x.Sequence } return 0 } type UserProfile struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - UserName string `protobuf:"bytes,2,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"` - FirstName string `protobuf:"bytes,3,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"` - LastName string `protobuf:"bytes,4,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"` - NickName string `protobuf:"bytes,5,opt,name=nick_name,json=nickName,proto3" json:"nick_name,omitempty"` - DisplayName string `protobuf:"bytes,6,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` - PreferredLanguage string `protobuf:"bytes,7,opt,name=preferred_language,json=preferredLanguage,proto3" json:"preferred_language,omitempty"` - Gender Gender `protobuf:"varint,8,opt,name=gender,proto3,enum=zitadel.auth.api.v1.Gender" json:"gender,omitempty"` - Sequence uint64 `protobuf:"varint,9,opt,name=sequence,proto3" json:"sequence,omitempty"` - CreationDate *timestamp.Timestamp `protobuf:"bytes,10,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` - ChangeDate *timestamp.Timestamp `protobuf:"bytes,11,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + UserName string `protobuf:"bytes,2,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"` + FirstName string `protobuf:"bytes,3,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"` + LastName string `protobuf:"bytes,4,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"` + NickName string `protobuf:"bytes,5,opt,name=nick_name,json=nickName,proto3" json:"nick_name,omitempty"` + DisplayName string `protobuf:"bytes,6,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + PreferredLanguage string `protobuf:"bytes,7,opt,name=preferred_language,json=preferredLanguage,proto3" json:"preferred_language,omitempty"` + Gender Gender `protobuf:"varint,8,opt,name=gender,proto3,enum=zitadel.auth.api.v1.Gender" json:"gender,omitempty"` + Sequence uint64 `protobuf:"varint,9,opt,name=sequence,proto3" json:"sequence,omitempty"` + CreationDate *timestamp.Timestamp `protobuf:"bytes,10,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` + ChangeDate *timestamp.Timestamp `protobuf:"bytes,11,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` } -func (m *UserProfile) Reset() { *m = UserProfile{} } -func (m *UserProfile) String() string { return proto.CompactTextString(m) } -func (*UserProfile) ProtoMessage() {} +func (x *UserProfile) Reset() { + *x = UserProfile{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserProfile) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserProfile) ProtoMessage() {} + +func (x *UserProfile) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserProfile.ProtoReflect.Descriptor instead. func (*UserProfile) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{3} + return file_auth_proto_rawDescGZIP(), []int{3} } -func (m *UserProfile) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserProfile.Unmarshal(m, b) -} -func (m *UserProfile) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserProfile.Marshal(b, m, deterministic) -} -func (m *UserProfile) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserProfile.Merge(m, src) -} -func (m *UserProfile) XXX_Size() int { - return xxx_messageInfo_UserProfile.Size(m) -} -func (m *UserProfile) XXX_DiscardUnknown() { - xxx_messageInfo_UserProfile.DiscardUnknown(m) -} - -var xxx_messageInfo_UserProfile proto.InternalMessageInfo - -func (m *UserProfile) GetId() string { - if m != nil { - return m.Id +func (x *UserProfile) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *UserProfile) GetUserName() string { - if m != nil { - return m.UserName +func (x *UserProfile) GetUserName() string { + if x != nil { + return x.UserName } return "" } -func (m *UserProfile) GetFirstName() string { - if m != nil { - return m.FirstName +func (x *UserProfile) GetFirstName() string { + if x != nil { + return x.FirstName } return "" } -func (m *UserProfile) GetLastName() string { - if m != nil { - return m.LastName +func (x *UserProfile) GetLastName() string { + if x != nil { + return x.LastName } return "" } -func (m *UserProfile) GetNickName() string { - if m != nil { - return m.NickName +func (x *UserProfile) GetNickName() string { + if x != nil { + return x.NickName } return "" } -func (m *UserProfile) GetDisplayName() string { - if m != nil { - return m.DisplayName +func (x *UserProfile) GetDisplayName() string { + if x != nil { + return x.DisplayName } return "" } -func (m *UserProfile) GetPreferredLanguage() string { - if m != nil { - return m.PreferredLanguage +func (x *UserProfile) GetPreferredLanguage() string { + if x != nil { + return x.PreferredLanguage } return "" } -func (m *UserProfile) GetGender() Gender { - if m != nil { - return m.Gender +func (x *UserProfile) GetGender() Gender { + if x != nil { + return x.Gender } return Gender_GENDER_UNSPECIFIED } -func (m *UserProfile) GetSequence() uint64 { - if m != nil { - return m.Sequence +func (x *UserProfile) GetSequence() uint64 { + if x != nil { + return x.Sequence } return 0 } -func (m *UserProfile) GetCreationDate() *timestamp.Timestamp { - if m != nil { - return m.CreationDate +func (x *UserProfile) GetCreationDate() *timestamp.Timestamp { + if x != nil { + return x.CreationDate } return nil } -func (m *UserProfile) GetChangeDate() *timestamp.Timestamp { - if m != nil { - return m.ChangeDate +func (x *UserProfile) GetChangeDate() *timestamp.Timestamp { + if x != nil { + return x.ChangeDate } return nil } type UpdateUserProfileRequest struct { - FirstName string `protobuf:"bytes,1,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"` - LastName string `protobuf:"bytes,2,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"` - NickName string `protobuf:"bytes,3,opt,name=nick_name,json=nickName,proto3" json:"nick_name,omitempty"` - DisplayName string `protobuf:"bytes,4,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` - PreferredLanguage string `protobuf:"bytes,5,opt,name=preferred_language,json=preferredLanguage,proto3" json:"preferred_language,omitempty"` - Gender Gender `protobuf:"varint,6,opt,name=gender,proto3,enum=zitadel.auth.api.v1.Gender" json:"gender,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FirstName string `protobuf:"bytes,1,opt,name=first_name,json=firstName,proto3" json:"first_name,omitempty"` + LastName string `protobuf:"bytes,2,opt,name=last_name,json=lastName,proto3" json:"last_name,omitempty"` + NickName string `protobuf:"bytes,3,opt,name=nick_name,json=nickName,proto3" json:"nick_name,omitempty"` + DisplayName string `protobuf:"bytes,4,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` + PreferredLanguage string `protobuf:"bytes,5,opt,name=preferred_language,json=preferredLanguage,proto3" json:"preferred_language,omitempty"` + Gender Gender `protobuf:"varint,6,opt,name=gender,proto3,enum=zitadel.auth.api.v1.Gender" json:"gender,omitempty"` } -func (m *UpdateUserProfileRequest) Reset() { *m = UpdateUserProfileRequest{} } -func (m *UpdateUserProfileRequest) String() string { return proto.CompactTextString(m) } -func (*UpdateUserProfileRequest) ProtoMessage() {} +func (x *UpdateUserProfileRequest) Reset() { + *x = UpdateUserProfileRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserProfileRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserProfileRequest) ProtoMessage() {} + +func (x *UpdateUserProfileRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserProfileRequest.ProtoReflect.Descriptor instead. func (*UpdateUserProfileRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{4} + return file_auth_proto_rawDescGZIP(), []int{4} } -func (m *UpdateUserProfileRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UpdateUserProfileRequest.Unmarshal(m, b) -} -func (m *UpdateUserProfileRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UpdateUserProfileRequest.Marshal(b, m, deterministic) -} -func (m *UpdateUserProfileRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_UpdateUserProfileRequest.Merge(m, src) -} -func (m *UpdateUserProfileRequest) XXX_Size() int { - return xxx_messageInfo_UpdateUserProfileRequest.Size(m) -} -func (m *UpdateUserProfileRequest) XXX_DiscardUnknown() { - xxx_messageInfo_UpdateUserProfileRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_UpdateUserProfileRequest proto.InternalMessageInfo - -func (m *UpdateUserProfileRequest) GetFirstName() string { - if m != nil { - return m.FirstName +func (x *UpdateUserProfileRequest) GetFirstName() string { + if x != nil { + return x.FirstName } return "" } -func (m *UpdateUserProfileRequest) GetLastName() string { - if m != nil { - return m.LastName +func (x *UpdateUserProfileRequest) GetLastName() string { + if x != nil { + return x.LastName } return "" } -func (m *UpdateUserProfileRequest) GetNickName() string { - if m != nil { - return m.NickName +func (x *UpdateUserProfileRequest) GetNickName() string { + if x != nil { + return x.NickName } return "" } -func (m *UpdateUserProfileRequest) GetDisplayName() string { - if m != nil { - return m.DisplayName +func (x *UpdateUserProfileRequest) GetDisplayName() string { + if x != nil { + return x.DisplayName } return "" } -func (m *UpdateUserProfileRequest) GetPreferredLanguage() string { - if m != nil { - return m.PreferredLanguage +func (x *UpdateUserProfileRequest) GetPreferredLanguage() string { + if x != nil { + return x.PreferredLanguage } return "" } -func (m *UpdateUserProfileRequest) GetGender() Gender { - if m != nil { - return m.Gender +func (x *UpdateUserProfileRequest) GetGender() Gender { + if x != nil { + return x.Gender } return Gender_GENDER_UNSPECIFIED } type UserEmail struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` - IsEmailVerified bool `protobuf:"varint,3,opt,name=isEmailVerified,proto3" json:"isEmailVerified,omitempty"` - Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` - CreationDate *timestamp.Timestamp `protobuf:"bytes,5,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` - ChangeDate *timestamp.Timestamp `protobuf:"bytes,6,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Email string `protobuf:"bytes,2,opt,name=email,proto3" json:"email,omitempty"` + IsEmailVerified bool `protobuf:"varint,3,opt,name=isEmailVerified,proto3" json:"isEmailVerified,omitempty"` + Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` + CreationDate *timestamp.Timestamp `protobuf:"bytes,5,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` + ChangeDate *timestamp.Timestamp `protobuf:"bytes,6,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` } -func (m *UserEmail) Reset() { *m = UserEmail{} } -func (m *UserEmail) String() string { return proto.CompactTextString(m) } -func (*UserEmail) ProtoMessage() {} +func (x *UserEmail) Reset() { + *x = UserEmail{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserEmail) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserEmail) ProtoMessage() {} + +func (x *UserEmail) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserEmail.ProtoReflect.Descriptor instead. func (*UserEmail) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{5} + return file_auth_proto_rawDescGZIP(), []int{5} } -func (m *UserEmail) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserEmail.Unmarshal(m, b) -} -func (m *UserEmail) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserEmail.Marshal(b, m, deterministic) -} -func (m *UserEmail) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserEmail.Merge(m, src) -} -func (m *UserEmail) XXX_Size() int { - return xxx_messageInfo_UserEmail.Size(m) -} -func (m *UserEmail) XXX_DiscardUnknown() { - xxx_messageInfo_UserEmail.DiscardUnknown(m) -} - -var xxx_messageInfo_UserEmail proto.InternalMessageInfo - -func (m *UserEmail) GetId() string { - if m != nil { - return m.Id +func (x *UserEmail) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *UserEmail) GetEmail() string { - if m != nil { - return m.Email +func (x *UserEmail) GetEmail() string { + if x != nil { + return x.Email } return "" } -func (m *UserEmail) GetIsEmailVerified() bool { - if m != nil { - return m.IsEmailVerified +func (x *UserEmail) GetIsEmailVerified() bool { + if x != nil { + return x.IsEmailVerified } return false } -func (m *UserEmail) GetSequence() uint64 { - if m != nil { - return m.Sequence +func (x *UserEmail) GetSequence() uint64 { + if x != nil { + return x.Sequence } return 0 } -func (m *UserEmail) GetCreationDate() *timestamp.Timestamp { - if m != nil { - return m.CreationDate +func (x *UserEmail) GetCreationDate() *timestamp.Timestamp { + if x != nil { + return x.CreationDate } return nil } -func (m *UserEmail) GetChangeDate() *timestamp.Timestamp { - if m != nil { - return m.ChangeDate +func (x *UserEmail) GetChangeDate() *timestamp.Timestamp { + if x != nil { + return x.ChangeDate } return nil } type VerifyMyUserEmailRequest struct { - Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` } -func (m *VerifyMyUserEmailRequest) Reset() { *m = VerifyMyUserEmailRequest{} } -func (m *VerifyMyUserEmailRequest) String() string { return proto.CompactTextString(m) } -func (*VerifyMyUserEmailRequest) ProtoMessage() {} +func (x *VerifyMyUserEmailRequest) Reset() { + *x = VerifyMyUserEmailRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyMyUserEmailRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyMyUserEmailRequest) ProtoMessage() {} + +func (x *VerifyMyUserEmailRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyMyUserEmailRequest.ProtoReflect.Descriptor instead. func (*VerifyMyUserEmailRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{6} + return file_auth_proto_rawDescGZIP(), []int{6} } -func (m *VerifyMyUserEmailRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_VerifyMyUserEmailRequest.Unmarshal(m, b) -} -func (m *VerifyMyUserEmailRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_VerifyMyUserEmailRequest.Marshal(b, m, deterministic) -} -func (m *VerifyMyUserEmailRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_VerifyMyUserEmailRequest.Merge(m, src) -} -func (m *VerifyMyUserEmailRequest) XXX_Size() int { - return xxx_messageInfo_VerifyMyUserEmailRequest.Size(m) -} -func (m *VerifyMyUserEmailRequest) XXX_DiscardUnknown() { - xxx_messageInfo_VerifyMyUserEmailRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_VerifyMyUserEmailRequest proto.InternalMessageInfo - -func (m *VerifyMyUserEmailRequest) GetCode() string { - if m != nil { - return m.Code +func (x *VerifyMyUserEmailRequest) GetCode() string { + if x != nil { + return x.Code } return "" } type VerifyUserEmailRequest struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Code string `protobuf:"bytes,2,opt,name=code,proto3" json:"code,omitempty"` } -func (m *VerifyUserEmailRequest) Reset() { *m = VerifyUserEmailRequest{} } -func (m *VerifyUserEmailRequest) String() string { return proto.CompactTextString(m) } -func (*VerifyUserEmailRequest) ProtoMessage() {} +func (x *VerifyUserEmailRequest) Reset() { + *x = VerifyUserEmailRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[7] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyUserEmailRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyUserEmailRequest) ProtoMessage() {} + +func (x *VerifyUserEmailRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[7] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyUserEmailRequest.ProtoReflect.Descriptor instead. func (*VerifyUserEmailRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{7} + return file_auth_proto_rawDescGZIP(), []int{7} } -func (m *VerifyUserEmailRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_VerifyUserEmailRequest.Unmarshal(m, b) -} -func (m *VerifyUserEmailRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_VerifyUserEmailRequest.Marshal(b, m, deterministic) -} -func (m *VerifyUserEmailRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_VerifyUserEmailRequest.Merge(m, src) -} -func (m *VerifyUserEmailRequest) XXX_Size() int { - return xxx_messageInfo_VerifyUserEmailRequest.Size(m) -} -func (m *VerifyUserEmailRequest) XXX_DiscardUnknown() { - xxx_messageInfo_VerifyUserEmailRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_VerifyUserEmailRequest proto.InternalMessageInfo - -func (m *VerifyUserEmailRequest) GetId() string { - if m != nil { - return m.Id +func (x *VerifyUserEmailRequest) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *VerifyUserEmailRequest) GetCode() string { - if m != nil { - return m.Code +func (x *VerifyUserEmailRequest) GetCode() string { + if x != nil { + return x.Code } return "" } type UpdateUserEmailRequest struct { - Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Email string `protobuf:"bytes,1,opt,name=email,proto3" json:"email,omitempty"` } -func (m *UpdateUserEmailRequest) Reset() { *m = UpdateUserEmailRequest{} } -func (m *UpdateUserEmailRequest) String() string { return proto.CompactTextString(m) } -func (*UpdateUserEmailRequest) ProtoMessage() {} +func (x *UpdateUserEmailRequest) Reset() { + *x = UpdateUserEmailRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[8] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserEmailRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserEmailRequest) ProtoMessage() {} + +func (x *UpdateUserEmailRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[8] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserEmailRequest.ProtoReflect.Descriptor instead. func (*UpdateUserEmailRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{8} + return file_auth_proto_rawDescGZIP(), []int{8} } -func (m *UpdateUserEmailRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UpdateUserEmailRequest.Unmarshal(m, b) -} -func (m *UpdateUserEmailRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UpdateUserEmailRequest.Marshal(b, m, deterministic) -} -func (m *UpdateUserEmailRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_UpdateUserEmailRequest.Merge(m, src) -} -func (m *UpdateUserEmailRequest) XXX_Size() int { - return xxx_messageInfo_UpdateUserEmailRequest.Size(m) -} -func (m *UpdateUserEmailRequest) XXX_DiscardUnknown() { - xxx_messageInfo_UpdateUserEmailRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_UpdateUserEmailRequest proto.InternalMessageInfo - -func (m *UpdateUserEmailRequest) GetEmail() string { - if m != nil { - return m.Email +func (x *UpdateUserEmailRequest) GetEmail() string { + if x != nil { + return x.Email } return "" } type UserPhone struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Phone string `protobuf:"bytes,2,opt,name=phone,proto3" json:"phone,omitempty"` - IsPhoneVerified bool `protobuf:"varint,3,opt,name=is_phone_verified,json=isPhoneVerified,proto3" json:"is_phone_verified,omitempty"` - Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` - CreationDate *timestamp.Timestamp `protobuf:"bytes,5,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` - ChangeDate *timestamp.Timestamp `protobuf:"bytes,6,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Phone string `protobuf:"bytes,2,opt,name=phone,proto3" json:"phone,omitempty"` + IsPhoneVerified bool `protobuf:"varint,3,opt,name=is_phone_verified,json=isPhoneVerified,proto3" json:"is_phone_verified,omitempty"` + Sequence uint64 `protobuf:"varint,4,opt,name=sequence,proto3" json:"sequence,omitempty"` + CreationDate *timestamp.Timestamp `protobuf:"bytes,5,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` + ChangeDate *timestamp.Timestamp `protobuf:"bytes,6,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` } -func (m *UserPhone) Reset() { *m = UserPhone{} } -func (m *UserPhone) String() string { return proto.CompactTextString(m) } -func (*UserPhone) ProtoMessage() {} +func (x *UserPhone) Reset() { + *x = UserPhone{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserPhone) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserPhone) ProtoMessage() {} + +func (x *UserPhone) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[9] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserPhone.ProtoReflect.Descriptor instead. func (*UserPhone) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{9} + return file_auth_proto_rawDescGZIP(), []int{9} } -func (m *UserPhone) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserPhone.Unmarshal(m, b) -} -func (m *UserPhone) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserPhone.Marshal(b, m, deterministic) -} -func (m *UserPhone) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserPhone.Merge(m, src) -} -func (m *UserPhone) XXX_Size() int { - return xxx_messageInfo_UserPhone.Size(m) -} -func (m *UserPhone) XXX_DiscardUnknown() { - xxx_messageInfo_UserPhone.DiscardUnknown(m) -} - -var xxx_messageInfo_UserPhone proto.InternalMessageInfo - -func (m *UserPhone) GetId() string { - if m != nil { - return m.Id +func (x *UserPhone) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *UserPhone) GetPhone() string { - if m != nil { - return m.Phone +func (x *UserPhone) GetPhone() string { + if x != nil { + return x.Phone } return "" } -func (m *UserPhone) GetIsPhoneVerified() bool { - if m != nil { - return m.IsPhoneVerified +func (x *UserPhone) GetIsPhoneVerified() bool { + if x != nil { + return x.IsPhoneVerified } return false } -func (m *UserPhone) GetSequence() uint64 { - if m != nil { - return m.Sequence +func (x *UserPhone) GetSequence() uint64 { + if x != nil { + return x.Sequence } return 0 } -func (m *UserPhone) GetCreationDate() *timestamp.Timestamp { - if m != nil { - return m.CreationDate +func (x *UserPhone) GetCreationDate() *timestamp.Timestamp { + if x != nil { + return x.CreationDate } return nil } -func (m *UserPhone) GetChangeDate() *timestamp.Timestamp { - if m != nil { - return m.ChangeDate +func (x *UserPhone) GetChangeDate() *timestamp.Timestamp { + if x != nil { + return x.ChangeDate } return nil } type UpdateUserPhoneRequest struct { - Phone string `protobuf:"bytes,1,opt,name=phone,proto3" json:"phone,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Phone string `protobuf:"bytes,1,opt,name=phone,proto3" json:"phone,omitempty"` } -func (m *UpdateUserPhoneRequest) Reset() { *m = UpdateUserPhoneRequest{} } -func (m *UpdateUserPhoneRequest) String() string { return proto.CompactTextString(m) } -func (*UpdateUserPhoneRequest) ProtoMessage() {} +func (x *UpdateUserPhoneRequest) Reset() { + *x = UpdateUserPhoneRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserPhoneRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserPhoneRequest) ProtoMessage() {} + +func (x *UpdateUserPhoneRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[10] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserPhoneRequest.ProtoReflect.Descriptor instead. func (*UpdateUserPhoneRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{10} + return file_auth_proto_rawDescGZIP(), []int{10} } -func (m *UpdateUserPhoneRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UpdateUserPhoneRequest.Unmarshal(m, b) -} -func (m *UpdateUserPhoneRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UpdateUserPhoneRequest.Marshal(b, m, deterministic) -} -func (m *UpdateUserPhoneRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_UpdateUserPhoneRequest.Merge(m, src) -} -func (m *UpdateUserPhoneRequest) XXX_Size() int { - return xxx_messageInfo_UpdateUserPhoneRequest.Size(m) -} -func (m *UpdateUserPhoneRequest) XXX_DiscardUnknown() { - xxx_messageInfo_UpdateUserPhoneRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_UpdateUserPhoneRequest proto.InternalMessageInfo - -func (m *UpdateUserPhoneRequest) GetPhone() string { - if m != nil { - return m.Phone +func (x *UpdateUserPhoneRequest) GetPhone() string { + if x != nil { + return x.Phone } return "" } type VerifyUserPhoneRequest struct { - Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` } -func (m *VerifyUserPhoneRequest) Reset() { *m = VerifyUserPhoneRequest{} } -func (m *VerifyUserPhoneRequest) String() string { return proto.CompactTextString(m) } -func (*VerifyUserPhoneRequest) ProtoMessage() {} +func (x *VerifyUserPhoneRequest) Reset() { + *x = VerifyUserPhoneRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[11] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyUserPhoneRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyUserPhoneRequest) ProtoMessage() {} + +func (x *VerifyUserPhoneRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[11] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyUserPhoneRequest.ProtoReflect.Descriptor instead. func (*VerifyUserPhoneRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{11} + return file_auth_proto_rawDescGZIP(), []int{11} } -func (m *VerifyUserPhoneRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_VerifyUserPhoneRequest.Unmarshal(m, b) -} -func (m *VerifyUserPhoneRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_VerifyUserPhoneRequest.Marshal(b, m, deterministic) -} -func (m *VerifyUserPhoneRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_VerifyUserPhoneRequest.Merge(m, src) -} -func (m *VerifyUserPhoneRequest) XXX_Size() int { - return xxx_messageInfo_VerifyUserPhoneRequest.Size(m) -} -func (m *VerifyUserPhoneRequest) XXX_DiscardUnknown() { - xxx_messageInfo_VerifyUserPhoneRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_VerifyUserPhoneRequest proto.InternalMessageInfo - -func (m *VerifyUserPhoneRequest) GetCode() string { - if m != nil { - return m.Code +func (x *VerifyUserPhoneRequest) GetCode() string { + if x != nil { + return x.Code } return "" } type UserAddress struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Country string `protobuf:"bytes,2,opt,name=country,proto3" json:"country,omitempty"` - Locality string `protobuf:"bytes,3,opt,name=locality,proto3" json:"locality,omitempty"` - PostalCode string `protobuf:"bytes,4,opt,name=postal_code,json=postalCode,proto3" json:"postal_code,omitempty"` - Region string `protobuf:"bytes,5,opt,name=region,proto3" json:"region,omitempty"` - StreetAddress string `protobuf:"bytes,6,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` - Sequence uint64 `protobuf:"varint,7,opt,name=sequence,proto3" json:"sequence,omitempty"` - CreationDate *timestamp.Timestamp `protobuf:"bytes,8,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` - ChangeDate *timestamp.Timestamp `protobuf:"bytes,9,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Country string `protobuf:"bytes,2,opt,name=country,proto3" json:"country,omitempty"` + Locality string `protobuf:"bytes,3,opt,name=locality,proto3" json:"locality,omitempty"` + PostalCode string `protobuf:"bytes,4,opt,name=postal_code,json=postalCode,proto3" json:"postal_code,omitempty"` + Region string `protobuf:"bytes,5,opt,name=region,proto3" json:"region,omitempty"` + StreetAddress string `protobuf:"bytes,6,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` + Sequence uint64 `protobuf:"varint,7,opt,name=sequence,proto3" json:"sequence,omitempty"` + CreationDate *timestamp.Timestamp `protobuf:"bytes,8,opt,name=creation_date,json=creationDate,proto3" json:"creation_date,omitempty"` + ChangeDate *timestamp.Timestamp `protobuf:"bytes,9,opt,name=change_date,json=changeDate,proto3" json:"change_date,omitempty"` } -func (m *UserAddress) Reset() { *m = UserAddress{} } -func (m *UserAddress) String() string { return proto.CompactTextString(m) } -func (*UserAddress) ProtoMessage() {} +func (x *UserAddress) Reset() { + *x = UserAddress{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[12] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserAddress) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserAddress) ProtoMessage() {} + +func (x *UserAddress) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[12] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserAddress.ProtoReflect.Descriptor instead. func (*UserAddress) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{12} + return file_auth_proto_rawDescGZIP(), []int{12} } -func (m *UserAddress) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UserAddress.Unmarshal(m, b) -} -func (m *UserAddress) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UserAddress.Marshal(b, m, deterministic) -} -func (m *UserAddress) XXX_Merge(src proto.Message) { - xxx_messageInfo_UserAddress.Merge(m, src) -} -func (m *UserAddress) XXX_Size() int { - return xxx_messageInfo_UserAddress.Size(m) -} -func (m *UserAddress) XXX_DiscardUnknown() { - xxx_messageInfo_UserAddress.DiscardUnknown(m) -} - -var xxx_messageInfo_UserAddress proto.InternalMessageInfo - -func (m *UserAddress) GetId() string { - if m != nil { - return m.Id +func (x *UserAddress) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *UserAddress) GetCountry() string { - if m != nil { - return m.Country +func (x *UserAddress) GetCountry() string { + if x != nil { + return x.Country } return "" } -func (m *UserAddress) GetLocality() string { - if m != nil { - return m.Locality +func (x *UserAddress) GetLocality() string { + if x != nil { + return x.Locality } return "" } -func (m *UserAddress) GetPostalCode() string { - if m != nil { - return m.PostalCode +func (x *UserAddress) GetPostalCode() string { + if x != nil { + return x.PostalCode } return "" } -func (m *UserAddress) GetRegion() string { - if m != nil { - return m.Region +func (x *UserAddress) GetRegion() string { + if x != nil { + return x.Region } return "" } -func (m *UserAddress) GetStreetAddress() string { - if m != nil { - return m.StreetAddress +func (x *UserAddress) GetStreetAddress() string { + if x != nil { + return x.StreetAddress } return "" } -func (m *UserAddress) GetSequence() uint64 { - if m != nil { - return m.Sequence +func (x *UserAddress) GetSequence() uint64 { + if x != nil { + return x.Sequence } return 0 } -func (m *UserAddress) GetCreationDate() *timestamp.Timestamp { - if m != nil { - return m.CreationDate +func (x *UserAddress) GetCreationDate() *timestamp.Timestamp { + if x != nil { + return x.CreationDate } return nil } -func (m *UserAddress) GetChangeDate() *timestamp.Timestamp { - if m != nil { - return m.ChangeDate +func (x *UserAddress) GetChangeDate() *timestamp.Timestamp { + if x != nil { + return x.ChangeDate } return nil } type UpdateUserAddressRequest struct { - Country string `protobuf:"bytes,1,opt,name=country,proto3" json:"country,omitempty"` - Locality string `protobuf:"bytes,2,opt,name=locality,proto3" json:"locality,omitempty"` - PostalCode string `protobuf:"bytes,3,opt,name=postal_code,json=postalCode,proto3" json:"postal_code,omitempty"` - Region string `protobuf:"bytes,4,opt,name=region,proto3" json:"region,omitempty"` - StreetAddress string `protobuf:"bytes,5,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Country string `protobuf:"bytes,1,opt,name=country,proto3" json:"country,omitempty"` + Locality string `protobuf:"bytes,2,opt,name=locality,proto3" json:"locality,omitempty"` + PostalCode string `protobuf:"bytes,3,opt,name=postal_code,json=postalCode,proto3" json:"postal_code,omitempty"` + Region string `protobuf:"bytes,4,opt,name=region,proto3" json:"region,omitempty"` + StreetAddress string `protobuf:"bytes,5,opt,name=street_address,json=streetAddress,proto3" json:"street_address,omitempty"` } -func (m *UpdateUserAddressRequest) Reset() { *m = UpdateUserAddressRequest{} } -func (m *UpdateUserAddressRequest) String() string { return proto.CompactTextString(m) } -func (*UpdateUserAddressRequest) ProtoMessage() {} +func (x *UpdateUserAddressRequest) Reset() { + *x = UpdateUserAddressRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[13] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UpdateUserAddressRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UpdateUserAddressRequest) ProtoMessage() {} + +func (x *UpdateUserAddressRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[13] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UpdateUserAddressRequest.ProtoReflect.Descriptor instead. func (*UpdateUserAddressRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{13} + return file_auth_proto_rawDescGZIP(), []int{13} } -func (m *UpdateUserAddressRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_UpdateUserAddressRequest.Unmarshal(m, b) -} -func (m *UpdateUserAddressRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_UpdateUserAddressRequest.Marshal(b, m, deterministic) -} -func (m *UpdateUserAddressRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_UpdateUserAddressRequest.Merge(m, src) -} -func (m *UpdateUserAddressRequest) XXX_Size() int { - return xxx_messageInfo_UpdateUserAddressRequest.Size(m) -} -func (m *UpdateUserAddressRequest) XXX_DiscardUnknown() { - xxx_messageInfo_UpdateUserAddressRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_UpdateUserAddressRequest proto.InternalMessageInfo - -func (m *UpdateUserAddressRequest) GetCountry() string { - if m != nil { - return m.Country +func (x *UpdateUserAddressRequest) GetCountry() string { + if x != nil { + return x.Country } return "" } -func (m *UpdateUserAddressRequest) GetLocality() string { - if m != nil { - return m.Locality +func (x *UpdateUserAddressRequest) GetLocality() string { + if x != nil { + return x.Locality } return "" } -func (m *UpdateUserAddressRequest) GetPostalCode() string { - if m != nil { - return m.PostalCode +func (x *UpdateUserAddressRequest) GetPostalCode() string { + if x != nil { + return x.PostalCode } return "" } -func (m *UpdateUserAddressRequest) GetRegion() string { - if m != nil { - return m.Region +func (x *UpdateUserAddressRequest) GetRegion() string { + if x != nil { + return x.Region } return "" } -func (m *UpdateUserAddressRequest) GetStreetAddress() string { - if m != nil { - return m.StreetAddress +func (x *UpdateUserAddressRequest) GetStreetAddress() string { + if x != nil { + return x.StreetAddress } return "" } type PasswordID struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` } -func (m *PasswordID) Reset() { *m = PasswordID{} } -func (m *PasswordID) String() string { return proto.CompactTextString(m) } -func (*PasswordID) ProtoMessage() {} +func (x *PasswordID) Reset() { + *x = PasswordID{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PasswordID) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PasswordID) ProtoMessage() {} + +func (x *PasswordID) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[14] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PasswordID.ProtoReflect.Descriptor instead. func (*PasswordID) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{14} + return file_auth_proto_rawDescGZIP(), []int{14} } -func (m *PasswordID) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PasswordID.Unmarshal(m, b) -} -func (m *PasswordID) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PasswordID.Marshal(b, m, deterministic) -} -func (m *PasswordID) XXX_Merge(src proto.Message) { - xxx_messageInfo_PasswordID.Merge(m, src) -} -func (m *PasswordID) XXX_Size() int { - return xxx_messageInfo_PasswordID.Size(m) -} -func (m *PasswordID) XXX_DiscardUnknown() { - xxx_messageInfo_PasswordID.DiscardUnknown(m) -} - -var xxx_messageInfo_PasswordID proto.InternalMessageInfo - -func (m *PasswordID) GetId() string { - if m != nil { - return m.Id +func (x *PasswordID) GetId() string { + if x != nil { + return x.Id } return "" } type PasswordRequest struct { - Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Password string `protobuf:"bytes,1,opt,name=password,proto3" json:"password,omitempty"` } -func (m *PasswordRequest) Reset() { *m = PasswordRequest{} } -func (m *PasswordRequest) String() string { return proto.CompactTextString(m) } -func (*PasswordRequest) ProtoMessage() {} +func (x *PasswordRequest) Reset() { + *x = PasswordRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PasswordRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PasswordRequest) ProtoMessage() {} + +func (x *PasswordRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[15] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PasswordRequest.ProtoReflect.Descriptor instead. func (*PasswordRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{15} + return file_auth_proto_rawDescGZIP(), []int{15} } -func (m *PasswordRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PasswordRequest.Unmarshal(m, b) -} -func (m *PasswordRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PasswordRequest.Marshal(b, m, deterministic) -} -func (m *PasswordRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_PasswordRequest.Merge(m, src) -} -func (m *PasswordRequest) XXX_Size() int { - return xxx_messageInfo_PasswordRequest.Size(m) -} -func (m *PasswordRequest) XXX_DiscardUnknown() { - xxx_messageInfo_PasswordRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_PasswordRequest proto.InternalMessageInfo - -func (m *PasswordRequest) GetPassword() string { - if m != nil { - return m.Password +func (x *PasswordRequest) GetPassword() string { + if x != nil { + return x.Password } return "" } type PasswordChange struct { - OldPassword string `protobuf:"bytes,1,opt,name=old_password,json=oldPassword,proto3" json:"old_password,omitempty"` - NewPassword string `protobuf:"bytes,2,opt,name=new_password,json=newPassword,proto3" json:"new_password,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OldPassword string `protobuf:"bytes,1,opt,name=old_password,json=oldPassword,proto3" json:"old_password,omitempty"` + NewPassword string `protobuf:"bytes,2,opt,name=new_password,json=newPassword,proto3" json:"new_password,omitempty"` } -func (m *PasswordChange) Reset() { *m = PasswordChange{} } -func (m *PasswordChange) String() string { return proto.CompactTextString(m) } -func (*PasswordChange) ProtoMessage() {} +func (x *PasswordChange) Reset() { + *x = PasswordChange{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PasswordChange) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PasswordChange) ProtoMessage() {} + +func (x *PasswordChange) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[16] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use PasswordChange.ProtoReflect.Descriptor instead. func (*PasswordChange) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{16} + return file_auth_proto_rawDescGZIP(), []int{16} } -func (m *PasswordChange) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_PasswordChange.Unmarshal(m, b) -} -func (m *PasswordChange) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_PasswordChange.Marshal(b, m, deterministic) -} -func (m *PasswordChange) XXX_Merge(src proto.Message) { - xxx_messageInfo_PasswordChange.Merge(m, src) -} -func (m *PasswordChange) XXX_Size() int { - return xxx_messageInfo_PasswordChange.Size(m) -} -func (m *PasswordChange) XXX_DiscardUnknown() { - xxx_messageInfo_PasswordChange.DiscardUnknown(m) -} - -var xxx_messageInfo_PasswordChange proto.InternalMessageInfo - -func (m *PasswordChange) GetOldPassword() string { - if m != nil { - return m.OldPassword +func (x *PasswordChange) GetOldPassword() string { + if x != nil { + return x.OldPassword } return "" } -func (m *PasswordChange) GetNewPassword() string { - if m != nil { - return m.NewPassword +func (x *PasswordChange) GetNewPassword() string { + if x != nil { + return x.NewPassword } return "" } type VerifyMfaOtp struct { - Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Code string `protobuf:"bytes,1,opt,name=code,proto3" json:"code,omitempty"` } -func (m *VerifyMfaOtp) Reset() { *m = VerifyMfaOtp{} } -func (m *VerifyMfaOtp) String() string { return proto.CompactTextString(m) } -func (*VerifyMfaOtp) ProtoMessage() {} +func (x *VerifyMfaOtp) Reset() { + *x = VerifyMfaOtp{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *VerifyMfaOtp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*VerifyMfaOtp) ProtoMessage() {} + +func (x *VerifyMfaOtp) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[17] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use VerifyMfaOtp.ProtoReflect.Descriptor instead. func (*VerifyMfaOtp) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{17} + return file_auth_proto_rawDescGZIP(), []int{17} } -func (m *VerifyMfaOtp) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_VerifyMfaOtp.Unmarshal(m, b) -} -func (m *VerifyMfaOtp) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_VerifyMfaOtp.Marshal(b, m, deterministic) -} -func (m *VerifyMfaOtp) XXX_Merge(src proto.Message) { - xxx_messageInfo_VerifyMfaOtp.Merge(m, src) -} -func (m *VerifyMfaOtp) XXX_Size() int { - return xxx_messageInfo_VerifyMfaOtp.Size(m) -} -func (m *VerifyMfaOtp) XXX_DiscardUnknown() { - xxx_messageInfo_VerifyMfaOtp.DiscardUnknown(m) -} - -var xxx_messageInfo_VerifyMfaOtp proto.InternalMessageInfo - -func (m *VerifyMfaOtp) GetCode() string { - if m != nil { - return m.Code +func (x *VerifyMfaOtp) GetCode() string { + if x != nil { + return x.Code } return "" } type MultiFactors struct { - Mfas []*MultiFactor `protobuf:"bytes,1,rep,name=mfas,proto3" json:"mfas,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Mfas []*MultiFactor `protobuf:"bytes,1,rep,name=mfas,proto3" json:"mfas,omitempty"` } -func (m *MultiFactors) Reset() { *m = MultiFactors{} } -func (m *MultiFactors) String() string { return proto.CompactTextString(m) } -func (*MultiFactors) ProtoMessage() {} +func (x *MultiFactors) Reset() { + *x = MultiFactors{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MultiFactors) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MultiFactors) ProtoMessage() {} + +func (x *MultiFactors) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[18] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MultiFactors.ProtoReflect.Descriptor instead. func (*MultiFactors) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{18} + return file_auth_proto_rawDescGZIP(), []int{18} } -func (m *MultiFactors) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MultiFactors.Unmarshal(m, b) -} -func (m *MultiFactors) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MultiFactors.Marshal(b, m, deterministic) -} -func (m *MultiFactors) XXX_Merge(src proto.Message) { - xxx_messageInfo_MultiFactors.Merge(m, src) -} -func (m *MultiFactors) XXX_Size() int { - return xxx_messageInfo_MultiFactors.Size(m) -} -func (m *MultiFactors) XXX_DiscardUnknown() { - xxx_messageInfo_MultiFactors.DiscardUnknown(m) -} - -var xxx_messageInfo_MultiFactors proto.InternalMessageInfo - -func (m *MultiFactors) GetMfas() []*MultiFactor { - if m != nil { - return m.Mfas +func (x *MultiFactors) GetMfas() []*MultiFactor { + if x != nil { + return x.Mfas } return nil } type MultiFactor struct { - Type MfaType `protobuf:"varint,1,opt,name=type,proto3,enum=zitadel.auth.api.v1.MfaType" json:"type,omitempty"` - State MFAState `protobuf:"varint,2,opt,name=state,proto3,enum=zitadel.auth.api.v1.MFAState" json:"state,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Type MfaType `protobuf:"varint,1,opt,name=type,proto3,enum=zitadel.auth.api.v1.MfaType" json:"type,omitempty"` + State MFAState `protobuf:"varint,2,opt,name=state,proto3,enum=zitadel.auth.api.v1.MFAState" json:"state,omitempty"` } -func (m *MultiFactor) Reset() { *m = MultiFactor{} } -func (m *MultiFactor) String() string { return proto.CompactTextString(m) } -func (*MultiFactor) ProtoMessage() {} +func (x *MultiFactor) Reset() { + *x = MultiFactor{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MultiFactor) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MultiFactor) ProtoMessage() {} + +func (x *MultiFactor) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[19] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MultiFactor.ProtoReflect.Descriptor instead. func (*MultiFactor) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{19} + return file_auth_proto_rawDescGZIP(), []int{19} } -func (m *MultiFactor) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MultiFactor.Unmarshal(m, b) -} -func (m *MultiFactor) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MultiFactor.Marshal(b, m, deterministic) -} -func (m *MultiFactor) XXX_Merge(src proto.Message) { - xxx_messageInfo_MultiFactor.Merge(m, src) -} -func (m *MultiFactor) XXX_Size() int { - return xxx_messageInfo_MultiFactor.Size(m) -} -func (m *MultiFactor) XXX_DiscardUnknown() { - xxx_messageInfo_MultiFactor.DiscardUnknown(m) -} - -var xxx_messageInfo_MultiFactor proto.InternalMessageInfo - -func (m *MultiFactor) GetType() MfaType { - if m != nil { - return m.Type +func (x *MultiFactor) GetType() MfaType { + if x != nil { + return x.Type } return MfaType_MFATYPE_UNSPECIFIED } -func (m *MultiFactor) GetState() MFAState { - if m != nil { - return m.State +func (x *MultiFactor) GetState() MFAState { + if x != nil { + return x.State } return MFAState_MFASTATE_UNSPECIFIED } type MfaOtpResponse struct { - UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` - Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` - Secret string `protobuf:"bytes,3,opt,name=secret,proto3" json:"secret,omitempty"` - State MFAState `protobuf:"varint,4,opt,name=state,proto3,enum=zitadel.auth.api.v1.MFAState" json:"state,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + UserId string `protobuf:"bytes,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` + Url string `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"` + Secret string `protobuf:"bytes,3,opt,name=secret,proto3" json:"secret,omitempty"` + State MFAState `protobuf:"varint,4,opt,name=state,proto3,enum=zitadel.auth.api.v1.MFAState" json:"state,omitempty"` } -func (m *MfaOtpResponse) Reset() { *m = MfaOtpResponse{} } -func (m *MfaOtpResponse) String() string { return proto.CompactTextString(m) } -func (*MfaOtpResponse) ProtoMessage() {} +func (x *MfaOtpResponse) Reset() { + *x = MfaOtpResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MfaOtpResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MfaOtpResponse) ProtoMessage() {} + +func (x *MfaOtpResponse) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[20] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MfaOtpResponse.ProtoReflect.Descriptor instead. func (*MfaOtpResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{20} + return file_auth_proto_rawDescGZIP(), []int{20} } -func (m *MfaOtpResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MfaOtpResponse.Unmarshal(m, b) -} -func (m *MfaOtpResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MfaOtpResponse.Marshal(b, m, deterministic) -} -func (m *MfaOtpResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MfaOtpResponse.Merge(m, src) -} -func (m *MfaOtpResponse) XXX_Size() int { - return xxx_messageInfo_MfaOtpResponse.Size(m) -} -func (m *MfaOtpResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MfaOtpResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MfaOtpResponse proto.InternalMessageInfo - -func (m *MfaOtpResponse) GetUserId() string { - if m != nil { - return m.UserId +func (x *MfaOtpResponse) GetUserId() string { + if x != nil { + return x.UserId } return "" } -func (m *MfaOtpResponse) GetUrl() string { - if m != nil { - return m.Url +func (x *MfaOtpResponse) GetUrl() string { + if x != nil { + return x.Url } return "" } -func (m *MfaOtpResponse) GetSecret() string { - if m != nil { - return m.Secret +func (x *MfaOtpResponse) GetSecret() string { + if x != nil { + return x.Secret } return "" } -func (m *MfaOtpResponse) GetState() MFAState { - if m != nil { - return m.State +func (x *MfaOtpResponse) GetState() MFAState { + if x != nil { + return x.State } return MFAState_MFASTATE_UNSPECIFIED } type OIDCClientAuth struct { - ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` - ClientSecret string `protobuf:"bytes,2,opt,name=client_secret,json=clientSecret,proto3" json:"client_secret,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ClientId string `protobuf:"bytes,1,opt,name=client_id,json=clientId,proto3" json:"client_id,omitempty"` + ClientSecret string `protobuf:"bytes,2,opt,name=client_secret,json=clientSecret,proto3" json:"client_secret,omitempty"` } -func (m *OIDCClientAuth) Reset() { *m = OIDCClientAuth{} } -func (m *OIDCClientAuth) String() string { return proto.CompactTextString(m) } -func (*OIDCClientAuth) ProtoMessage() {} +func (x *OIDCClientAuth) Reset() { + *x = OIDCClientAuth{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *OIDCClientAuth) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*OIDCClientAuth) ProtoMessage() {} + +func (x *OIDCClientAuth) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[21] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use OIDCClientAuth.ProtoReflect.Descriptor instead. func (*OIDCClientAuth) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{21} + return file_auth_proto_rawDescGZIP(), []int{21} } -func (m *OIDCClientAuth) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_OIDCClientAuth.Unmarshal(m, b) -} -func (m *OIDCClientAuth) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_OIDCClientAuth.Marshal(b, m, deterministic) -} -func (m *OIDCClientAuth) XXX_Merge(src proto.Message) { - xxx_messageInfo_OIDCClientAuth.Merge(m, src) -} -func (m *OIDCClientAuth) XXX_Size() int { - return xxx_messageInfo_OIDCClientAuth.Size(m) -} -func (m *OIDCClientAuth) XXX_DiscardUnknown() { - xxx_messageInfo_OIDCClientAuth.DiscardUnknown(m) -} - -var xxx_messageInfo_OIDCClientAuth proto.InternalMessageInfo - -func (m *OIDCClientAuth) GetClientId() string { - if m != nil { - return m.ClientId +func (x *OIDCClientAuth) GetClientId() string { + if x != nil { + return x.ClientId } return "" } -func (m *OIDCClientAuth) GetClientSecret() string { - if m != nil { - return m.ClientSecret +func (x *OIDCClientAuth) GetClientSecret() string { + if x != nil { + return x.ClientSecret + } + return "" +} + +type UserGrantSearchRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Offset uint64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + SortingColumn UserGrantSearchKey `protobuf:"varint,3,opt,name=sorting_column,json=sortingColumn,proto3,enum=zitadel.auth.api.v1.UserGrantSearchKey" json:"sorting_column,omitempty"` + Asc bool `protobuf:"varint,4,opt,name=asc,proto3" json:"asc,omitempty"` + Queries []*UserGrantSearchQuery `protobuf:"bytes,5,rep,name=queries,proto3" json:"queries,omitempty"` +} + +func (x *UserGrantSearchRequest) Reset() { + *x = UserGrantSearchRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserGrantSearchRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserGrantSearchRequest) ProtoMessage() {} + +func (x *UserGrantSearchRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[22] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserGrantSearchRequest.ProtoReflect.Descriptor instead. +func (*UserGrantSearchRequest) Descriptor() ([]byte, []int) { + return file_auth_proto_rawDescGZIP(), []int{22} +} + +func (x *UserGrantSearchRequest) GetOffset() uint64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *UserGrantSearchRequest) GetLimit() uint64 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *UserGrantSearchRequest) GetSortingColumn() UserGrantSearchKey { + if x != nil { + return x.SortingColumn + } + return UserGrantSearchKey_UserGrantSearchKey_UNKNOWN +} + +func (x *UserGrantSearchRequest) GetAsc() bool { + if x != nil { + return x.Asc + } + return false +} + +func (x *UserGrantSearchRequest) GetQueries() []*UserGrantSearchQuery { + if x != nil { + return x.Queries + } + return nil +} + +type UserGrantSearchQuery struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key UserGrantSearchKey `protobuf:"varint,1,opt,name=key,proto3,enum=zitadel.auth.api.v1.UserGrantSearchKey" json:"key,omitempty"` + Method SearchMethod `protobuf:"varint,2,opt,name=method,proto3,enum=zitadel.auth.api.v1.SearchMethod" json:"method,omitempty"` + Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *UserGrantSearchQuery) Reset() { + *x = UserGrantSearchQuery{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserGrantSearchQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserGrantSearchQuery) ProtoMessage() {} + +func (x *UserGrantSearchQuery) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[23] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserGrantSearchQuery.ProtoReflect.Descriptor instead. +func (*UserGrantSearchQuery) Descriptor() ([]byte, []int) { + return file_auth_proto_rawDescGZIP(), []int{23} +} + +func (x *UserGrantSearchQuery) GetKey() UserGrantSearchKey { + if x != nil { + return x.Key + } + return UserGrantSearchKey_UserGrantSearchKey_UNKNOWN +} + +func (x *UserGrantSearchQuery) GetMethod() SearchMethod { + if x != nil { + return x.Method + } + return SearchMethod_SEARCHMETHOD_EQUALS +} + +func (x *UserGrantSearchQuery) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +type UserGrantSearchResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Offset uint64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + TotalResult uint64 `protobuf:"varint,3,opt,name=total_result,json=totalResult,proto3" json:"total_result,omitempty"` + Result []*UserGrantView `protobuf:"bytes,4,rep,name=result,proto3" json:"result,omitempty"` +} + +func (x *UserGrantSearchResponse) Reset() { + *x = UserGrantSearchResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[24] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserGrantSearchResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserGrantSearchResponse) ProtoMessage() {} + +func (x *UserGrantSearchResponse) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[24] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserGrantSearchResponse.ProtoReflect.Descriptor instead. +func (*UserGrantSearchResponse) Descriptor() ([]byte, []int) { + return file_auth_proto_rawDescGZIP(), []int{24} +} + +func (x *UserGrantSearchResponse) GetOffset() uint64 { + if x != nil { + return x.Offset + } + return 0 +} + +func (x *UserGrantSearchResponse) GetLimit() uint64 { + if x != nil { + return x.Limit + } + return 0 +} + +func (x *UserGrantSearchResponse) GetTotalResult() uint64 { + if x != nil { + return x.TotalResult + } + return 0 +} + +func (x *UserGrantSearchResponse) GetResult() []*UserGrantView { + if x != nil { + return x.Result + } + return nil +} + +type UserGrantView struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OrgId string `protobuf:"bytes,1,opt,name=OrgId,proto3" json:"OrgId,omitempty"` + ProjectId string `protobuf:"bytes,2,opt,name=ProjectId,proto3" json:"ProjectId,omitempty"` + UserId string `protobuf:"bytes,3,opt,name=UserId,proto3" json:"UserId,omitempty"` + Roles []string `protobuf:"bytes,4,rep,name=Roles,proto3" json:"Roles,omitempty"` + OrgName string `protobuf:"bytes,5,opt,name=OrgName,proto3" json:"OrgName,omitempty"` +} + +func (x *UserGrantView) Reset() { + *x = UserGrantView{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[25] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *UserGrantView) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*UserGrantView) ProtoMessage() {} + +func (x *UserGrantView) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[25] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use UserGrantView.ProtoReflect.Descriptor instead. +func (*UserGrantView) Descriptor() ([]byte, []int) { + return file_auth_proto_rawDescGZIP(), []int{25} +} + +func (x *UserGrantView) GetOrgId() string { + if x != nil { + return x.OrgId + } + return "" +} + +func (x *UserGrantView) GetProjectId() string { + if x != nil { + return x.ProjectId + } + return "" +} + +func (x *UserGrantView) GetUserId() string { + if x != nil { + return x.UserId + } + return "" +} + +func (x *UserGrantView) GetRoles() []string { + if x != nil { + return x.Roles + } + return nil +} + +func (x *UserGrantView) GetOrgName() string { + if x != nil { + return x.OrgName } return "" } type MyProjectOrgSearchRequest struct { - Offset uint64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` - Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` - Asc bool `protobuf:"varint,4,opt,name=asc,proto3" json:"asc,omitempty"` - Queries []*MyProjectOrgSearchQuery `protobuf:"bytes,5,rep,name=queries,proto3" json:"queries,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Offset uint64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + Asc bool `protobuf:"varint,4,opt,name=asc,proto3" json:"asc,omitempty"` + Queries []*MyProjectOrgSearchQuery `protobuf:"bytes,5,rep,name=queries,proto3" json:"queries,omitempty"` } -func (m *MyProjectOrgSearchRequest) Reset() { *m = MyProjectOrgSearchRequest{} } -func (m *MyProjectOrgSearchRequest) String() string { return proto.CompactTextString(m) } -func (*MyProjectOrgSearchRequest) ProtoMessage() {} +func (x *MyProjectOrgSearchRequest) Reset() { + *x = MyProjectOrgSearchRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[26] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MyProjectOrgSearchRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MyProjectOrgSearchRequest) ProtoMessage() {} + +func (x *MyProjectOrgSearchRequest) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[26] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MyProjectOrgSearchRequest.ProtoReflect.Descriptor instead. func (*MyProjectOrgSearchRequest) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{22} + return file_auth_proto_rawDescGZIP(), []int{26} } -func (m *MyProjectOrgSearchRequest) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MyProjectOrgSearchRequest.Unmarshal(m, b) -} -func (m *MyProjectOrgSearchRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MyProjectOrgSearchRequest.Marshal(b, m, deterministic) -} -func (m *MyProjectOrgSearchRequest) XXX_Merge(src proto.Message) { - xxx_messageInfo_MyProjectOrgSearchRequest.Merge(m, src) -} -func (m *MyProjectOrgSearchRequest) XXX_Size() int { - return xxx_messageInfo_MyProjectOrgSearchRequest.Size(m) -} -func (m *MyProjectOrgSearchRequest) XXX_DiscardUnknown() { - xxx_messageInfo_MyProjectOrgSearchRequest.DiscardUnknown(m) -} - -var xxx_messageInfo_MyProjectOrgSearchRequest proto.InternalMessageInfo - -func (m *MyProjectOrgSearchRequest) GetOffset() uint64 { - if m != nil { - return m.Offset +func (x *MyProjectOrgSearchRequest) GetOffset() uint64 { + if x != nil { + return x.Offset } return 0 } -func (m *MyProjectOrgSearchRequest) GetLimit() uint64 { - if m != nil { - return m.Limit +func (x *MyProjectOrgSearchRequest) GetLimit() uint64 { + if x != nil { + return x.Limit } return 0 } -func (m *MyProjectOrgSearchRequest) GetAsc() bool { - if m != nil { - return m.Asc +func (x *MyProjectOrgSearchRequest) GetAsc() bool { + if x != nil { + return x.Asc } return false } -func (m *MyProjectOrgSearchRequest) GetQueries() []*MyProjectOrgSearchQuery { - if m != nil { - return m.Queries +func (x *MyProjectOrgSearchRequest) GetQueries() []*MyProjectOrgSearchQuery { + if x != nil { + return x.Queries } return nil } type MyProjectOrgSearchQuery struct { - Key MyProjectOrgSearchKey `protobuf:"varint,1,opt,name=key,proto3,enum=zitadel.auth.api.v1.MyProjectOrgSearchKey" json:"key,omitempty"` - Method SearchMethod `protobuf:"varint,2,opt,name=method,proto3,enum=zitadel.auth.api.v1.SearchMethod" json:"method,omitempty"` - Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key MyProjectOrgSearchKey `protobuf:"varint,1,opt,name=key,proto3,enum=zitadel.auth.api.v1.MyProjectOrgSearchKey" json:"key,omitempty"` + Method SearchMethod `protobuf:"varint,2,opt,name=method,proto3,enum=zitadel.auth.api.v1.SearchMethod" json:"method,omitempty"` + Value string `protobuf:"bytes,3,opt,name=value,proto3" json:"value,omitempty"` } -func (m *MyProjectOrgSearchQuery) Reset() { *m = MyProjectOrgSearchQuery{} } -func (m *MyProjectOrgSearchQuery) String() string { return proto.CompactTextString(m) } -func (*MyProjectOrgSearchQuery) ProtoMessage() {} +func (x *MyProjectOrgSearchQuery) Reset() { + *x = MyProjectOrgSearchQuery{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[27] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MyProjectOrgSearchQuery) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MyProjectOrgSearchQuery) ProtoMessage() {} + +func (x *MyProjectOrgSearchQuery) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[27] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MyProjectOrgSearchQuery.ProtoReflect.Descriptor instead. func (*MyProjectOrgSearchQuery) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{23} + return file_auth_proto_rawDescGZIP(), []int{27} } -func (m *MyProjectOrgSearchQuery) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MyProjectOrgSearchQuery.Unmarshal(m, b) -} -func (m *MyProjectOrgSearchQuery) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MyProjectOrgSearchQuery.Marshal(b, m, deterministic) -} -func (m *MyProjectOrgSearchQuery) XXX_Merge(src proto.Message) { - xxx_messageInfo_MyProjectOrgSearchQuery.Merge(m, src) -} -func (m *MyProjectOrgSearchQuery) XXX_Size() int { - return xxx_messageInfo_MyProjectOrgSearchQuery.Size(m) -} -func (m *MyProjectOrgSearchQuery) XXX_DiscardUnknown() { - xxx_messageInfo_MyProjectOrgSearchQuery.DiscardUnknown(m) -} - -var xxx_messageInfo_MyProjectOrgSearchQuery proto.InternalMessageInfo - -func (m *MyProjectOrgSearchQuery) GetKey() MyProjectOrgSearchKey { - if m != nil { - return m.Key +func (x *MyProjectOrgSearchQuery) GetKey() MyProjectOrgSearchKey { + if x != nil { + return x.Key } return MyProjectOrgSearchKey_MYPROJECTORGSEARCHKEY_UNSPECIFIED } -func (m *MyProjectOrgSearchQuery) GetMethod() SearchMethod { - if m != nil { - return m.Method +func (x *MyProjectOrgSearchQuery) GetMethod() SearchMethod { + if x != nil { + return x.Method } return SearchMethod_SEARCHMETHOD_EQUALS } -func (m *MyProjectOrgSearchQuery) GetValue() string { - if m != nil { - return m.Value +func (x *MyProjectOrgSearchQuery) GetValue() string { + if x != nil { + return x.Value } return "" } type MyProjectOrgSearchResponse struct { - Offset uint64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` - Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` - TotalResult uint64 `protobuf:"varint,3,opt,name=total_result,json=totalResult,proto3" json:"total_result,omitempty"` - Result []*Org `protobuf:"bytes,4,rep,name=result,proto3" json:"result,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Offset uint64 `protobuf:"varint,1,opt,name=offset,proto3" json:"offset,omitempty"` + Limit uint64 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"` + TotalResult uint64 `protobuf:"varint,3,opt,name=total_result,json=totalResult,proto3" json:"total_result,omitempty"` + Result []*Org `protobuf:"bytes,4,rep,name=result,proto3" json:"result,omitempty"` } -func (m *MyProjectOrgSearchResponse) Reset() { *m = MyProjectOrgSearchResponse{} } -func (m *MyProjectOrgSearchResponse) String() string { return proto.CompactTextString(m) } -func (*MyProjectOrgSearchResponse) ProtoMessage() {} +func (x *MyProjectOrgSearchResponse) Reset() { + *x = MyProjectOrgSearchResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[28] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MyProjectOrgSearchResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MyProjectOrgSearchResponse) ProtoMessage() {} + +func (x *MyProjectOrgSearchResponse) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[28] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MyProjectOrgSearchResponse.ProtoReflect.Descriptor instead. func (*MyProjectOrgSearchResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{24} + return file_auth_proto_rawDescGZIP(), []int{28} } -func (m *MyProjectOrgSearchResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MyProjectOrgSearchResponse.Unmarshal(m, b) -} -func (m *MyProjectOrgSearchResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MyProjectOrgSearchResponse.Marshal(b, m, deterministic) -} -func (m *MyProjectOrgSearchResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_MyProjectOrgSearchResponse.Merge(m, src) -} -func (m *MyProjectOrgSearchResponse) XXX_Size() int { - return xxx_messageInfo_MyProjectOrgSearchResponse.Size(m) -} -func (m *MyProjectOrgSearchResponse) XXX_DiscardUnknown() { - xxx_messageInfo_MyProjectOrgSearchResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_MyProjectOrgSearchResponse proto.InternalMessageInfo - -func (m *MyProjectOrgSearchResponse) GetOffset() uint64 { - if m != nil { - return m.Offset +func (x *MyProjectOrgSearchResponse) GetOffset() uint64 { + if x != nil { + return x.Offset } return 0 } -func (m *MyProjectOrgSearchResponse) GetLimit() uint64 { - if m != nil { - return m.Limit +func (x *MyProjectOrgSearchResponse) GetLimit() uint64 { + if x != nil { + return x.Limit } return 0 } -func (m *MyProjectOrgSearchResponse) GetTotalResult() uint64 { - if m != nil { - return m.TotalResult +func (x *MyProjectOrgSearchResponse) GetTotalResult() uint64 { + if x != nil { + return x.TotalResult } return 0 } -func (m *MyProjectOrgSearchResponse) GetResult() []*Org { - if m != nil { - return m.Result +func (x *MyProjectOrgSearchResponse) GetResult() []*Org { + if x != nil { + return x.Result } return nil } -type IsAdminResponse struct { - IsAdmin bool `protobuf:"varint,1,opt,name=is_admin,json=isAdmin,proto3" json:"is_admin,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` -} - -func (m *IsAdminResponse) Reset() { *m = IsAdminResponse{} } -func (m *IsAdminResponse) String() string { return proto.CompactTextString(m) } -func (*IsAdminResponse) ProtoMessage() {} -func (*IsAdminResponse) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{25} -} - -func (m *IsAdminResponse) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_IsAdminResponse.Unmarshal(m, b) -} -func (m *IsAdminResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_IsAdminResponse.Marshal(b, m, deterministic) -} -func (m *IsAdminResponse) XXX_Merge(src proto.Message) { - xxx_messageInfo_IsAdminResponse.Merge(m, src) -} -func (m *IsAdminResponse) XXX_Size() int { - return xxx_messageInfo_IsAdminResponse.Size(m) -} -func (m *IsAdminResponse) XXX_DiscardUnknown() { - xxx_messageInfo_IsAdminResponse.DiscardUnknown(m) -} - -var xxx_messageInfo_IsAdminResponse proto.InternalMessageInfo - -func (m *IsAdminResponse) GetIsAdmin() bool { - if m != nil { - return m.IsAdmin - } - return false -} - type Org struct { - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` } -func (m *Org) Reset() { *m = Org{} } -func (m *Org) String() string { return proto.CompactTextString(m) } -func (*Org) ProtoMessage() {} +func (x *Org) Reset() { + *x = Org{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[29] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Org) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Org) ProtoMessage() {} + +func (x *Org) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[29] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Org.ProtoReflect.Descriptor instead. func (*Org) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{26} + return file_auth_proto_rawDescGZIP(), []int{29} } -func (m *Org) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_Org.Unmarshal(m, b) -} -func (m *Org) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_Org.Marshal(b, m, deterministic) -} -func (m *Org) XXX_Merge(src proto.Message) { - xxx_messageInfo_Org.Merge(m, src) -} -func (m *Org) XXX_Size() int { - return xxx_messageInfo_Org.Size(m) -} -func (m *Org) XXX_DiscardUnknown() { - xxx_messageInfo_Org.DiscardUnknown(m) -} - -var xxx_messageInfo_Org proto.InternalMessageInfo - -func (m *Org) GetId() string { - if m != nil { - return m.Id +func (x *Org) GetId() string { + if x != nil { + return x.Id } return "" } -func (m *Org) GetName() string { - if m != nil { - return m.Name +func (x *Org) GetName() string { + if x != nil { + return x.Name } return "" } type MyPermissions struct { - Permissions []string `protobuf:"bytes,1,rep,name=permissions,proto3" json:"permissions,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Permissions []string `protobuf:"bytes,1,rep,name=permissions,proto3" json:"permissions,omitempty"` } -func (m *MyPermissions) Reset() { *m = MyPermissions{} } -func (m *MyPermissions) String() string { return proto.CompactTextString(m) } -func (*MyPermissions) ProtoMessage() {} +func (x *MyPermissions) Reset() { + *x = MyPermissions{} + if protoimpl.UnsafeEnabled { + mi := &file_auth_proto_msgTypes[30] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *MyPermissions) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*MyPermissions) ProtoMessage() {} + +func (x *MyPermissions) ProtoReflect() protoreflect.Message { + mi := &file_auth_proto_msgTypes[30] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use MyPermissions.ProtoReflect.Descriptor instead. func (*MyPermissions) Descriptor() ([]byte, []int) { - return fileDescriptor_8bbd6f3875b0e874, []int{27} + return file_auth_proto_rawDescGZIP(), []int{30} } -func (m *MyPermissions) XXX_Unmarshal(b []byte) error { - return xxx_messageInfo_MyPermissions.Unmarshal(m, b) -} -func (m *MyPermissions) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { - return xxx_messageInfo_MyPermissions.Marshal(b, m, deterministic) -} -func (m *MyPermissions) XXX_Merge(src proto.Message) { - xxx_messageInfo_MyPermissions.Merge(m, src) -} -func (m *MyPermissions) XXX_Size() int { - return xxx_messageInfo_MyPermissions.Size(m) -} -func (m *MyPermissions) XXX_DiscardUnknown() { - xxx_messageInfo_MyPermissions.DiscardUnknown(m) -} - -var xxx_messageInfo_MyPermissions proto.InternalMessageInfo - -func (m *MyPermissions) GetPermissions() []string { - if m != nil { - return m.Permissions +func (x *MyPermissions) GetPermissions() []string { + if x != nil { + return x.Permissions } return nil } -func init() { - proto.RegisterEnum("zitadel.auth.api.v1.UserSessionState", UserSessionState_name, UserSessionState_value) - proto.RegisterEnum("zitadel.auth.api.v1.OIDCResponseType", OIDCResponseType_name, OIDCResponseType_value) - proto.RegisterEnum("zitadel.auth.api.v1.UserState", UserState_name, UserState_value) - proto.RegisterEnum("zitadel.auth.api.v1.Gender", Gender_name, Gender_value) - proto.RegisterEnum("zitadel.auth.api.v1.MfaType", MfaType_name, MfaType_value) - proto.RegisterEnum("zitadel.auth.api.v1.MFAState", MFAState_name, MFAState_value) - proto.RegisterEnum("zitadel.auth.api.v1.MyProjectOrgSearchKey", MyProjectOrgSearchKey_name, MyProjectOrgSearchKey_value) - proto.RegisterEnum("zitadel.auth.api.v1.SearchMethod", SearchMethod_name, SearchMethod_value) - proto.RegisterType((*UserSessionViews)(nil), "zitadel.auth.api.v1.UserSessionViews") - proto.RegisterType((*UserSessionView)(nil), "zitadel.auth.api.v1.UserSessionView") - proto.RegisterType((*User)(nil), "zitadel.auth.api.v1.User") - proto.RegisterType((*UserProfile)(nil), "zitadel.auth.api.v1.UserProfile") - proto.RegisterType((*UpdateUserProfileRequest)(nil), "zitadel.auth.api.v1.UpdateUserProfileRequest") - proto.RegisterType((*UserEmail)(nil), "zitadel.auth.api.v1.UserEmail") - proto.RegisterType((*VerifyMyUserEmailRequest)(nil), "zitadel.auth.api.v1.VerifyMyUserEmailRequest") - proto.RegisterType((*VerifyUserEmailRequest)(nil), "zitadel.auth.api.v1.VerifyUserEmailRequest") - proto.RegisterType((*UpdateUserEmailRequest)(nil), "zitadel.auth.api.v1.UpdateUserEmailRequest") - proto.RegisterType((*UserPhone)(nil), "zitadel.auth.api.v1.UserPhone") - proto.RegisterType((*UpdateUserPhoneRequest)(nil), "zitadel.auth.api.v1.UpdateUserPhoneRequest") - proto.RegisterType((*VerifyUserPhoneRequest)(nil), "zitadel.auth.api.v1.VerifyUserPhoneRequest") - proto.RegisterType((*UserAddress)(nil), "zitadel.auth.api.v1.UserAddress") - proto.RegisterType((*UpdateUserAddressRequest)(nil), "zitadel.auth.api.v1.UpdateUserAddressRequest") - proto.RegisterType((*PasswordID)(nil), "zitadel.auth.api.v1.PasswordID") - proto.RegisterType((*PasswordRequest)(nil), "zitadel.auth.api.v1.PasswordRequest") - proto.RegisterType((*PasswordChange)(nil), "zitadel.auth.api.v1.PasswordChange") - proto.RegisterType((*VerifyMfaOtp)(nil), "zitadel.auth.api.v1.VerifyMfaOtp") - proto.RegisterType((*MultiFactors)(nil), "zitadel.auth.api.v1.MultiFactors") - proto.RegisterType((*MultiFactor)(nil), "zitadel.auth.api.v1.MultiFactor") - proto.RegisterType((*MfaOtpResponse)(nil), "zitadel.auth.api.v1.MfaOtpResponse") - proto.RegisterType((*OIDCClientAuth)(nil), "zitadel.auth.api.v1.OIDCClientAuth") - proto.RegisterType((*MyProjectOrgSearchRequest)(nil), "zitadel.auth.api.v1.MyProjectOrgSearchRequest") - proto.RegisterType((*MyProjectOrgSearchQuery)(nil), "zitadel.auth.api.v1.MyProjectOrgSearchQuery") - proto.RegisterType((*MyProjectOrgSearchResponse)(nil), "zitadel.auth.api.v1.MyProjectOrgSearchResponse") - proto.RegisterType((*IsAdminResponse)(nil), "zitadel.auth.api.v1.IsAdminResponse") - proto.RegisterType((*Org)(nil), "zitadel.auth.api.v1.Org") - proto.RegisterType((*MyPermissions)(nil), "zitadel.auth.api.v1.MyPermissions") +var File_auth_proto protoreflect.FileDescriptor + +var file_auth_proto_rawDesc = []byte{ + 0x0a, 0x0a, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x7a, 0x69, + 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, + 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, + 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x73, 0x74, + 0x72, 0x75, 0x63, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x74, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, + 0x69, 0x64, 0x61, 0x74, 0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, + 0x2d, 0x73, 0x77, 0x61, 0x67, 0x67, 0x65, 0x72, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, + 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x1a, 0x18, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6f, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x5d, 0x0a, 0x10, + 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x69, 0x65, 0x77, 0x73, + 0x12, 0x49, 0x0a, 0x0d, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, + 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x69, 0x65, 0x77, 0x52, 0x0c, 0x75, + 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0xd4, 0x01, 0x0a, 0x0f, + 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x69, 0x65, 0x77, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x19, 0x0a, 0x08, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x49, 0x64, 0x12, 0x44, 0x0a, 0x0a, 0x61, 0x75, + 0x74, 0x68, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, + 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x09, 0x61, 0x75, 0x74, 0x68, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, + 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, + 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, + 0x63, 0x65, 0x22, 0xfe, 0x07, 0x0a, 0x04, 0x55, 0x73, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x34, 0x0a, 0x05, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x7a, 0x69, 0x74, + 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, + 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, + 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, + 0x74, 0x65, 0x12, 0x43, 0x0a, 0x0f, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, + 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0e, 0x61, 0x63, 0x74, 0x69, 0x76, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x67, + 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, + 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x44, 0x61, 0x74, 0x65, 0x12, 0x39, 0x0a, 0x0a, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6c, 0x6f, 0x67, + 0x69, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, + 0x74, 0x61, 0x6d, 0x70, 0x52, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, + 0x45, 0x0a, 0x10, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, + 0x67, 0x65, 0x64, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, + 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, + 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x6e, 0x69, 0x63, 0x6b, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, + 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x2d, 0x0a, 0x12, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x5f, 0x6c, 0x61, 0x6e, + 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x70, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x33, + 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x0e, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, + 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x52, 0x06, 0x67, 0x65, 0x6e, + 0x64, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x0f, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x2a, 0x0a, 0x11, 0x69, 0x73, 0x5f, + 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x10, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x73, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x56, 0x65, 0x72, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x11, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x69, + 0x73, 0x5f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x18, 0x12, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x73, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x56, + 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, + 0x72, 0x79, 0x18, 0x13, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x14, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x12, 0x1f, 0x0a, + 0x0b, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x15, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0a, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, + 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x16, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, + 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x17, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, + 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x38, 0x0a, + 0x18, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, + 0x5f, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x18, 0x18, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x16, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x65, 0x18, 0x19, 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, + 0x6e, 0x63, 0x65, 0x22, 0xb4, 0x03, 0x0a, 0x0b, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, + 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x09, + 0x6e, 0x69, 0x63, 0x6b, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x6e, 0x69, 0x63, 0x6b, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, + 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x12, + 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, + 0x67, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x11, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, + 0x72, 0x65, 0x64, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x33, 0x0a, 0x06, 0x67, + 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, 0x2e, 0x7a, 0x69, + 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x52, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, + 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x3f, 0x0a, 0x0d, + 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x0a, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, + 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, + 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x61, 0x74, 0x65, 0x22, 0xb6, 0x02, 0x0a, 0x18, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x29, 0x0a, 0x0a, 0x66, 0x69, 0x72, 0x73, 0x74, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, + 0x72, 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x09, 0x66, 0x69, 0x72, 0x73, 0x74, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x09, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xc8, + 0x01, 0x52, 0x08, 0x6c, 0x61, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x09, 0x6e, + 0x69, 0x63, 0x6b, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, + 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x08, 0x6e, 0x69, 0x63, 0x6b, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, + 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x39, 0x0a, 0x12, 0x70, 0x72, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, + 0x5f, 0x6c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x11, 0x70, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x4c, 0x61, 0x6e, 0x67, 0x75, 0x61, 0x67, 0x65, 0x12, 0x33, + 0x0a, 0x06, 0x67, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1b, + 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x52, 0x06, 0x67, 0x65, 0x6e, + 0x64, 0x65, 0x72, 0x22, 0xf5, 0x01, 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, + 0x6c, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x28, 0x0a, 0x0f, 0x69, 0x73, 0x45, 0x6d, 0x61, + 0x69, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0f, 0x69, 0x73, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, + 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x3f, 0x0a, + 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, 0x3b, + 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, + 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x61, 0x74, 0x65, 0x22, 0x3a, 0x0a, 0x18, 0x56, + 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xc8, + 0x01, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x48, 0x0a, 0x16, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, + 0x64, 0x12, 0x1e, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x0a, 0xfa, 0x42, 0x07, 0x72, 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x04, 0x63, 0x6f, 0x64, + 0x65, 0x22, 0x3a, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x45, + 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x05, 0x65, + 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, + 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x05, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0xf7, 0x01, + 0x0a, 0x09, 0x55, 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x70, + 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x70, 0x68, 0x6f, 0x6e, + 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x69, 0x73, 0x5f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x5f, 0x76, 0x65, + 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0f, 0x69, 0x73, + 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x1a, 0x0a, + 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x3f, 0x0a, 0x0d, 0x63, 0x72, 0x65, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0c, 0x63, 0x72, + 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, 0x3b, 0x0a, 0x0b, 0x63, 0x68, + 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x52, 0x0a, 0x63, 0x68, 0x61, + 0x6e, 0x67, 0x65, 0x44, 0x61, 0x74, 0x65, 0x22, 0x39, 0x0a, 0x16, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x55, 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1f, 0x0a, 0x05, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x14, 0x52, 0x05, 0x70, 0x68, 0x6f, + 0x6e, 0x65, 0x22, 0x38, 0x0a, 0x16, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x55, 0x73, 0x65, 0x72, + 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1e, 0x0a, 0x04, + 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x0a, 0xfa, 0x42, 0x07, 0x72, + 0x05, 0x10, 0x01, 0x18, 0xc8, 0x01, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0xcd, 0x02, 0x0a, + 0x0b, 0x55, 0x73, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, + 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, + 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, + 0x74, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, + 0x74, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, 0x64, + 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x43, + 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x73, + 0x74, 0x72, 0x65, 0x65, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x18, 0x06, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x18, 0x07, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x08, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x12, 0x3f, + 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, + 0x70, 0x52, 0x0c, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x44, 0x61, 0x74, 0x65, 0x12, + 0x3b, 0x0a, 0x0b, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x5f, 0x64, 0x61, 0x74, 0x65, 0x18, 0x09, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, + 0x52, 0x0a, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x44, 0x61, 0x74, 0x65, 0x22, 0xe2, 0x01, 0x0a, + 0x18, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x22, 0x0a, 0x07, 0x63, 0x6f, 0x75, + 0x6e, 0x74, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, + 0x03, 0x18, 0xc8, 0x01, 0x52, 0x07, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x24, 0x0a, + 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x69, 0x74, 0x79, 0x12, 0x29, 0x0a, 0x0b, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x5f, 0x63, 0x6f, + 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, + 0xc8, 0x01, 0x52, 0x0a, 0x70, 0x6f, 0x73, 0x74, 0x61, 0x6c, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x20, + 0x0a, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, + 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, 0xc8, 0x01, 0x52, 0x06, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, + 0x12, 0x2f, 0x0a, 0x0e, 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x65, + 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x18, + 0xc8, 0x01, 0x52, 0x0d, 0x73, 0x74, 0x72, 0x65, 0x65, 0x74, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x22, 0x1c, 0x0a, 0x0a, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x49, 0x44, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x22, + 0x38, 0x0a, 0x0f, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x25, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x48, 0x52, + 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x6c, 0x0a, 0x0e, 0x50, 0x61, 0x73, + 0x73, 0x77, 0x6f, 0x72, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x12, 0x2c, 0x0a, 0x0c, 0x6f, + 0x6c, 0x64, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x42, 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x48, 0x52, 0x0b, 0x6f, 0x6c, + 0x64, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x2c, 0x0a, 0x0c, 0x6e, 0x65, 0x77, + 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, + 0x09, 0xfa, 0x42, 0x06, 0x72, 0x04, 0x10, 0x01, 0x18, 0x48, 0x52, 0x0b, 0x6e, 0x65, 0x77, 0x50, + 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, 0x22, 0x0a, 0x0c, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x4d, 0x66, 0x61, 0x4f, 0x74, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x44, 0x0a, 0x0c, 0x4d, + 0x75, 0x6c, 0x74, 0x69, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x12, 0x34, 0x0a, 0x04, 0x6d, + 0x66, 0x61, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x20, 0x2e, 0x7a, 0x69, 0x74, 0x61, + 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, + 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, 0x52, 0x04, 0x6d, 0x66, 0x61, + 0x73, 0x22, 0x74, 0x0a, 0x0b, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x46, 0x61, 0x63, 0x74, 0x6f, 0x72, + 0x12, 0x30, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, + 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x66, 0x61, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x12, 0x33, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x1d, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x46, 0x41, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x22, 0x88, 0x01, 0x0a, 0x0e, 0x4d, 0x66, 0x61, 0x4f, + 0x74, 0x70, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, + 0x72, 0x49, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x12, 0x33, 0x0a, + 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, 0x7a, + 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x4d, 0x46, 0x41, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x22, 0x52, 0x0a, 0x0e, 0x4f, 0x49, 0x44, 0x43, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x41, 0x75, 0x74, 0x68, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x49, + 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, + 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, + 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x22, 0xf7, 0x01, 0x0a, 0x16, 0x55, 0x73, 0x65, 0x72, 0x47, + 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, + 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, + 0x58, 0x0a, 0x0e, 0x73, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x63, 0x6f, 0x6c, 0x75, 0x6d, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, + 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, + 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, + 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x20, 0x00, 0x52, 0x0d, 0x73, 0x6f, 0x72, 0x74, + 0x69, 0x6e, 0x67, 0x43, 0x6f, 0x6c, 0x75, 0x6d, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x63, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x03, 0x61, 0x73, 0x63, 0x12, 0x43, 0x0a, 0x07, 0x71, + 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x7a, + 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, + 0x22, 0xac, 0x01, 0x0a, 0x14, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x43, 0x0a, 0x03, 0x6b, 0x65, 0x79, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, + 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, + 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x42, + 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x20, 0x00, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x39, + 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x21, + 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, + 0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, + 0xa6, 0x01, 0x0a, 0x17, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, + 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, + 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x6f, 0x74, + 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x52, + 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x3a, 0x0a, 0x06, + 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x22, 0x2e, 0x7a, + 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x56, 0x69, 0x65, 0x77, + 0x52, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x22, 0x8b, 0x01, 0x0a, 0x0d, 0x55, 0x73, 0x65, + 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x56, 0x69, 0x65, 0x77, 0x12, 0x14, 0x0a, 0x05, 0x4f, 0x72, + 0x67, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x4f, 0x72, 0x67, 0x49, 0x64, + 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x64, 0x12, 0x16, + 0x0a, 0x06, 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, + 0x55, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x18, + 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x52, 0x6f, 0x6c, 0x65, 0x73, 0x12, 0x18, 0x0a, 0x07, + 0x4f, 0x72, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x4f, + 0x72, 0x67, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xa3, 0x01, 0x0a, 0x19, 0x4d, 0x79, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, + 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, + 0x69, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x61, 0x73, 0x63, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x03, 0x61, 0x73, 0x63, 0x12, 0x46, 0x0a, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x18, + 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, + 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x79, 0x50, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x51, 0x75, + 0x65, 0x72, 0x79, 0x52, 0x07, 0x71, 0x75, 0x65, 0x72, 0x69, 0x65, 0x73, 0x22, 0xb2, 0x01, 0x0a, + 0x17, 0x4d, 0x79, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x51, 0x75, 0x65, 0x72, 0x79, 0x12, 0x46, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, + 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x79, 0x50, 0x72, + 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, + 0x79, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x20, 0x00, 0x52, 0x03, 0x6b, 0x65, 0x79, + 0x12, 0x39, 0x0a, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x21, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4d, 0x65, 0x74, + 0x68, 0x6f, 0x64, 0x52, 0x06, 0x6d, 0x65, 0x74, 0x68, 0x6f, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x22, 0x9f, 0x01, 0x0a, 0x1a, 0x4d, 0x79, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, + 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, + 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, + 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x21, + 0x0a, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x52, 0x65, 0x73, 0x75, 0x6c, + 0x74, 0x12, 0x30, 0x0a, 0x06, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x18, 0x04, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x18, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x72, 0x67, 0x52, 0x06, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x22, 0x29, 0x0a, 0x03, 0x4f, 0x72, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x31, + 0x0a, 0x0d, 0x4d, 0x79, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, + 0x20, 0x0a, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x73, 0x2a, 0x72, 0x0a, 0x10, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x20, 0x0a, 0x1c, 0x55, 0x53, 0x45, 0x52, 0x53, 0x45, 0x53, + 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, + 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x55, 0x53, 0x45, 0x52, 0x53, + 0x45, 0x53, 0x53, 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x41, 0x43, 0x54, 0x49, + 0x56, 0x45, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x55, 0x53, 0x45, 0x52, 0x53, 0x45, 0x53, 0x53, + 0x49, 0x4f, 0x4e, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x45, 0x52, 0x4d, 0x49, 0x4e, 0x41, + 0x54, 0x45, 0x44, 0x10, 0x02, 0x2a, 0x71, 0x0a, 0x10, 0x4f, 0x49, 0x44, 0x43, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x19, 0x0a, 0x15, 0x4f, 0x49, 0x44, + 0x43, 0x52, 0x45, 0x53, 0x50, 0x4f, 0x4e, 0x53, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x43, 0x4f, + 0x44, 0x45, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x4f, 0x49, 0x44, 0x43, 0x52, 0x45, 0x53, 0x50, + 0x4f, 0x4e, 0x53, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x54, 0x4f, 0x4b, 0x45, + 0x4e, 0x10, 0x01, 0x12, 0x23, 0x0a, 0x1f, 0x4f, 0x49, 0x44, 0x43, 0x52, 0x45, 0x53, 0x50, 0x4f, + 0x4e, 0x53, 0x45, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x44, 0x5f, 0x54, 0x4f, 0x4b, 0x45, 0x4e, + 0x5f, 0x54, 0x4f, 0x4b, 0x45, 0x4e, 0x10, 0x02, 0x2a, 0xb0, 0x01, 0x0a, 0x09, 0x55, 0x73, 0x65, + 0x72, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x16, 0x55, 0x53, 0x45, 0x52, 0x53, 0x54, + 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x45, 0x46, 0x49, 0x45, 0x44, + 0x10, 0x00, 0x12, 0x14, 0x0a, 0x10, 0x55, 0x53, 0x45, 0x52, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, + 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x55, 0x53, 0x45, 0x52, + 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x49, 0x4e, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, + 0x12, 0x15, 0x0a, 0x11, 0x55, 0x53, 0x45, 0x52, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x44, 0x45, + 0x4c, 0x45, 0x54, 0x45, 0x44, 0x10, 0x03, 0x12, 0x14, 0x0a, 0x10, 0x55, 0x53, 0x45, 0x52, 0x53, + 0x54, 0x41, 0x54, 0x45, 0x5f, 0x4c, 0x4f, 0x43, 0x4b, 0x45, 0x44, 0x10, 0x04, 0x12, 0x15, 0x0a, + 0x11, 0x55, 0x53, 0x45, 0x52, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x53, 0x55, 0x53, 0x50, 0x45, + 0x4e, 0x44, 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x55, 0x53, 0x45, 0x52, 0x53, 0x54, 0x41, 0x54, + 0x45, 0x5f, 0x49, 0x4e, 0x49, 0x54, 0x49, 0x41, 0x4c, 0x10, 0x06, 0x2a, 0x58, 0x0a, 0x06, 0x47, + 0x65, 0x6e, 0x64, 0x65, 0x72, 0x12, 0x16, 0x0a, 0x12, 0x47, 0x45, 0x4e, 0x44, 0x45, 0x52, 0x5f, + 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x11, 0x0a, + 0x0d, 0x47, 0x45, 0x4e, 0x44, 0x45, 0x52, 0x5f, 0x46, 0x45, 0x4d, 0x41, 0x4c, 0x45, 0x10, 0x01, + 0x12, 0x0f, 0x0a, 0x0b, 0x47, 0x45, 0x4e, 0x44, 0x45, 0x52, 0x5f, 0x4d, 0x41, 0x4c, 0x45, 0x10, + 0x02, 0x12, 0x12, 0x0a, 0x0e, 0x47, 0x45, 0x4e, 0x44, 0x45, 0x52, 0x5f, 0x44, 0x49, 0x56, 0x45, + 0x52, 0x53, 0x45, 0x10, 0x03, 0x2a, 0x44, 0x0a, 0x07, 0x4d, 0x66, 0x61, 0x54, 0x79, 0x70, 0x65, + 0x12, 0x17, 0x0a, 0x13, 0x4d, 0x46, 0x41, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, + 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x46, 0x41, + 0x54, 0x59, 0x50, 0x45, 0x5f, 0x53, 0x4d, 0x53, 0x10, 0x01, 0x12, 0x0f, 0x0a, 0x0b, 0x4d, 0x46, + 0x41, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x4f, 0x54, 0x50, 0x10, 0x02, 0x2a, 0x66, 0x0a, 0x08, 0x4d, + 0x46, 0x41, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x4d, 0x46, 0x41, 0x53, 0x54, + 0x41, 0x54, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, + 0x00, 0x12, 0x16, 0x0a, 0x12, 0x4d, 0x46, 0x41, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x4e, 0x4f, + 0x54, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x59, 0x10, 0x01, 0x12, 0x12, 0x0a, 0x0e, 0x4d, 0x46, 0x41, + 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x52, 0x45, 0x41, 0x44, 0x59, 0x10, 0x02, 0x12, 0x14, 0x0a, + 0x10, 0x4d, 0x46, 0x41, 0x53, 0x54, 0x41, 0x54, 0x45, 0x5f, 0x52, 0x45, 0x4d, 0x4f, 0x56, 0x45, + 0x44, 0x10, 0x03, 0x2a, 0x76, 0x0a, 0x12, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, + 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x12, 0x1e, 0x0a, 0x1a, 0x55, 0x73, 0x65, + 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x5f, + 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x1d, 0x0a, 0x19, 0x55, 0x73, 0x65, + 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x5f, + 0x4f, 0x52, 0x47, 0x5f, 0x49, 0x44, 0x10, 0x01, 0x12, 0x21, 0x0a, 0x1d, 0x55, 0x73, 0x65, 0x72, + 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4b, 0x65, 0x79, 0x5f, 0x50, + 0x52, 0x4f, 0x4a, 0x45, 0x43, 0x54, 0x5f, 0x49, 0x44, 0x10, 0x02, 0x2a, 0x62, 0x0a, 0x15, 0x4d, + 0x79, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x4b, 0x65, 0x79, 0x12, 0x25, 0x0a, 0x21, 0x4d, 0x59, 0x50, 0x52, 0x4f, 0x4a, 0x45, 0x43, + 0x54, 0x4f, 0x52, 0x47, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x4b, 0x45, 0x59, 0x5f, 0x55, 0x4e, + 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x22, 0x0a, 0x1e, 0x4d, + 0x59, 0x50, 0x52, 0x4f, 0x4a, 0x45, 0x43, 0x54, 0x4f, 0x52, 0x47, 0x53, 0x45, 0x41, 0x52, 0x43, + 0x48, 0x4b, 0x45, 0x59, 0x5f, 0x4f, 0x52, 0x47, 0x5f, 0x4e, 0x41, 0x4d, 0x45, 0x10, 0x01, 0x2a, + 0xd6, 0x01, 0x0a, 0x0c, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4d, 0x65, 0x74, 0x68, 0x6f, 0x64, + 0x12, 0x17, 0x0a, 0x13, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, + 0x5f, 0x45, 0x51, 0x55, 0x41, 0x4c, 0x53, 0x10, 0x00, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x45, 0x41, + 0x52, 0x43, 0x48, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x53, + 0x5f, 0x57, 0x49, 0x54, 0x48, 0x10, 0x01, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x45, 0x41, 0x52, 0x43, + 0x48, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49, 0x4e, 0x53, + 0x10, 0x02, 0x12, 0x23, 0x0a, 0x1f, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x4d, 0x45, 0x54, 0x48, + 0x4f, 0x44, 0x5f, 0x45, 0x51, 0x55, 0x41, 0x4c, 0x53, 0x5f, 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45, + 0x5f, 0x43, 0x41, 0x53, 0x45, 0x10, 0x03, 0x12, 0x28, 0x0a, 0x24, 0x53, 0x45, 0x41, 0x52, 0x43, + 0x48, 0x4d, 0x45, 0x54, 0x48, 0x4f, 0x44, 0x5f, 0x53, 0x54, 0x41, 0x52, 0x54, 0x53, 0x5f, 0x57, + 0x49, 0x54, 0x48, 0x5f, 0x49, 0x47, 0x4e, 0x4f, 0x52, 0x45, 0x5f, 0x43, 0x41, 0x53, 0x45, 0x10, + 0x04, 0x12, 0x25, 0x0a, 0x21, 0x53, 0x45, 0x41, 0x52, 0x43, 0x48, 0x4d, 0x45, 0x54, 0x48, 0x4f, + 0x44, 0x5f, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49, 0x4e, 0x53, 0x5f, 0x49, 0x47, 0x4e, 0x4f, 0x52, + 0x45, 0x5f, 0x43, 0x41, 0x53, 0x45, 0x10, 0x05, 0x32, 0xd5, 0x18, 0x0a, 0x0b, 0x41, 0x75, 0x74, + 0x68, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x4b, 0x0a, 0x07, 0x48, 0x65, 0x61, 0x6c, + 0x74, 0x68, 0x7a, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x22, 0x10, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0a, 0x12, 0x08, 0x2f, 0x68, 0x65, + 0x61, 0x6c, 0x74, 0x68, 0x7a, 0x12, 0x47, 0x0a, 0x05, 0x52, 0x65, 0x61, 0x64, 0x79, 0x12, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x0e, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x08, 0x12, 0x06, 0x2f, 0x72, 0x65, 0x61, 0x64, 0x79, 0x12, 0x4e, + 0x0a, 0x08, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x1a, 0x17, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x75, 0x63, 0x74, 0x22, 0x11, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x0b, 0x12, 0x09, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x12, 0x7f, + 0x0a, 0x11, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, + 0x6f, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x25, 0x2e, 0x7a, 0x69, + 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x56, 0x69, 0x65, + 0x77, 0x73, 0x22, 0x2b, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x12, 0x10, 0x2f, 0x6d, 0x65, 0x2f, + 0x75, 0x73, 0x65, 0x72, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x82, 0xb5, 0x18, 0x0f, + 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, + 0x7a, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x20, 0x2e, 0x7a, 0x69, + 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, + 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x22, 0x2c, 0x82, + 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, + 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x97, 0x01, 0x0a, 0x13, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, + 0x69, 0x6c, 0x65, 0x12, 0x2d, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, + 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x72, 0x6f, + 0x66, 0x69, 0x6c, 0x65, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x1a, 0x11, 0x2f, 0x75, + 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x66, 0x69, 0x6c, 0x65, 0x3a, + 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x74, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x55, 0x73, + 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x1e, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x22, + 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, + 0x6d, 0x65, 0x2f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x8f, 0x01, 0x0a, 0x11, + 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, + 0x6c, 0x12, 0x2b, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, + 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1e, + 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, + 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x22, 0x2d, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x1a, 0x0f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, + 0x65, 0x2f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, + 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x91, 0x01, + 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, + 0x61, 0x69, 0x6c, 0x12, 0x2d, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, + 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x35, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x1c, 0x22, 0x17, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x65, 0x6d, + 0x61, 0x69, 0x6c, 0x2f, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x3a, 0x01, 0x2a, 0x82, 0xb5, + 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x64, 0x12, 0x92, 0x01, 0x0a, 0x1d, 0x52, 0x65, 0x73, 0x65, 0x6e, 0x64, 0x4d, 0x79, 0x45, 0x6d, + 0x61, 0x69, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, + 0x61, 0x69, 0x6c, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x22, 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x22, 0x23, 0x2f, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x2f, 0x5f, 0x72, 0x65, + 0x73, 0x65, 0x6e, 0x64, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x74, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x55, + 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x1a, 0x1e, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, + 0x22, 0x2a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x11, 0x12, 0x0f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, + 0x2f, 0x6d, 0x65, 0x2f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, + 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x8f, 0x01, 0x0a, + 0x11, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, + 0x6e, 0x65, 0x12, 0x2b, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, + 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, + 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x1e, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x22, + 0x2d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x1a, 0x0f, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, + 0x6d, 0x65, 0x2f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, + 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x8f, + 0x01, 0x0a, 0x11, 0x56, 0x65, 0x72, 0x69, 0x66, 0x79, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x50, + 0x68, 0x6f, 0x6e, 0x65, 0x12, 0x2b, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, + 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x55, 0x73, 0x65, 0x72, 0x50, 0x68, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x35, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x1c, 0x22, 0x17, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x70, 0x68, 0x6f, + 0x6e, 0x65, 0x2f, 0x5f, 0x76, 0x65, 0x72, 0x69, 0x66, 0x79, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, + 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x12, 0x92, 0x01, 0x0a, 0x1d, 0x52, 0x65, 0x73, 0x65, 0x6e, 0x64, 0x4d, 0x79, 0x50, 0x68, 0x6f, + 0x6e, 0x65, 0x56, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, + 0x64, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x22, 0x41, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x28, 0x22, 0x23, 0x2f, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x70, 0x68, 0x6f, 0x6e, 0x65, 0x2f, 0x5f, 0x72, 0x65, 0x73, + 0x65, 0x6e, 0x64, 0x76, 0x65, 0x72, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x3a, + 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, + 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x7a, 0x0a, 0x10, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x55, 0x73, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x1a, 0x20, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, + 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, + 0x65, 0x73, 0x73, 0x22, 0x2c, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x12, 0x11, 0x2f, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x61, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x82, 0xb5, + 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, + 0x64, 0x12, 0x97, 0x01, 0x0a, 0x13, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4d, 0x79, 0x55, 0x73, + 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x2d, 0x2e, 0x7a, 0x69, 0x74, 0x61, + 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, + 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x20, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, + 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, + 0x73, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x16, 0x1a, 0x11, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x61, 0x64, + 0x64, 0x72, 0x65, 0x73, 0x73, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x71, 0x0a, 0x09, 0x47, + 0x65, 0x74, 0x4d, 0x79, 0x4d, 0x66, 0x61, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x1a, 0x21, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x75, 0x6c, 0x74, 0x69, 0x46, 0x61, 0x63, 0x74, + 0x6f, 0x72, 0x73, 0x22, 0x29, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x10, 0x12, 0x0e, 0x2f, 0x75, 0x73, + 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x6d, 0x66, 0x61, 0x73, 0x82, 0xb5, 0x18, 0x0f, 0x0a, + 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x8a, + 0x01, 0x0a, 0x10, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x4d, 0x79, 0x50, 0x61, 0x73, 0x73, 0x77, + 0x6f, 0x72, 0x64, 0x12, 0x23, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, + 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, + 0x72, 0x64, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x1a, 0x1b, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, + 0x2f, 0x6d, 0x65, 0x2f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x2f, 0x5f, 0x63, + 0x68, 0x61, 0x6e, 0x67, 0x65, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x79, 0x0a, 0x09, 0x41, + 0x64, 0x64, 0x4d, 0x66, 0x61, 0x4f, 0x54, 0x50, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x1a, 0x23, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, + 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, 0x66, 0x61, 0x4f, 0x74, 0x70, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x2f, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x16, 0x22, 0x11, 0x2f, + 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x6d, 0x66, 0x61, 0x2f, 0x6f, 0x74, 0x70, + 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, + 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x82, 0x01, 0x0a, 0x0c, 0x56, 0x65, 0x72, 0x69, 0x66, + 0x79, 0x4d, 0x66, 0x61, 0x4f, 0x54, 0x50, 0x12, 0x21, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, + 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x56, 0x65, + 0x72, 0x69, 0x66, 0x79, 0x4d, 0x66, 0x61, 0x4f, 0x74, 0x70, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x22, 0x37, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1e, 0x1a, 0x19, 0x2f, 0x75, 0x73, 0x65, + 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x6d, 0x66, 0x61, 0x2f, 0x6f, 0x74, 0x70, 0x2f, 0x5f, 0x76, + 0x65, 0x72, 0x69, 0x66, 0x79, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, + 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0x6c, 0x0a, 0x0c, 0x52, + 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x4d, 0x66, 0x61, 0x4f, 0x54, 0x50, 0x12, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x2c, 0x82, 0xd3, 0xe4, + 0x93, 0x02, 0x13, 0x2a, 0x11, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x73, 0x2f, 0x6d, 0x65, 0x2f, 0x6d, + 0x66, 0x61, 0x2f, 0x6f, 0x74, 0x70, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, + 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, 0x12, 0xa4, 0x01, 0x0a, 0x11, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x4d, 0x79, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x12, + 0x2b, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, + 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x7a, + 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, + 0x76, 0x31, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x47, 0x72, 0x61, 0x6e, 0x74, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x34, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x1b, 0x22, 0x16, 0x2f, 0x75, 0x73, 0x65, 0x72, 0x67, 0x72, 0x61, 0x6e, 0x74, 0x73, 0x2f, + 0x6d, 0x65, 0x2f, 0x5f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x3a, 0x01, 0x2a, 0x82, 0xb5, 0x18, + 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x12, 0xb1, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x4d, 0x79, 0x50, 0x72, 0x6f, + 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x73, 0x12, 0x2e, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, + 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, + 0x79, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2f, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, + 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, + 0x79, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x4f, 0x72, 0x67, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x39, 0x82, 0xd3, 0xe4, 0x93, 0x02, + 0x20, 0x22, 0x1b, 0x2f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x6a, 0x65, + 0x63, 0x74, 0x6f, 0x72, 0x67, 0x73, 0x2f, 0x5f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x3a, 0x01, + 0x2a, 0x82, 0xb5, 0x18, 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, + 0x61, 0x74, 0x65, 0x64, 0x12, 0x89, 0x01, 0x0a, 0x17, 0x47, 0x65, 0x74, 0x4d, 0x79, 0x5a, 0x69, + 0x74, 0x61, 0x64, 0x65, 0x6c, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, + 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x22, 0x2e, 0x7a, 0x69, 0x74, 0x61, 0x64, + 0x65, 0x6c, 0x2e, 0x61, 0x75, 0x74, 0x68, 0x2e, 0x61, 0x70, 0x69, 0x2e, 0x76, 0x31, 0x2e, 0x4d, + 0x79, 0x50, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x32, 0x82, 0xd3, + 0xe4, 0x93, 0x02, 0x19, 0x12, 0x17, 0x2f, 0x70, 0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, + 0x6e, 0x73, 0x2f, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2f, 0x6d, 0x65, 0x82, 0xb5, 0x18, + 0x0f, 0x0a, 0x0d, 0x61, 0x75, 0x74, 0x68, 0x65, 0x6e, 0x74, 0x69, 0x63, 0x61, 0x74, 0x65, 0x64, + 0x42, 0xb7, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x63, 0x61, 0x6f, 0x73, 0x2f, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, 0x6c, 0x2f, 0x70, 0x6b, 0x67, + 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x92, 0x41, + 0x88, 0x01, 0x12, 0x3b, 0x0a, 0x08, 0x41, 0x75, 0x74, 0x68, 0x20, 0x41, 0x50, 0x49, 0x22, 0x2a, + 0x12, 0x28, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x61, 0x6f, 0x73, 0x2f, 0x7a, 0x69, 0x74, 0x61, 0x64, 0x65, + 0x6c, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x32, 0x03, 0x30, 0x2e, 0x31, 0x2a, + 0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, + 0x6a, 0x73, 0x6f, 0x6e, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } -func init() { proto.RegisterFile("auth.proto", fileDescriptor_8bbd6f3875b0e874) } +var ( + file_auth_proto_rawDescOnce sync.Once + file_auth_proto_rawDescData = file_auth_proto_rawDesc +) -var fileDescriptor_8bbd6f3875b0e874 = []byte{ - // 2779 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xcc, 0x5a, 0x4b, 0x6f, 0x1b, 0xd7, - 0x15, 0xf6, 0x90, 0x14, 0x45, 0x1e, 0x4a, 0xd4, 0xe8, 0xca, 0x96, 0x46, 0x0f, 0xdb, 0xf4, 0x38, - 0x46, 0x64, 0xc6, 0x16, 0x13, 0x25, 0x45, 0x63, 0x67, 0x51, 0xd0, 0xe2, 0xc8, 0x66, 0x2d, 0x3e, - 0x32, 0xa4, 0xdd, 0x3a, 0x40, 0xc1, 0x8e, 0x39, 0x57, 0xd4, 0x24, 0x24, 0x67, 0x3c, 0x33, 0x94, - 0xc1, 0x6c, 0x0a, 0x78, 0x95, 0x76, 0x13, 0x34, 0x5d, 0x74, 0xd9, 0x45, 0x77, 0x5d, 0xb5, 0x45, - 0x1f, 0x7f, 0xa1, 0x9b, 0xae, 0xda, 0x5f, 0x50, 0xf4, 0x2f, 0x14, 0x05, 0xb2, 0x28, 0x8a, 0xfb, - 0x18, 0x72, 0x1e, 0x1c, 0x91, 0x82, 0x51, 0xa0, 0x2b, 0xf3, 0x9e, 0xe7, 0x77, 0xcf, 0x39, 0xf7, - 0xcc, 0xbd, 0xc7, 0x02, 0xd0, 0x46, 0xee, 0xd9, 0x81, 0x65, 0x9b, 0xae, 0x89, 0x36, 0xbe, 0x34, - 0x5c, 0x4d, 0xc7, 0xfd, 0x03, 0x4a, 0xd3, 0x2c, 0xe3, 0xe0, 0xfc, 0x83, 0x9d, 0xbd, 0x9e, 0x69, - 0xf6, 0xfa, 0xb8, 0xa4, 0x59, 0x46, 0x49, 0x1b, 0x0e, 0x4d, 0x57, 0x73, 0x0d, 0x73, 0xe8, 0x30, - 0x95, 0x9d, 0x5d, 0xce, 0xa5, 0xab, 0x97, 0xa3, 0xd3, 0x12, 0x1e, 0x58, 0xee, 0x98, 0x33, 0xf7, - 0xc2, 0x4c, 0xc7, 0xb5, 0x47, 0x5d, 0x97, 0x73, 0x6f, 0x86, 0xb9, 0xae, 0x31, 0xc0, 0x8e, 0xab, - 0x0d, 0x2c, 0x2e, 0xb0, 0x75, 0xae, 0xf5, 0x0d, 0x5d, 0x73, 0x71, 0xc9, 0xfb, 0xc1, 0x19, 0xf7, - 0xe8, 0x3f, 0xdd, 0xfb, 0x3d, 0x3c, 0xbc, 0xef, 0xbc, 0xd6, 0x7a, 0x3d, 0x6c, 0x97, 0x4c, 0x8b, - 0xc2, 0x9a, 0x01, 0x51, 0x22, 0xbb, 0x61, 0x6c, 0x4f, 0x8a, 0x71, 0xe4, 0x1f, 0x81, 0xf8, 0xcc, - 0xc1, 0x76, 0x0b, 0x3b, 0x8e, 0x61, 0x0e, 0x9f, 0x1b, 0xf8, 0xb5, 0x83, 0xaa, 0xb0, 0x3a, 0x72, - 0xb0, 0xdd, 0x71, 0x18, 0xd1, 0x91, 0x84, 0x42, 0x72, 0x3f, 0x77, 0xf8, 0xce, 0xc1, 0x8c, 0xd8, - 0x1c, 0x84, 0xb4, 0xd5, 0x95, 0xd1, 0x94, 0xe0, 0xc8, 0x7f, 0x17, 0x60, 0x2d, 0x24, 0x81, 0xf2, - 0x90, 0x30, 0x74, 0x49, 0x28, 0x08, 0xfb, 0x59, 0x35, 0x61, 0xe8, 0x68, 0x1b, 0x32, 0x5a, 0x0f, - 0x0f, 0xdd, 0x8e, 0xa1, 0x4b, 0x09, 0x4a, 0x5d, 0xa6, 0xeb, 0xaa, 0x8e, 0x2a, 0x2c, 0x37, 0x1d, - 0xc7, 0xd5, 0x5c, 0x2c, 0x25, 0x0b, 0xc2, 0x7e, 0xfe, 0xf0, 0xce, 0x3c, 0x18, 0x2d, 0x22, 0xac, - 0x66, 0x09, 0x97, 0xfe, 0x44, 0x5b, 0xb0, 0x4c, 0xf7, 0x63, 0xe8, 0x52, 0x8a, 0xda, 0x4f, 0x93, - 0x65, 0x55, 0x47, 0xbb, 0x90, 0xa5, 0x8c, 0xa1, 0x36, 0xc0, 0xd2, 0x12, 0x65, 0x65, 0x08, 0xa1, - 0xae, 0x0d, 0x30, 0xda, 0x81, 0x8c, 0x83, 0x5f, 0x8d, 0xf0, 0xb0, 0x8b, 0xa5, 0x74, 0x41, 0xd8, - 0x4f, 0xa9, 0x93, 0xb5, 0xfc, 0x9f, 0x65, 0x48, 0x11, 0x8f, 0x91, 0xbd, 0x7c, 0x04, 0x4b, 0x0c, - 0x6b, 0x82, 0x62, 0xbd, 0x11, 0x8f, 0x95, 0x82, 0x64, 0xc2, 0xe8, 0x7b, 0xb0, 0xda, 0xb5, 0x31, - 0xcd, 0x58, 0x47, 0xf7, 0x76, 0x9a, 0x3b, 0xdc, 0x39, 0x60, 0xe5, 0x71, 0xe0, 0x95, 0xc7, 0x41, - 0xdb, 0x2b, 0x0f, 0x75, 0xc5, 0x53, 0xa8, 0x10, 0x03, 0x47, 0xb0, 0xa6, 0x75, 0x5d, 0xe3, 0xdc, - 0x67, 0x22, 0x35, 0xd7, 0x44, 0x7e, 0xaa, 0x42, 0x8d, 0x7c, 0x02, 0xb9, 0xee, 0x99, 0x36, 0xec, - 0x61, 0x66, 0x60, 0x69, 0xae, 0x01, 0x60, 0xe2, 0x54, 0xf9, 0x01, 0x40, 0x5f, 0x73, 0xdc, 0x4e, - 0xdf, 0xec, 0x19, 0x43, 0x1a, 0xaf, 0x8b, 0x75, 0xb3, 0x44, 0xfa, 0x84, 0x08, 0x23, 0x05, 0x44, - 0x4b, 0x73, 0x9c, 0xd7, 0xa6, 0xad, 0x77, 0x98, 0x45, 0x5d, 0x5a, 0x9e, 0x6b, 0x60, 0xcd, 0xd3, - 0x39, 0x62, 0x2a, 0xc1, 0x64, 0x66, 0x42, 0xc9, 0xbc, 0x0e, 0x70, 0x6a, 0xd8, 0x8e, 0xcb, 0xb8, - 0x59, 0xca, 0xcd, 0x52, 0x0a, 0x65, 0xef, 0x02, 0xc5, 0xc3, 0xb8, 0xc0, 0x74, 0x09, 0xc1, 0x63, - 0x0e, 0x8d, 0xee, 0x17, 0x8c, 0x99, 0x63, 0x4c, 0x42, 0xa0, 0xcc, 0x5b, 0xb0, 0xa2, 0x1b, 0x8e, - 0xd5, 0xd7, 0xc6, 0x8c, 0xbf, 0x42, 0xf9, 0x39, 0x4e, 0xa3, 0x22, 0xf7, 0x01, 0x59, 0x36, 0x3e, - 0xc5, 0xb6, 0x8d, 0xf5, 0x4e, 0x5f, 0x1b, 0xf6, 0x46, 0x5a, 0x0f, 0x4b, 0xab, 0x54, 0x70, 0x7d, - 0xc2, 0x39, 0xe1, 0x0c, 0xf4, 0x21, 0xa4, 0x7b, 0x78, 0xa8, 0x63, 0x5b, 0xca, 0xd3, 0x1a, 0xda, - 0x9d, 0x59, 0x43, 0x8f, 0xa9, 0x88, 0xca, 0x45, 0xd1, 0x55, 0x58, 0xc2, 0x03, 0xcd, 0xe8, 0x4b, - 0x6b, 0xd4, 0x2c, 0x5b, 0xa0, 0x22, 0xac, 0x1b, 0x4e, 0x87, 0xfe, 0xee, 0x9c, 0x63, 0xdb, 0x38, - 0x35, 0xb0, 0x2e, 0x89, 0x05, 0x61, 0x3f, 0xa3, 0xae, 0x19, 0x8e, 0x42, 0xe8, 0xcf, 0x39, 0x99, - 0x58, 0xb0, 0xce, 0xcc, 0x21, 0x96, 0xd6, 0x99, 0x05, 0xba, 0xe0, 0x16, 0xe8, 0xef, 0xa9, 0x05, - 0xe4, 0x59, 0x68, 0x12, 0xfa, 0xc4, 0x82, 0x04, 0xcb, 0x5d, 0x73, 0x34, 0x74, 0xed, 0xb1, 0xb4, - 0xc1, 0x8e, 0x31, 0x5f, 0x92, 0xa3, 0xd4, 0x37, 0xbb, 0x5a, 0xdf, 0x70, 0xc7, 0xd2, 0x55, 0x1e, - 0x5d, 0xbe, 0x46, 0x37, 0x21, 0x67, 0x99, 0x8e, 0xab, 0xf5, 0x3b, 0x5d, 0x53, 0xc7, 0xd2, 0x35, - 0xca, 0x06, 0x46, 0x3a, 0x32, 0x75, 0x8c, 0x36, 0x21, 0x6d, 0xe3, 0x9e, 0x61, 0x0e, 0xa5, 0x4d, - 0x76, 0x78, 0xd9, 0x0a, 0xdd, 0x81, 0xbc, 0xe3, 0xda, 0x18, 0xbb, 0x1d, 0x4d, 0xd7, 0x6d, 0xec, - 0x38, 0xd2, 0x16, 0xe5, 0xaf, 0x32, 0x6a, 0x99, 0x11, 0xd1, 0xc7, 0x20, 0x85, 0xaa, 0xab, 0x63, - 0xe3, 0x57, 0x23, 0xc3, 0xc6, 0xba, 0x24, 0xd1, 0x8d, 0x6c, 0x06, 0x2b, 0x49, 0xe5, 0xdc, 0x40, - 0x03, 0xd8, 0x0e, 0x35, 0x80, 0x3f, 0x24, 0x21, 0x47, 0x8e, 0x71, 0xd3, 0x36, 0x4f, 0x8d, 0x3e, - 0x8e, 0xf4, 0x81, 0x40, 0x31, 0x26, 0x2e, 0x2c, 0xc6, 0xe4, 0x85, 0xc5, 0x98, 0xba, 0xa8, 0x18, - 0x97, 0xe6, 0x14, 0x63, 0x7a, 0xd1, 0x62, 0x5c, 0x9e, 0x5f, 0x8c, 0x99, 0xc5, 0x8b, 0xd1, 0x1f, - 0xb8, 0x6c, 0x30, 0x70, 0xd1, 0x56, 0x07, 0x97, 0x6c, 0x75, 0xa1, 0x2e, 0x95, 0xbb, 0x4c, 0x97, - 0x92, 0xff, 0x94, 0x00, 0xe9, 0x99, 0x45, 0x14, 0x7d, 0xc9, 0x23, 0x09, 0xc7, 0x8e, 0x8b, 0xee, - 0x06, 0xd2, 0x42, 0x73, 0xf9, 0x08, 0xbe, 0x7d, 0xb4, 0x6c, 0x2f, 0x89, 0x82, 0xf4, 0x17, 0xc1, - 0x9f, 0xa2, 0x77, 0xfd, 0x29, 0x4a, 0x44, 0x24, 0xa7, 0xe9, 0x7a, 0xd7, 0x9f, 0xae, 0x64, 0x54, - 0x70, 0x92, 0xba, 0xfb, 0xa1, 0xd4, 0xa5, 0x22, 0xb2, 0x81, 0x34, 0x3e, 0x98, 0x99, 0xc6, 0xa5, - 0x88, 0xd2, 0x85, 0x29, 0x4d, 0x2f, 0x9c, 0x52, 0xf9, 0x5f, 0x02, 0x64, 0x49, 0xc8, 0x68, 0xcf, - 0x88, 0x54, 0xfb, 0xa4, 0xfb, 0x24, 0xfc, 0xdd, 0x67, 0x1f, 0xc2, 0x4d, 0x86, 0x46, 0x60, 0x46, - 0xef, 0xf1, 0x17, 0x4c, 0x6a, 0x5e, 0xc1, 0x2c, 0xbd, 0x5d, 0xc1, 0xa4, 0x2f, 0x55, 0x30, 0x0f, - 0x41, 0xa2, 0x28, 0xc7, 0xb5, 0xf1, 0x64, 0xfb, 0x5e, 0xbd, 0xdc, 0x80, 0x14, 0x6d, 0x59, 0xd1, - 0x4a, 0xa1, 0x74, 0xf9, 0x09, 0x6c, 0x32, 0xdd, 0x88, 0x66, 0x38, 0x7e, 0x9e, 0xa5, 0x44, 0x8c, - 0xa5, 0x87, 0xb0, 0x39, 0xad, 0xda, 0x80, 0xa5, 0x82, 0x17, 0xf9, 0x28, 0x08, 0xc6, 0x90, 0xff, - 0xcd, 0x33, 0x47, 0x7b, 0xf5, 0xac, 0xcc, 0xb1, 0xae, 0x9f, 0x98, 0xdb, 0xf5, 0x93, 0xb3, 0xbb, - 0xfe, 0xff, 0x6f, 0xee, 0x1e, 0xf8, 0xa3, 0x46, 0x41, 0x7b, 0x51, 0xbb, 0xe9, 0xed, 0x9a, 0x45, - 0x2d, 0xfb, 0xed, 0xa3, 0xb4, 0x9d, 0x12, 0x05, 0xe9, 0x2a, 0x0f, 0x80, 0xfc, 0xb1, 0x3f, 0x75, - 0x01, 0xd5, 0x79, 0x49, 0xff, 0x6b, 0x82, 0x7d, 0x18, 0xbc, 0xcf, 0x4f, 0x38, 0xe0, 0xbe, 0x8f, - 0x64, 0x22, 0xfe, 0x23, 0x99, 0xbc, 0xf8, 0x23, 0x99, 0xba, 0xe0, 0x23, 0xb9, 0x34, 0xe7, 0x23, - 0x99, 0x9e, 0xf5, 0x91, 0xf4, 0x27, 0x71, 0x79, 0x5e, 0x12, 0x33, 0x6f, 0x97, 0xc4, 0xec, 0xa5, - 0x92, 0xf8, 0x0f, 0xc1, 0xdf, 0xb1, 0x39, 0x5e, 0x2f, 0x19, 0xf2, 0x34, 0x98, 0x2c, 0x1f, 0x99, - 0x6f, 0x1f, 0x2d, 0xd9, 0x49, 0x92, 0x8d, 0x49, 0x58, 0xdf, 0xf1, 0x85, 0x35, 0x11, 0x12, 0x9a, - 0x06, 0xf8, 0x6e, 0x30, 0xc0, 0xc9, 0x90, 0xa0, 0x3f, 0xd4, 0x85, 0x49, 0xa8, 0x53, 0x21, 0x29, - 0x2f, 0xe8, 0xa5, 0x48, 0xd0, 0x97, 0x42, 0x92, 0xc1, 0xf0, 0xcb, 0x7b, 0x00, 0x4d, 0x7e, 0x07, - 0xa9, 0x56, 0xc2, 0x25, 0x23, 0x7f, 0x0c, 0x6b, 0x1e, 0xd7, 0xdb, 0xf8, 0x1d, 0xc8, 0x78, 0x97, - 0x96, 0x70, 0x0d, 0x3f, 0x51, 0x27, 0x2c, 0xb9, 0x0f, 0xf9, 0x66, 0xe0, 0x6e, 0x83, 0xee, 0xc1, - 0x8a, 0xd9, 0xd7, 0x3b, 0xf1, 0xca, 0x39, 0xb3, 0xaf, 0x7b, 0x3a, 0x44, 0x7a, 0x88, 0x5f, 0x4f, - 0xa5, 0x13, 0x11, 0xe9, 0x21, 0x7e, 0xed, 0x49, 0xcb, 0x32, 0xac, 0xf0, 0x5e, 0x79, 0xaa, 0x35, - 0x5c, 0x0b, 0x21, 0xff, 0x51, 0xe1, 0xc7, 0xa3, 0x02, 0x2b, 0xb5, 0x51, 0xdf, 0x35, 0x8e, 0xb5, - 0xae, 0x6b, 0xda, 0x0e, 0xfa, 0x08, 0x52, 0x83, 0x53, 0xcd, 0x7b, 0x61, 0x16, 0x66, 0x7e, 0x8a, - 0x7c, 0x0a, 0x2a, 0x95, 0x96, 0x5d, 0xc8, 0xf9, 0x88, 0xe8, 0x7d, 0x48, 0xb9, 0x63, 0x8b, 0x39, - 0xca, 0x1f, 0xee, 0xcd, 0x36, 0x72, 0xaa, 0xb5, 0xc7, 0x16, 0x56, 0xa9, 0x24, 0xfa, 0x30, 0xf8, - 0x4c, 0xbb, 0x3e, 0x5b, 0xe5, 0xb8, 0xec, 0x7f, 0xa5, 0xc9, 0x5f, 0x09, 0x90, 0x67, 0x5b, 0x53, - 0xb1, 0x63, 0x99, 0x43, 0x27, 0xf0, 0xb2, 0x14, 0x02, 0x2f, 0x4b, 0x11, 0x92, 0x23, 0xdb, 0xfb, - 0x1e, 0x92, 0x9f, 0xe4, 0x84, 0x3a, 0xb8, 0x6b, 0x63, 0x97, 0x1f, 0x6e, 0xbe, 0x9a, 0x42, 0x49, - 0x5d, 0x02, 0x8a, 0x0a, 0xf9, 0x46, 0xb5, 0x72, 0x74, 0xd4, 0x37, 0xf0, 0xd0, 0x2d, 0x8f, 0xdc, - 0x33, 0x72, 0x2f, 0xec, 0xd2, 0xd5, 0x14, 0x4b, 0x86, 0x11, 0xaa, 0x3a, 0xba, 0x0d, 0xab, 0x9c, - 0xc9, 0x21, 0x30, 0x5c, 0x2b, 0x8c, 0xd8, 0xa2, 0x34, 0xf9, 0xd7, 0x02, 0x6c, 0xd7, 0xc6, 0x4d, - 0xdb, 0xfc, 0x1c, 0x77, 0xdd, 0x86, 0xdd, 0x6b, 0x61, 0xcd, 0xee, 0x9e, 0x79, 0x15, 0xb7, 0x09, - 0x69, 0xf3, 0xf4, 0xd4, 0xc1, 0x2e, 0x35, 0x9e, 0x52, 0xf9, 0x8a, 0x7c, 0x40, 0xfa, 0xc6, 0xc0, - 0x60, 0x26, 0x53, 0x2a, 0x5b, 0x90, 0xed, 0x6b, 0x4e, 0x97, 0x6e, 0x29, 0xa3, 0x92, 0x9f, 0xe8, - 0x18, 0x96, 0x5f, 0x8d, 0xb0, 0x6d, 0x60, 0x72, 0x18, 0x48, 0xae, 0xef, 0xcd, 0xde, 0x68, 0x04, - 0xc0, 0xa7, 0x23, 0x6c, 0x8f, 0x55, 0x4f, 0x59, 0xfe, 0xbd, 0x00, 0x5b, 0x31, 0x42, 0xe8, 0x18, - 0x92, 0x5f, 0xe0, 0x31, 0x2f, 0x83, 0xe2, 0x82, 0xf6, 0x9f, 0xe2, 0x31, 0x3d, 0x98, 0x6f, 0x84, - 0x44, 0xe1, 0x8a, 0x4a, 0x0c, 0xa0, 0x07, 0x90, 0x1e, 0x60, 0xf7, 0xcc, 0xd4, 0x79, 0x79, 0xdc, - 0x9a, 0x69, 0x8a, 0xa9, 0xd7, 0xa8, 0xa0, 0xca, 0x15, 0x48, 0x38, 0xce, 0xb5, 0xfe, 0xc8, 0xbb, - 0xd5, 0xb3, 0x85, 0xfc, 0x2b, 0x01, 0x76, 0x66, 0x85, 0x96, 0x57, 0xd1, 0xe5, 0x62, 0x7b, 0x0b, - 0x56, 0x5c, 0x93, 0x74, 0x2a, 0x1b, 0x3b, 0xa3, 0x3e, 0x2b, 0xa7, 0x94, 0x9a, 0xa3, 0x34, 0x95, - 0x92, 0xd0, 0xfb, 0xa4, 0x45, 0x51, 0x66, 0x8a, 0xc6, 0x5a, 0x9a, 0xb9, 0x81, 0x86, 0xdd, 0x53, - 0xb9, 0x9c, 0x7c, 0x0f, 0xd6, 0xaa, 0x4e, 0x59, 0x1f, 0x18, 0xc3, 0x09, 0xaa, 0x6d, 0xc8, 0x18, - 0x4e, 0x47, 0x23, 0x34, 0x8a, 0x2b, 0xa3, 0x2e, 0x1b, 0x4c, 0x44, 0xbe, 0x0b, 0xc9, 0x86, 0xdd, - 0x8b, 0x7c, 0xdb, 0x10, 0xa4, 0x7c, 0xef, 0x1d, 0xfa, 0x5b, 0xfe, 0x00, 0x56, 0x6b, 0xe3, 0x26, - 0xb6, 0x07, 0x06, 0x9b, 0x08, 0xa1, 0x02, 0xe4, 0xac, 0xe9, 0x92, 0x1e, 0xfc, 0xac, 0xea, 0x27, - 0x15, 0xed, 0xc0, 0x48, 0x8a, 0x8d, 0x70, 0x0a, 0xb0, 0xf7, 0xac, 0xa5, 0xa8, 0x2d, 0xa5, 0xd5, - 0xaa, 0x36, 0xea, 0xad, 0x76, 0xb9, 0xad, 0x74, 0x9e, 0xd5, 0x5b, 0x4d, 0xe5, 0xa8, 0x7a, 0x5c, - 0x55, 0x2a, 0xe2, 0x15, 0xb4, 0x0b, 0x5b, 0x11, 0x89, 0xf2, 0x51, 0xbb, 0xfa, 0x5c, 0x11, 0x05, - 0x74, 0x13, 0x76, 0x23, 0xcc, 0xb6, 0xa2, 0xd6, 0xaa, 0xf5, 0x72, 0x5b, 0xa9, 0x88, 0x89, 0xe2, - 0x2b, 0x10, 0xc9, 0x81, 0xf2, 0x36, 0x4f, 0x5a, 0x05, 0xda, 0x86, 0x6b, 0x94, 0xa6, 0xb4, 0x9a, - 0x8d, 0x7a, 0x4b, 0x69, 0xbf, 0x68, 0x2a, 0x9d, 0xa3, 0x46, 0x45, 0x11, 0xaf, 0xa0, 0xeb, 0xb0, - 0x1d, 0x61, 0x55, 0x2b, 0x9d, 0x76, 0xe3, 0xa9, 0x52, 0x17, 0x05, 0x74, 0x1b, 0x6e, 0xc6, 0xb2, - 0xb9, 0x50, 0xa2, 0xf8, 0x5b, 0x7e, 0x31, 0x63, 0x1b, 0xdc, 0x81, 0x4d, 0x8a, 0xd0, 0xbf, 0x33, - 0x85, 0x6f, 0xed, 0x2a, 0x88, 0x53, 0xde, 0x64, 0x4f, 0x9b, 0x80, 0xa6, 0xd4, 0x6a, 0x9d, 0xd3, - 0x13, 0xe8, 0x1a, 0xac, 0x4f, 0xe9, 0x15, 0xe5, 0x44, 0x21, 0x3b, 0x4c, 0x06, 0x8d, 0x9c, 0x34, - 0x8e, 0x9e, 0x2a, 0x15, 0x31, 0x15, 0x14, 0x6e, 0x3d, 0x6b, 0x35, 0x95, 0x7a, 0x45, 0x5c, 0x0a, - 0x92, 0xab, 0xf5, 0x6a, 0xbb, 0x5a, 0x3e, 0x11, 0xd3, 0xc5, 0x1f, 0x42, 0x9a, 0xbd, 0x0b, 0x88, - 0xf3, 0xc7, 0x4a, 0xbd, 0xa2, 0xa8, 0xa1, 0x2c, 0xac, 0xc3, 0x2a, 0xa7, 0x1f, 0x2b, 0xb5, 0xf2, - 0x09, 0xc1, 0xb9, 0x06, 0x39, 0x4e, 0xa2, 0x84, 0x04, 0x42, 0x90, 0xe7, 0x84, 0x4a, 0xf5, 0x39, - 0x49, 0x8a, 0x98, 0x2c, 0x56, 0x60, 0x99, 0x77, 0x68, 0xb4, 0x05, 0x1b, 0xb5, 0xe3, 0x32, 0x8d, - 0x59, 0xd0, 0xf6, 0x1a, 0xe4, 0x3c, 0x46, 0xab, 0xd6, 0x62, 0x96, 0x3d, 0x42, 0xa3, 0xdd, 0x14, - 0x13, 0xc5, 0x53, 0xc8, 0x78, 0x9d, 0x12, 0x49, 0x70, 0x95, 0xfc, 0x9e, 0x51, 0x29, 0x9b, 0x80, - 0x26, 0x9c, 0x7a, 0xa3, 0xdd, 0x51, 0x95, 0x72, 0xe5, 0x85, 0x28, 0x10, 0x5c, 0x13, 0x3a, 0xa3, - 0x25, 0x48, 0xd4, 0x7c, 0xb4, 0x5a, 0xe3, 0x39, 0x89, 0x65, 0xf1, 0x25, 0x5c, 0x9b, 0xd9, 0x48, - 0xd0, 0x1d, 0xb8, 0x55, 0x7b, 0xd1, 0x54, 0x1b, 0xdf, 0x57, 0x8e, 0xda, 0x0d, 0xf5, 0x71, 0x4b, - 0x29, 0xab, 0x47, 0x4f, 0x9e, 0x2a, 0x2f, 0x42, 0x08, 0x64, 0xb8, 0x31, 0x5b, 0xac, 0xa1, 0x3e, - 0xee, 0xd4, 0xcb, 0x35, 0x45, 0x14, 0x8a, 0x3f, 0x86, 0x15, 0x7f, 0x87, 0x21, 0x61, 0x61, 0x72, - 0x35, 0xa5, 0xfd, 0xa4, 0x51, 0xe9, 0x28, 0x9f, 0x3e, 0x2b, 0x9f, 0xb4, 0xc4, 0x2b, 0x68, 0x0f, - 0xa4, 0x00, 0xa3, 0xd5, 0x2e, 0xab, 0xed, 0x56, 0xe7, 0x07, 0xd5, 0xf6, 0x13, 0x51, 0x20, 0x45, - 0x1c, 0xe0, 0x1e, 0x35, 0xea, 0xed, 0x72, 0xb5, 0xde, 0x12, 0x13, 0x87, 0xbf, 0x91, 0x20, 0x47, - 0xbe, 0x1d, 0x2d, 0x6c, 0x9f, 0x1b, 0x5d, 0x8c, 0x9e, 0xc2, 0xf2, 0x13, 0xac, 0xf5, 0xdd, 0xb3, - 0x2f, 0xd1, 0x66, 0xe4, 0x76, 0xa6, 0x0c, 0x2c, 0x77, 0xbc, 0x13, 0x43, 0x97, 0xc5, 0x37, 0x7f, - 0xfb, 0xe7, 0x2f, 0x12, 0x80, 0x32, 0xa5, 0x33, 0x6e, 0xe1, 0x31, 0x2c, 0xa9, 0x58, 0xd3, 0xc7, - 0x97, 0x36, 0x95, 0xa7, 0xa6, 0x32, 0x28, 0x5d, 0xb2, 0xa9, 0x7e, 0x1d, 0x32, 0xcf, 0xf9, 0xe8, - 0x3b, 0xd6, 0xd6, 0x56, 0x84, 0xde, 0xa2, 0x53, 0x76, 0x79, 0x9d, 0x1a, 0xcb, 0xa1, 0xec, 0x64, - 0x7c, 0x8e, 0x7e, 0x02, 0xeb, 0x8f, 0xb1, 0xcb, 0x9e, 0x73, 0xde, 0x98, 0x3a, 0xd6, 0xf0, 0x9d, - 0x45, 0x46, 0xde, 0x8e, 0xfc, 0xde, 0x9b, 0x3f, 0x4a, 0x6b, 0xb0, 0x4a, 0x64, 0xf0, 0xd0, 0x35, - 0xba, 0x9a, 0x8b, 0x75, 0xea, 0x19, 0x21, 0xb1, 0x34, 0xc0, 0x25, 0x72, 0x29, 0xf0, 0x86, 0xe9, - 0xe8, 0x4b, 0x10, 0x27, 0x00, 0xbc, 0xf1, 0x51, 0x9c, 0xff, 0x42, 0xac, 0x7f, 0xae, 0x29, 0xdf, - 0x8b, 0x73, 0xbd, 0x81, 0xd6, 0x99, 0x5f, 0x02, 0xc0, 0xe2, 0x7e, 0x7e, 0x29, 0xc0, 0x06, 0xbb, - 0x4d, 0x07, 0xfd, 0xdf, 0x9f, 0xed, 0x27, 0x66, 0x52, 0xb2, 0x00, 0xac, 0x52, 0x1c, 0xac, 0xcd, - 0x9d, 0x28, 0xac, 0x87, 0x42, 0x11, 0xb9, 0x90, 0x9f, 0x44, 0x85, 0x0d, 0x19, 0xe2, 0x62, 0x12, - 0x3f, 0x53, 0xa7, 0x7a, 0x72, 0x31, 0xce, 0xf5, 0x3a, 0x5a, 0x9b, 0xba, 0x66, 0x23, 0x8a, 0xaf, - 0x05, 0x58, 0x67, 0x37, 0x63, 0xbf, 0xe7, 0xf7, 0xe6, 0x44, 0xc3, 0xff, 0x02, 0x9f, 0x0b, 0xe7, - 0x7e, 0x1c, 0x9c, 0xab, 0x3b, 0x61, 0x38, 0x24, 0x0e, 0x3f, 0x17, 0x60, 0x3d, 0x32, 0x71, 0x88, - 0xc9, 0x4f, 0xdc, 0x64, 0x22, 0xf6, 0x6c, 0x7d, 0x27, 0x0e, 0xcb, 0x9e, 0xbc, 0x15, 0xc2, 0x52, - 0x62, 0x0f, 0xff, 0x31, 0xc1, 0xf4, 0x8d, 0x00, 0xd7, 0x55, 0xec, 0xe0, 0xa1, 0x5e, 0x1b, 0xfb, - 0x06, 0x37, 0x5d, 0xfa, 0xc4, 0xab, 0x5d, 0x94, 0xab, 0x38, 0x20, 0xe5, 0x38, 0x20, 0xfb, 0xf2, - 0xed, 0x08, 0x10, 0x9b, 0xba, 0x3e, 0xf7, 0xf9, 0x0c, 0x17, 0x0c, 0x9b, 0x6d, 0x5c, 0xbe, 0x60, - 0xa8, 0xde, 0x82, 0x05, 0xc3, 0x26, 0x23, 0xe1, 0x82, 0x61, 0x9e, 0xe7, 0x15, 0x8c, 0x7f, 0x82, - 0x30, 0x17, 0xce, 0x62, 0x05, 0x43, 0xe1, 0x90, 0x38, 0x7c, 0x1d, 0x2a, 0x98, 0x8b, 0x10, 0xcd, - 0x9e, 0x69, 0xbc, 0x65, 0xb9, 0x50, 0x24, 0x71, 0xe5, 0xe2, 0x9b, 0x15, 0xb1, 0xd4, 0xb1, 0x69, - 0xc5, 0xff, 0xa4, 0x5c, 0x38, 0x90, 0xd9, 0xe5, 0xe2, 0xef, 0xba, 0xde, 0xd4, 0xe3, 0xf2, 0x5d, - 0xd7, 0x7b, 0xb0, 0x2f, 0xd6, 0x75, 0xf9, 0xeb, 0x3f, 0xd2, 0x75, 0x3d, 0xff, 0xf3, 0xba, 0x6e, - 0x70, 0xda, 0xb1, 0x00, 0xac, 0xc5, 0xba, 0x2e, 0x87, 0x45, 0xa2, 0xf2, 0x0a, 0xb2, 0x34, 0x2a, - 0xb5, 0x53, 0x2d, 0x3e, 0x1c, 0xb7, 0xe6, 0xbd, 0xca, 0x1d, 0xf9, 0x6e, 0x9c, 0x63, 0x11, 0xe5, - 0xa7, 0x8e, 0xc9, 0xdb, 0x1d, 0xfd, 0x4c, 0x00, 0xd1, 0x3b, 0x41, 0x93, 0x41, 0xc3, 0xed, 0x99, - 0x2e, 0x82, 0xb3, 0x8b, 0xd8, 0xea, 0x78, 0x10, 0xe7, 0xbc, 0xb0, 0xb3, 0xeb, 0xab, 0x0e, 0x6e, - 0xcc, 0x29, 0xf1, 0xff, 0x06, 0x22, 0xfb, 0x1f, 0x43, 0xb6, 0xac, 0xeb, 0xe4, 0x51, 0xdf, 0x6e, - 0xc6, 0xee, 0xff, 0x76, 0xdc, 0x40, 0xc1, 0x37, 0x09, 0xb8, 0x20, 0xf4, 0xf2, 0x7a, 0x20, 0x02, - 0x25, 0xd3, 0xb5, 0x88, 0xeb, 0x37, 0x82, 0x7f, 0x5c, 0xd2, 0x6e, 0xa2, 0x5b, 0x17, 0xf5, 0x78, - 0xea, 0x2c, 0x36, 0x02, 0xdf, 0x8d, 0x73, 0x7e, 0x63, 0x67, 0x3b, 0xe2, 0xdc, 0x7f, 0x54, 0xfb, - 0xb0, 0xa2, 0xe2, 0x81, 0x79, 0x8e, 0xe7, 0x84, 0x20, 0xce, 0x71, 0xfc, 0x39, 0x28, 0x46, 0x77, - 0x8d, 0x7e, 0x27, 0xc0, 0x06, 0xbf, 0xd3, 0xfa, 0x6e, 0xcf, 0x0e, 0x3a, 0x58, 0xf0, 0xa9, 0xee, - 0x1d, 0x84, 0xd2, 0xc2, 0xf2, 0x3c, 0x39, 0xf1, 0x15, 0x22, 0xef, 0x96, 0x7a, 0x7d, 0xf3, 0xa5, - 0xd6, 0x27, 0x77, 0x11, 0xa2, 0x6c, 0xda, 0x3d, 0xa7, 0xd4, 0x71, 0xa8, 0x3e, 0xeb, 0x1b, 0x50, - 0x75, 0xaa, 0xda, 0x80, 0x3e, 0x7c, 0x63, 0xe3, 0x33, 0xfb, 0x4f, 0x23, 0x42, 0x2f, 0x6a, 0xf9, - 0x20, 0x0e, 0xc6, 0x35, 0xb4, 0xe1, 0xc1, 0xe8, 0x18, 0x8e, 0xa1, 0x0d, 0xe8, 0xab, 0x1b, 0xfd, - 0x54, 0x80, 0x2d, 0x7a, 0x3c, 0x3f, 0x63, 0xc6, 0xfd, 0xcf, 0xe8, 0x38, 0x24, 0x72, 0x5c, 0x6c, - 0xa6, 0xba, 0xf2, 0x61, 0x1c, 0x8e, 0x6d, 0xb4, 0x55, 0xf2, 0xbd, 0xc4, 0x4b, 0xdc, 0x54, 0x69, - 0x80, 0x1f, 0xfd, 0x59, 0xf8, 0xa6, 0xfc, 0x95, 0x80, 0x3e, 0x81, 0x0c, 0x79, 0x32, 0x14, 0xca, - 0xcd, 0xaa, 0x5c, 0x44, 0xfb, 0x67, 0xae, 0x6b, 0x39, 0x0f, 0x4b, 0xa5, 0x9e, 0xe1, 0x9e, 0x8d, - 0x5e, 0x1e, 0x74, 0xcd, 0x41, 0xa9, 0xab, 0x99, 0x53, 0x45, 0xeb, 0x8b, 0x5e, 0x89, 0xb8, 0x39, - 0x4c, 0xbe, 0x7f, 0xf0, 0x41, 0x51, 0x48, 0x1c, 0x8a, 0x9a, 0x65, 0xf5, 0x79, 0x5b, 0x2e, 0x7d, - 0xee, 0x98, 0xc3, 0x20, 0xa5, 0x67, 0x5b, 0xdd, 0x87, 0x11, 0x99, 0x87, 0x11, 0x99, 0xcf, 0xee, - 0xce, 0xf3, 0x48, 0xff, 0x56, 0x87, 0x88, 0xbe, 0x4c, 0xd3, 0x08, 0x7d, 0xf8, 0xdf, 0x00, 0x00, - 0x00, 0xff, 0xff, 0x64, 0x6c, 0xef, 0xe7, 0xe6, 0x23, 0x00, 0x00, +func file_auth_proto_rawDescGZIP() []byte { + file_auth_proto_rawDescOnce.Do(func() { + file_auth_proto_rawDescData = protoimpl.X.CompressGZIP(file_auth_proto_rawDescData) + }) + return file_auth_proto_rawDescData +} + +var file_auth_proto_enumTypes = make([]protoimpl.EnumInfo, 9) +var file_auth_proto_msgTypes = make([]protoimpl.MessageInfo, 31) +var file_auth_proto_goTypes = []interface{}{ + (UserSessionState)(0), // 0: zitadel.auth.api.v1.UserSessionState + (OIDCResponseType)(0), // 1: zitadel.auth.api.v1.OIDCResponseType + (UserState)(0), // 2: zitadel.auth.api.v1.UserState + (Gender)(0), // 3: zitadel.auth.api.v1.Gender + (MfaType)(0), // 4: zitadel.auth.api.v1.MfaType + (MFAState)(0), // 5: zitadel.auth.api.v1.MFAState + (UserGrantSearchKey)(0), // 6: zitadel.auth.api.v1.UserGrantSearchKey + (MyProjectOrgSearchKey)(0), // 7: zitadel.auth.api.v1.MyProjectOrgSearchKey + (SearchMethod)(0), // 8: zitadel.auth.api.v1.SearchMethod + (*UserSessionViews)(nil), // 9: zitadel.auth.api.v1.UserSessionViews + (*UserSessionView)(nil), // 10: zitadel.auth.api.v1.UserSessionView + (*User)(nil), // 11: zitadel.auth.api.v1.User + (*UserProfile)(nil), // 12: zitadel.auth.api.v1.UserProfile + (*UpdateUserProfileRequest)(nil), // 13: zitadel.auth.api.v1.UpdateUserProfileRequest + (*UserEmail)(nil), // 14: zitadel.auth.api.v1.UserEmail + (*VerifyMyUserEmailRequest)(nil), // 15: zitadel.auth.api.v1.VerifyMyUserEmailRequest + (*VerifyUserEmailRequest)(nil), // 16: zitadel.auth.api.v1.VerifyUserEmailRequest + (*UpdateUserEmailRequest)(nil), // 17: zitadel.auth.api.v1.UpdateUserEmailRequest + (*UserPhone)(nil), // 18: zitadel.auth.api.v1.UserPhone + (*UpdateUserPhoneRequest)(nil), // 19: zitadel.auth.api.v1.UpdateUserPhoneRequest + (*VerifyUserPhoneRequest)(nil), // 20: zitadel.auth.api.v1.VerifyUserPhoneRequest + (*UserAddress)(nil), // 21: zitadel.auth.api.v1.UserAddress + (*UpdateUserAddressRequest)(nil), // 22: zitadel.auth.api.v1.UpdateUserAddressRequest + (*PasswordID)(nil), // 23: zitadel.auth.api.v1.PasswordID + (*PasswordRequest)(nil), // 24: zitadel.auth.api.v1.PasswordRequest + (*PasswordChange)(nil), // 25: zitadel.auth.api.v1.PasswordChange + (*VerifyMfaOtp)(nil), // 26: zitadel.auth.api.v1.VerifyMfaOtp + (*MultiFactors)(nil), // 27: zitadel.auth.api.v1.MultiFactors + (*MultiFactor)(nil), // 28: zitadel.auth.api.v1.MultiFactor + (*MfaOtpResponse)(nil), // 29: zitadel.auth.api.v1.MfaOtpResponse + (*OIDCClientAuth)(nil), // 30: zitadel.auth.api.v1.OIDCClientAuth + (*UserGrantSearchRequest)(nil), // 31: zitadel.auth.api.v1.UserGrantSearchRequest + (*UserGrantSearchQuery)(nil), // 32: zitadel.auth.api.v1.UserGrantSearchQuery + (*UserGrantSearchResponse)(nil), // 33: zitadel.auth.api.v1.UserGrantSearchResponse + (*UserGrantView)(nil), // 34: zitadel.auth.api.v1.UserGrantView + (*MyProjectOrgSearchRequest)(nil), // 35: zitadel.auth.api.v1.MyProjectOrgSearchRequest + (*MyProjectOrgSearchQuery)(nil), // 36: zitadel.auth.api.v1.MyProjectOrgSearchQuery + (*MyProjectOrgSearchResponse)(nil), // 37: zitadel.auth.api.v1.MyProjectOrgSearchResponse + (*Org)(nil), // 38: zitadel.auth.api.v1.Org + (*MyPermissions)(nil), // 39: zitadel.auth.api.v1.MyPermissions + (*timestamp.Timestamp)(nil), // 40: google.protobuf.Timestamp + (*empty.Empty)(nil), // 41: google.protobuf.Empty + (*_struct.Struct)(nil), // 42: google.protobuf.Struct +} +var file_auth_proto_depIdxs = []int32{ + 10, // 0: zitadel.auth.api.v1.UserSessionViews.user_sessions:type_name -> zitadel.auth.api.v1.UserSessionView + 0, // 1: zitadel.auth.api.v1.UserSessionView.auth_state:type_name -> zitadel.auth.api.v1.UserSessionState + 2, // 2: zitadel.auth.api.v1.User.state:type_name -> zitadel.auth.api.v1.UserState + 40, // 3: zitadel.auth.api.v1.User.creation_date:type_name -> google.protobuf.Timestamp + 40, // 4: zitadel.auth.api.v1.User.activation_date:type_name -> google.protobuf.Timestamp + 40, // 5: zitadel.auth.api.v1.User.change_date:type_name -> google.protobuf.Timestamp + 40, // 6: zitadel.auth.api.v1.User.last_login:type_name -> google.protobuf.Timestamp + 40, // 7: zitadel.auth.api.v1.User.password_changed:type_name -> google.protobuf.Timestamp + 3, // 8: zitadel.auth.api.v1.User.gender:type_name -> zitadel.auth.api.v1.Gender + 3, // 9: zitadel.auth.api.v1.UserProfile.gender:type_name -> zitadel.auth.api.v1.Gender + 40, // 10: zitadel.auth.api.v1.UserProfile.creation_date:type_name -> google.protobuf.Timestamp + 40, // 11: zitadel.auth.api.v1.UserProfile.change_date:type_name -> google.protobuf.Timestamp + 3, // 12: zitadel.auth.api.v1.UpdateUserProfileRequest.gender:type_name -> zitadel.auth.api.v1.Gender + 40, // 13: zitadel.auth.api.v1.UserEmail.creation_date:type_name -> google.protobuf.Timestamp + 40, // 14: zitadel.auth.api.v1.UserEmail.change_date:type_name -> google.protobuf.Timestamp + 40, // 15: zitadel.auth.api.v1.UserPhone.creation_date:type_name -> google.protobuf.Timestamp + 40, // 16: zitadel.auth.api.v1.UserPhone.change_date:type_name -> google.protobuf.Timestamp + 40, // 17: zitadel.auth.api.v1.UserAddress.creation_date:type_name -> google.protobuf.Timestamp + 40, // 18: zitadel.auth.api.v1.UserAddress.change_date:type_name -> google.protobuf.Timestamp + 28, // 19: zitadel.auth.api.v1.MultiFactors.mfas:type_name -> zitadel.auth.api.v1.MultiFactor + 4, // 20: zitadel.auth.api.v1.MultiFactor.type:type_name -> zitadel.auth.api.v1.MfaType + 5, // 21: zitadel.auth.api.v1.MultiFactor.state:type_name -> zitadel.auth.api.v1.MFAState + 5, // 22: zitadel.auth.api.v1.MfaOtpResponse.state:type_name -> zitadel.auth.api.v1.MFAState + 6, // 23: zitadel.auth.api.v1.UserGrantSearchRequest.sorting_column:type_name -> zitadel.auth.api.v1.UserGrantSearchKey + 32, // 24: zitadel.auth.api.v1.UserGrantSearchRequest.queries:type_name -> zitadel.auth.api.v1.UserGrantSearchQuery + 6, // 25: zitadel.auth.api.v1.UserGrantSearchQuery.key:type_name -> zitadel.auth.api.v1.UserGrantSearchKey + 8, // 26: zitadel.auth.api.v1.UserGrantSearchQuery.method:type_name -> zitadel.auth.api.v1.SearchMethod + 34, // 27: zitadel.auth.api.v1.UserGrantSearchResponse.result:type_name -> zitadel.auth.api.v1.UserGrantView + 36, // 28: zitadel.auth.api.v1.MyProjectOrgSearchRequest.queries:type_name -> zitadel.auth.api.v1.MyProjectOrgSearchQuery + 7, // 29: zitadel.auth.api.v1.MyProjectOrgSearchQuery.key:type_name -> zitadel.auth.api.v1.MyProjectOrgSearchKey + 8, // 30: zitadel.auth.api.v1.MyProjectOrgSearchQuery.method:type_name -> zitadel.auth.api.v1.SearchMethod + 38, // 31: zitadel.auth.api.v1.MyProjectOrgSearchResponse.result:type_name -> zitadel.auth.api.v1.Org + 41, // 32: zitadel.auth.api.v1.AuthService.Healthz:input_type -> google.protobuf.Empty + 41, // 33: zitadel.auth.api.v1.AuthService.Ready:input_type -> google.protobuf.Empty + 41, // 34: zitadel.auth.api.v1.AuthService.Validate:input_type -> google.protobuf.Empty + 41, // 35: zitadel.auth.api.v1.AuthService.GetMyUserSessions:input_type -> google.protobuf.Empty + 41, // 36: zitadel.auth.api.v1.AuthService.GetMyUserProfile:input_type -> google.protobuf.Empty + 13, // 37: zitadel.auth.api.v1.AuthService.UpdateMyUserProfile:input_type -> zitadel.auth.api.v1.UpdateUserProfileRequest + 41, // 38: zitadel.auth.api.v1.AuthService.GetMyUserEmail:input_type -> google.protobuf.Empty + 17, // 39: zitadel.auth.api.v1.AuthService.ChangeMyUserEmail:input_type -> zitadel.auth.api.v1.UpdateUserEmailRequest + 15, // 40: zitadel.auth.api.v1.AuthService.VerifyMyUserEmail:input_type -> zitadel.auth.api.v1.VerifyMyUserEmailRequest + 41, // 41: zitadel.auth.api.v1.AuthService.ResendMyEmailVerificationMail:input_type -> google.protobuf.Empty + 41, // 42: zitadel.auth.api.v1.AuthService.GetMyUserPhone:input_type -> google.protobuf.Empty + 19, // 43: zitadel.auth.api.v1.AuthService.ChangeMyUserPhone:input_type -> zitadel.auth.api.v1.UpdateUserPhoneRequest + 20, // 44: zitadel.auth.api.v1.AuthService.VerifyMyUserPhone:input_type -> zitadel.auth.api.v1.VerifyUserPhoneRequest + 41, // 45: zitadel.auth.api.v1.AuthService.ResendMyPhoneVerificationCode:input_type -> google.protobuf.Empty + 41, // 46: zitadel.auth.api.v1.AuthService.GetMyUserAddress:input_type -> google.protobuf.Empty + 22, // 47: zitadel.auth.api.v1.AuthService.UpdateMyUserAddress:input_type -> zitadel.auth.api.v1.UpdateUserAddressRequest + 41, // 48: zitadel.auth.api.v1.AuthService.GetMyMfas:input_type -> google.protobuf.Empty + 25, // 49: zitadel.auth.api.v1.AuthService.ChangeMyPassword:input_type -> zitadel.auth.api.v1.PasswordChange + 41, // 50: zitadel.auth.api.v1.AuthService.AddMfaOTP:input_type -> google.protobuf.Empty + 26, // 51: zitadel.auth.api.v1.AuthService.VerifyMfaOTP:input_type -> zitadel.auth.api.v1.VerifyMfaOtp + 41, // 52: zitadel.auth.api.v1.AuthService.RemoveMfaOTP:input_type -> google.protobuf.Empty + 31, // 53: zitadel.auth.api.v1.AuthService.SearchMyUserGrant:input_type -> zitadel.auth.api.v1.UserGrantSearchRequest + 35, // 54: zitadel.auth.api.v1.AuthService.SearchMyProjectOrgs:input_type -> zitadel.auth.api.v1.MyProjectOrgSearchRequest + 41, // 55: zitadel.auth.api.v1.AuthService.GetMyZitadelPermissions:input_type -> google.protobuf.Empty + 41, // 56: zitadel.auth.api.v1.AuthService.Healthz:output_type -> google.protobuf.Empty + 41, // 57: zitadel.auth.api.v1.AuthService.Ready:output_type -> google.protobuf.Empty + 42, // 58: zitadel.auth.api.v1.AuthService.Validate:output_type -> google.protobuf.Struct + 9, // 59: zitadel.auth.api.v1.AuthService.GetMyUserSessions:output_type -> zitadel.auth.api.v1.UserSessionViews + 12, // 60: zitadel.auth.api.v1.AuthService.GetMyUserProfile:output_type -> zitadel.auth.api.v1.UserProfile + 12, // 61: zitadel.auth.api.v1.AuthService.UpdateMyUserProfile:output_type -> zitadel.auth.api.v1.UserProfile + 14, // 62: zitadel.auth.api.v1.AuthService.GetMyUserEmail:output_type -> zitadel.auth.api.v1.UserEmail + 14, // 63: zitadel.auth.api.v1.AuthService.ChangeMyUserEmail:output_type -> zitadel.auth.api.v1.UserEmail + 41, // 64: zitadel.auth.api.v1.AuthService.VerifyMyUserEmail:output_type -> google.protobuf.Empty + 41, // 65: zitadel.auth.api.v1.AuthService.ResendMyEmailVerificationMail:output_type -> google.protobuf.Empty + 18, // 66: zitadel.auth.api.v1.AuthService.GetMyUserPhone:output_type -> zitadel.auth.api.v1.UserPhone + 18, // 67: zitadel.auth.api.v1.AuthService.ChangeMyUserPhone:output_type -> zitadel.auth.api.v1.UserPhone + 41, // 68: zitadel.auth.api.v1.AuthService.VerifyMyUserPhone:output_type -> google.protobuf.Empty + 41, // 69: zitadel.auth.api.v1.AuthService.ResendMyPhoneVerificationCode:output_type -> google.protobuf.Empty + 21, // 70: zitadel.auth.api.v1.AuthService.GetMyUserAddress:output_type -> zitadel.auth.api.v1.UserAddress + 21, // 71: zitadel.auth.api.v1.AuthService.UpdateMyUserAddress:output_type -> zitadel.auth.api.v1.UserAddress + 27, // 72: zitadel.auth.api.v1.AuthService.GetMyMfas:output_type -> zitadel.auth.api.v1.MultiFactors + 41, // 73: zitadel.auth.api.v1.AuthService.ChangeMyPassword:output_type -> google.protobuf.Empty + 29, // 74: zitadel.auth.api.v1.AuthService.AddMfaOTP:output_type -> zitadel.auth.api.v1.MfaOtpResponse + 41, // 75: zitadel.auth.api.v1.AuthService.VerifyMfaOTP:output_type -> google.protobuf.Empty + 41, // 76: zitadel.auth.api.v1.AuthService.RemoveMfaOTP:output_type -> google.protobuf.Empty + 33, // 77: zitadel.auth.api.v1.AuthService.SearchMyUserGrant:output_type -> zitadel.auth.api.v1.UserGrantSearchResponse + 37, // 78: zitadel.auth.api.v1.AuthService.SearchMyProjectOrgs:output_type -> zitadel.auth.api.v1.MyProjectOrgSearchResponse + 39, // 79: zitadel.auth.api.v1.AuthService.GetMyZitadelPermissions:output_type -> zitadel.auth.api.v1.MyPermissions + 56, // [56:80] is the sub-list for method output_type + 32, // [32:56] is the sub-list for method input_type + 32, // [32:32] is the sub-list for extension type_name + 32, // [32:32] is the sub-list for extension extendee + 0, // [0:32] is the sub-list for field type_name +} + +func init() { file_auth_proto_init() } +func file_auth_proto_init() { + if File_auth_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_auth_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserSessionViews); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserSessionView); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*User); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserProfile); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserProfileRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserEmail); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyMyUserEmailRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyUserEmailRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserEmailRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserPhone); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserPhoneRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyUserPhoneRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserAddress); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UpdateUserAddressRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PasswordID); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PasswordRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*PasswordChange); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*VerifyMfaOtp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MultiFactors); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MultiFactor); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MfaOtpResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*OIDCClientAuth); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserGrantSearchRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserGrantSearchQuery); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserGrantSearchResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*UserGrantView); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MyProjectOrgSearchRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MyProjectOrgSearchQuery); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MyProjectOrgSearchResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Org); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_auth_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*MyPermissions); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_auth_proto_rawDesc, + NumEnums: 9, + NumMessages: 31, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_auth_proto_goTypes, + DependencyIndexes: file_auth_proto_depIdxs, + EnumInfos: file_auth_proto_enumTypes, + MessageInfos: file_auth_proto_msgTypes, + }.Build() + File_auth_proto = out.File + file_auth_proto_rawDesc = nil + file_auth_proto_goTypes = nil + file_auth_proto_depIdxs = nil } // Reference imports to suppress errors if they are not otherwise used. @@ -2275,8 +3944,8 @@ type AuthServiceClient interface { AddMfaOTP(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*MfaOtpResponse, error) VerifyMfaOTP(ctx context.Context, in *VerifyMfaOtp, opts ...grpc.CallOption) (*empty.Empty, error) RemoveMfaOTP(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*empty.Empty, error) + SearchMyUserGrant(ctx context.Context, in *UserGrantSearchRequest, opts ...grpc.CallOption) (*UserGrantSearchResponse, error) SearchMyProjectOrgs(ctx context.Context, in *MyProjectOrgSearchRequest, opts ...grpc.CallOption) (*MyProjectOrgSearchResponse, error) - IsIamAdmin(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*IsAdminResponse, error) //Permission GetMyZitadelPermissions(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*MyPermissions, error) } @@ -2478,18 +4147,18 @@ func (c *authServiceClient) RemoveMfaOTP(ctx context.Context, in *empty.Empty, o return out, nil } -func (c *authServiceClient) SearchMyProjectOrgs(ctx context.Context, in *MyProjectOrgSearchRequest, opts ...grpc.CallOption) (*MyProjectOrgSearchResponse, error) { - out := new(MyProjectOrgSearchResponse) - err := c.cc.Invoke(ctx, "/zitadel.auth.api.v1.AuthService/SearchMyProjectOrgs", in, out, opts...) +func (c *authServiceClient) SearchMyUserGrant(ctx context.Context, in *UserGrantSearchRequest, opts ...grpc.CallOption) (*UserGrantSearchResponse, error) { + out := new(UserGrantSearchResponse) + err := c.cc.Invoke(ctx, "/zitadel.auth.api.v1.AuthService/SearchMyUserGrant", in, out, opts...) if err != nil { return nil, err } return out, nil } -func (c *authServiceClient) IsIamAdmin(ctx context.Context, in *empty.Empty, opts ...grpc.CallOption) (*IsAdminResponse, error) { - out := new(IsAdminResponse) - err := c.cc.Invoke(ctx, "/zitadel.auth.api.v1.AuthService/IsIamAdmin", in, out, opts...) +func (c *authServiceClient) SearchMyProjectOrgs(ctx context.Context, in *MyProjectOrgSearchRequest, opts ...grpc.CallOption) (*MyProjectOrgSearchResponse, error) { + out := new(MyProjectOrgSearchResponse) + err := c.cc.Invoke(ctx, "/zitadel.auth.api.v1.AuthService/SearchMyProjectOrgs", in, out, opts...) if err != nil { return nil, err } @@ -2533,8 +4202,8 @@ type AuthServiceServer interface { AddMfaOTP(context.Context, *empty.Empty) (*MfaOtpResponse, error) VerifyMfaOTP(context.Context, *VerifyMfaOtp) (*empty.Empty, error) RemoveMfaOTP(context.Context, *empty.Empty) (*empty.Empty, error) + SearchMyUserGrant(context.Context, *UserGrantSearchRequest) (*UserGrantSearchResponse, error) SearchMyProjectOrgs(context.Context, *MyProjectOrgSearchRequest) (*MyProjectOrgSearchResponse, error) - IsIamAdmin(context.Context, *empty.Empty) (*IsAdminResponse, error) //Permission GetMyZitadelPermissions(context.Context, *empty.Empty) (*MyPermissions, error) } @@ -2543,76 +4212,76 @@ type AuthServiceServer interface { type UnimplementedAuthServiceServer struct { } -func (*UnimplementedAuthServiceServer) Healthz(ctx context.Context, req *empty.Empty) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) Healthz(context.Context, *empty.Empty) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Healthz not implemented") } -func (*UnimplementedAuthServiceServer) Ready(ctx context.Context, req *empty.Empty) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) Ready(context.Context, *empty.Empty) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method Ready not implemented") } -func (*UnimplementedAuthServiceServer) Validate(ctx context.Context, req *empty.Empty) (*_struct.Struct, error) { +func (*UnimplementedAuthServiceServer) Validate(context.Context, *empty.Empty) (*_struct.Struct, error) { return nil, status.Errorf(codes.Unimplemented, "method Validate not implemented") } -func (*UnimplementedAuthServiceServer) GetMyUserSessions(ctx context.Context, req *empty.Empty) (*UserSessionViews, error) { +func (*UnimplementedAuthServiceServer) GetMyUserSessions(context.Context, *empty.Empty) (*UserSessionViews, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyUserSessions not implemented") } -func (*UnimplementedAuthServiceServer) GetMyUserProfile(ctx context.Context, req *empty.Empty) (*UserProfile, error) { +func (*UnimplementedAuthServiceServer) GetMyUserProfile(context.Context, *empty.Empty) (*UserProfile, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyUserProfile not implemented") } -func (*UnimplementedAuthServiceServer) UpdateMyUserProfile(ctx context.Context, req *UpdateUserProfileRequest) (*UserProfile, error) { +func (*UnimplementedAuthServiceServer) UpdateMyUserProfile(context.Context, *UpdateUserProfileRequest) (*UserProfile, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateMyUserProfile not implemented") } -func (*UnimplementedAuthServiceServer) GetMyUserEmail(ctx context.Context, req *empty.Empty) (*UserEmail, error) { +func (*UnimplementedAuthServiceServer) GetMyUserEmail(context.Context, *empty.Empty) (*UserEmail, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyUserEmail not implemented") } -func (*UnimplementedAuthServiceServer) ChangeMyUserEmail(ctx context.Context, req *UpdateUserEmailRequest) (*UserEmail, error) { +func (*UnimplementedAuthServiceServer) ChangeMyUserEmail(context.Context, *UpdateUserEmailRequest) (*UserEmail, error) { return nil, status.Errorf(codes.Unimplemented, "method ChangeMyUserEmail not implemented") } -func (*UnimplementedAuthServiceServer) VerifyMyUserEmail(ctx context.Context, req *VerifyMyUserEmailRequest) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) VerifyMyUserEmail(context.Context, *VerifyMyUserEmailRequest) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method VerifyMyUserEmail not implemented") } -func (*UnimplementedAuthServiceServer) ResendMyEmailVerificationMail(ctx context.Context, req *empty.Empty) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) ResendMyEmailVerificationMail(context.Context, *empty.Empty) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method ResendMyEmailVerificationMail not implemented") } -func (*UnimplementedAuthServiceServer) GetMyUserPhone(ctx context.Context, req *empty.Empty) (*UserPhone, error) { +func (*UnimplementedAuthServiceServer) GetMyUserPhone(context.Context, *empty.Empty) (*UserPhone, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyUserPhone not implemented") } -func (*UnimplementedAuthServiceServer) ChangeMyUserPhone(ctx context.Context, req *UpdateUserPhoneRequest) (*UserPhone, error) { +func (*UnimplementedAuthServiceServer) ChangeMyUserPhone(context.Context, *UpdateUserPhoneRequest) (*UserPhone, error) { return nil, status.Errorf(codes.Unimplemented, "method ChangeMyUserPhone not implemented") } -func (*UnimplementedAuthServiceServer) VerifyMyUserPhone(ctx context.Context, req *VerifyUserPhoneRequest) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) VerifyMyUserPhone(context.Context, *VerifyUserPhoneRequest) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method VerifyMyUserPhone not implemented") } -func (*UnimplementedAuthServiceServer) ResendMyPhoneVerificationCode(ctx context.Context, req *empty.Empty) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) ResendMyPhoneVerificationCode(context.Context, *empty.Empty) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method ResendMyPhoneVerificationCode not implemented") } -func (*UnimplementedAuthServiceServer) GetMyUserAddress(ctx context.Context, req *empty.Empty) (*UserAddress, error) { +func (*UnimplementedAuthServiceServer) GetMyUserAddress(context.Context, *empty.Empty) (*UserAddress, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyUserAddress not implemented") } -func (*UnimplementedAuthServiceServer) UpdateMyUserAddress(ctx context.Context, req *UpdateUserAddressRequest) (*UserAddress, error) { +func (*UnimplementedAuthServiceServer) UpdateMyUserAddress(context.Context, *UpdateUserAddressRequest) (*UserAddress, error) { return nil, status.Errorf(codes.Unimplemented, "method UpdateMyUserAddress not implemented") } -func (*UnimplementedAuthServiceServer) GetMyMfas(ctx context.Context, req *empty.Empty) (*MultiFactors, error) { +func (*UnimplementedAuthServiceServer) GetMyMfas(context.Context, *empty.Empty) (*MultiFactors, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyMfas not implemented") } -func (*UnimplementedAuthServiceServer) ChangeMyPassword(ctx context.Context, req *PasswordChange) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) ChangeMyPassword(context.Context, *PasswordChange) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method ChangeMyPassword not implemented") } -func (*UnimplementedAuthServiceServer) AddMfaOTP(ctx context.Context, req *empty.Empty) (*MfaOtpResponse, error) { +func (*UnimplementedAuthServiceServer) AddMfaOTP(context.Context, *empty.Empty) (*MfaOtpResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method AddMfaOTP not implemented") } -func (*UnimplementedAuthServiceServer) VerifyMfaOTP(ctx context.Context, req *VerifyMfaOtp) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) VerifyMfaOTP(context.Context, *VerifyMfaOtp) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method VerifyMfaOTP not implemented") } -func (*UnimplementedAuthServiceServer) RemoveMfaOTP(ctx context.Context, req *empty.Empty) (*empty.Empty, error) { +func (*UnimplementedAuthServiceServer) RemoveMfaOTP(context.Context, *empty.Empty) (*empty.Empty, error) { return nil, status.Errorf(codes.Unimplemented, "method RemoveMfaOTP not implemented") } -func (*UnimplementedAuthServiceServer) SearchMyProjectOrgs(ctx context.Context, req *MyProjectOrgSearchRequest) (*MyProjectOrgSearchResponse, error) { +func (*UnimplementedAuthServiceServer) SearchMyUserGrant(context.Context, *UserGrantSearchRequest) (*UserGrantSearchResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SearchMyUserGrant not implemented") +} +func (*UnimplementedAuthServiceServer) SearchMyProjectOrgs(context.Context, *MyProjectOrgSearchRequest) (*MyProjectOrgSearchResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method SearchMyProjectOrgs not implemented") } -func (*UnimplementedAuthServiceServer) IsIamAdmin(ctx context.Context, req *empty.Empty) (*IsAdminResponse, error) { - return nil, status.Errorf(codes.Unimplemented, "method IsIamAdmin not implemented") -} -func (*UnimplementedAuthServiceServer) GetMyZitadelPermissions(ctx context.Context, req *empty.Empty) (*MyPermissions, error) { +func (*UnimplementedAuthServiceServer) GetMyZitadelPermissions(context.Context, *empty.Empty) (*MyPermissions, error) { return nil, status.Errorf(codes.Unimplemented, "method GetMyZitadelPermissions not implemented") } @@ -2998,6 +4667,24 @@ func _AuthService_RemoveMfaOTP_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _AuthService_SearchMyUserGrant_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(UserGrantSearchRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(AuthServiceServer).SearchMyUserGrant(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/zitadel.auth.api.v1.AuthService/SearchMyUserGrant", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(AuthServiceServer).SearchMyUserGrant(ctx, req.(*UserGrantSearchRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _AuthService_SearchMyProjectOrgs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(MyProjectOrgSearchRequest) if err := dec(in); err != nil { @@ -3016,24 +4703,6 @@ func _AuthService_SearchMyProjectOrgs_Handler(srv interface{}, ctx context.Conte return interceptor(ctx, in, info, handler) } -func _AuthService_IsIamAdmin_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(empty.Empty) - if err := dec(in); err != nil { - return nil, err - } - if interceptor == nil { - return srv.(AuthServiceServer).IsIamAdmin(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: "/zitadel.auth.api.v1.AuthService/IsIamAdmin", - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(AuthServiceServer).IsIamAdmin(ctx, req.(*empty.Empty)) - } - return interceptor(ctx, in, info, handler) -} - func _AuthService_GetMyZitadelPermissions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(empty.Empty) if err := dec(in); err != nil { @@ -3141,12 +4810,12 @@ var _AuthService_serviceDesc = grpc.ServiceDesc{ Handler: _AuthService_RemoveMfaOTP_Handler, }, { - MethodName: "SearchMyProjectOrgs", - Handler: _AuthService_SearchMyProjectOrgs_Handler, + MethodName: "SearchMyUserGrant", + Handler: _AuthService_SearchMyUserGrant_Handler, }, { - MethodName: "IsIamAdmin", - Handler: _AuthService_IsIamAdmin_Handler, + MethodName: "SearchMyProjectOrgs", + Handler: _AuthService_SearchMyProjectOrgs_Handler, }, { MethodName: "GetMyZitadelPermissions", diff --git a/pkg/auth/api/grpc/auth.pb.gw.go b/pkg/auth/api/grpc/auth.pb.gw.go index b5ff7ac015..76e3b6a304 100644 --- a/pkg/auth/api/grpc/auth.pb.gw.go +++ b/pkg/auth/api/grpc/auth.pb.gw.go @@ -38,15 +38,6 @@ func request_AuthService_Healthz_0(ctx context.Context, marshaler runtime.Marsha } -func local_request_AuthService_Healthz_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.Healthz(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_Ready_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -56,15 +47,6 @@ func request_AuthService_Ready_0(ctx context.Context, marshaler runtime.Marshale } -func local_request_AuthService_Ready_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.Ready(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_Validate_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -74,15 +56,6 @@ func request_AuthService_Validate_0(ctx context.Context, marshaler runtime.Marsh } -func local_request_AuthService_Validate_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.Validate(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyUserSessions_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -92,15 +65,6 @@ func request_AuthService_GetMyUserSessions_0(ctx context.Context, marshaler runt } -func local_request_AuthService_GetMyUserSessions_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyUserSessions(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyUserProfile_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -110,15 +74,6 @@ func request_AuthService_GetMyUserProfile_0(ctx context.Context, marshaler runti } -func local_request_AuthService_GetMyUserProfile_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyUserProfile(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_UpdateMyUserProfile_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq UpdateUserProfileRequest var metadata runtime.ServerMetadata @@ -136,23 +91,6 @@ func request_AuthService_UpdateMyUserProfile_0(ctx context.Context, marshaler ru } -func local_request_AuthService_UpdateMyUserProfile_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq UpdateUserProfileRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.UpdateMyUserProfile(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyUserEmail_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -162,15 +100,6 @@ func request_AuthService_GetMyUserEmail_0(ctx context.Context, marshaler runtime } -func local_request_AuthService_GetMyUserEmail_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyUserEmail(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_ChangeMyUserEmail_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq UpdateUserEmailRequest var metadata runtime.ServerMetadata @@ -188,23 +117,6 @@ func request_AuthService_ChangeMyUserEmail_0(ctx context.Context, marshaler runt } -func local_request_AuthService_ChangeMyUserEmail_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq UpdateUserEmailRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ChangeMyUserEmail(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_VerifyMyUserEmail_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq VerifyMyUserEmailRequest var metadata runtime.ServerMetadata @@ -222,23 +134,6 @@ func request_AuthService_VerifyMyUserEmail_0(ctx context.Context, marshaler runt } -func local_request_AuthService_VerifyMyUserEmail_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq VerifyMyUserEmailRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.VerifyMyUserEmail(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_ResendMyEmailVerificationMail_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -256,23 +151,6 @@ func request_AuthService_ResendMyEmailVerificationMail_0(ctx context.Context, ma } -func local_request_AuthService_ResendMyEmailVerificationMail_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ResendMyEmailVerificationMail(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyUserPhone_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -282,15 +160,6 @@ func request_AuthService_GetMyUserPhone_0(ctx context.Context, marshaler runtime } -func local_request_AuthService_GetMyUserPhone_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyUserPhone(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_ChangeMyUserPhone_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq UpdateUserPhoneRequest var metadata runtime.ServerMetadata @@ -308,23 +177,6 @@ func request_AuthService_ChangeMyUserPhone_0(ctx context.Context, marshaler runt } -func local_request_AuthService_ChangeMyUserPhone_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq UpdateUserPhoneRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ChangeMyUserPhone(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_VerifyMyUserPhone_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq VerifyUserPhoneRequest var metadata runtime.ServerMetadata @@ -342,23 +194,6 @@ func request_AuthService_VerifyMyUserPhone_0(ctx context.Context, marshaler runt } -func local_request_AuthService_VerifyMyUserPhone_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq VerifyUserPhoneRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.VerifyMyUserPhone(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_ResendMyPhoneVerificationCode_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -376,23 +211,6 @@ func request_AuthService_ResendMyPhoneVerificationCode_0(ctx context.Context, ma } -func local_request_AuthService_ResendMyPhoneVerificationCode_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ResendMyPhoneVerificationCode(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyUserAddress_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -402,15 +220,6 @@ func request_AuthService_GetMyUserAddress_0(ctx context.Context, marshaler runti } -func local_request_AuthService_GetMyUserAddress_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyUserAddress(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_UpdateMyUserAddress_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq UpdateUserAddressRequest var metadata runtime.ServerMetadata @@ -428,23 +237,6 @@ func request_AuthService_UpdateMyUserAddress_0(ctx context.Context, marshaler ru } -func local_request_AuthService_UpdateMyUserAddress_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq UpdateUserAddressRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.UpdateMyUserAddress(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyMfas_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -454,15 +246,6 @@ func request_AuthService_GetMyMfas_0(ctx context.Context, marshaler runtime.Mars } -func local_request_AuthService_GetMyMfas_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyMfas(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_ChangeMyPassword_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq PasswordChange var metadata runtime.ServerMetadata @@ -480,23 +263,6 @@ func request_AuthService_ChangeMyPassword_0(ctx context.Context, marshaler runti } -func local_request_AuthService_ChangeMyPassword_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq PasswordChange - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.ChangeMyPassword(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_AddMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -514,23 +280,6 @@ func request_AuthService_AddMfaOTP_0(ctx context.Context, marshaler runtime.Mars } -func local_request_AuthService_AddMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.AddMfaOTP(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_VerifyMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq VerifyMfaOtp var metadata runtime.ServerMetadata @@ -548,8 +297,17 @@ func request_AuthService_VerifyMfaOTP_0(ctx context.Context, marshaler runtime.M } -func local_request_AuthService_VerifyMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq VerifyMfaOtp +func request_AuthService_RemoveMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq empty.Empty + var metadata runtime.ServerMetadata + + msg, err := client.RemoveMfaOTP(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func request_AuthService_SearchMyUserGrant_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq UserGrantSearchRequest var metadata runtime.ServerMetadata newReader, berr := utilities.IOReaderFactory(req.Body) @@ -560,25 +318,7 @@ func local_request_AuthService_VerifyMfaOTP_0(ctx context.Context, marshaler run return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) } - msg, err := server.VerifyMfaOTP(ctx, &protoReq) - return msg, metadata, err - -} - -func request_AuthService_RemoveMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := client.RemoveMfaOTP(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_AuthService_RemoveMfaOTP_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.RemoveMfaOTP(ctx, &protoReq) + msg, err := client.SearchMyUserGrant(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) return msg, metadata, err } @@ -600,41 +340,6 @@ func request_AuthService_SearchMyProjectOrgs_0(ctx context.Context, marshaler ru } -func local_request_AuthService_SearchMyProjectOrgs_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq MyProjectOrgSearchRequest - var metadata runtime.ServerMetadata - - newReader, berr := utilities.IOReaderFactory(req.Body) - if berr != nil { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr) - } - if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF { - return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) - } - - msg, err := server.SearchMyProjectOrgs(ctx, &protoReq) - return msg, metadata, err - -} - -func request_AuthService_IsIamAdmin_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := client.IsIamAdmin(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) - return msg, metadata, err - -} - -func local_request_AuthService_IsIamAdmin_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.IsIamAdmin(ctx, &protoReq) - return msg, metadata, err - -} - func request_AuthService_GetMyZitadelPermissions_0(ctx context.Context, marshaler runtime.Marshaler, client AuthServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { var protoReq empty.Empty var metadata runtime.ServerMetadata @@ -644,503 +349,6 @@ func request_AuthService_GetMyZitadelPermissions_0(ctx context.Context, marshale } -func local_request_AuthService_GetMyZitadelPermissions_0(ctx context.Context, marshaler runtime.Marshaler, server AuthServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { - var protoReq empty.Empty - var metadata runtime.ServerMetadata - - msg, err := server.GetMyZitadelPermissions(ctx, &protoReq) - return msg, metadata, err - -} - -// RegisterAuthServiceHandlerServer registers the http handlers for service AuthService to "mux". -// UnaryRPC :call AuthServiceServer directly. -// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. -func RegisterAuthServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, server AuthServiceServer, opts []grpc.DialOption) error { - - mux.Handle("GET", pattern_AuthService_Healthz_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_Healthz_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_Healthz_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_Ready_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_Ready_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_Ready_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_Validate_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_Validate_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_Validate_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyUserSessions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyUserSessions_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyUserSessions_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyUserProfile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyUserProfile_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyUserProfile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PUT", pattern_AuthService_UpdateMyUserProfile_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_UpdateMyUserProfile_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_UpdateMyUserProfile_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyUserEmail_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyUserEmail_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyUserEmail_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PUT", pattern_AuthService_ChangeMyUserEmail_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_ChangeMyUserEmail_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_ChangeMyUserEmail_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_AuthService_VerifyMyUserEmail_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_VerifyMyUserEmail_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_VerifyMyUserEmail_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_AuthService_ResendMyEmailVerificationMail_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_ResendMyEmailVerificationMail_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_ResendMyEmailVerificationMail_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyUserPhone_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyUserPhone_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyUserPhone_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PUT", pattern_AuthService_ChangeMyUserPhone_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_ChangeMyUserPhone_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_ChangeMyUserPhone_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_AuthService_VerifyMyUserPhone_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_VerifyMyUserPhone_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_VerifyMyUserPhone_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_AuthService_ResendMyPhoneVerificationCode_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_ResendMyPhoneVerificationCode_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_ResendMyPhoneVerificationCode_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyUserAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyUserAddress_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyUserAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PUT", pattern_AuthService_UpdateMyUserAddress_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_UpdateMyUserAddress_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_UpdateMyUserAddress_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyMfas_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyMfas_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyMfas_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PUT", pattern_AuthService_ChangeMyPassword_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_ChangeMyPassword_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_ChangeMyPassword_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_AuthService_AddMfaOTP_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_AddMfaOTP_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_AddMfaOTP_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("PUT", pattern_AuthService_VerifyMfaOTP_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_VerifyMfaOTP_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_VerifyMfaOTP_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("DELETE", pattern_AuthService_RemoveMfaOTP_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_RemoveMfaOTP_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_RemoveMfaOTP_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("POST", pattern_AuthService_SearchMyProjectOrgs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_SearchMyProjectOrgs_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_SearchMyProjectOrgs_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_IsIamAdmin_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_IsIamAdmin_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_IsIamAdmin_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - mux.Handle("GET", pattern_AuthService_GetMyZitadelPermissions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := local_request_AuthService_GetMyZitadelPermissions_0(rctx, inboundMarshaler, server, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_GetMyZitadelPermissions_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - - return nil -} - // RegisterAuthServiceHandlerFromEndpoint is same as RegisterAuthServiceHandler but // automatically dials to "endpoint" and closes the connection when "ctx" gets done. func RegisterAuthServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) { @@ -1599,6 +807,26 @@ func RegisterAuthServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) + mux.Handle("POST", pattern_AuthService_SearchMyUserGrant_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_AuthService_SearchMyUserGrant_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_AuthService_SearchMyUserGrant_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + mux.Handle("POST", pattern_AuthService_SearchMyProjectOrgs_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1619,26 +847,6 @@ func RegisterAuthServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux }) - mux.Handle("GET", pattern_AuthService_IsIamAdmin_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { - ctx, cancel := context.WithCancel(req.Context()) - defer cancel() - inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) - rctx, err := runtime.AnnotateContext(ctx, mux, req) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - resp, md, err := request_AuthService_IsIamAdmin_0(rctx, inboundMarshaler, client, req, pathParams) - ctx = runtime.NewServerMetadataContext(ctx, md) - if err != nil { - runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) - return - } - - forward_AuthService_IsIamAdmin_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) - - }) - mux.Handle("GET", pattern_AuthService_GetMyZitadelPermissions_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { ctx, cancel := context.WithCancel(req.Context()) defer cancel() @@ -1663,53 +871,53 @@ func RegisterAuthServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux } var ( - pattern_AuthService_Healthz_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"healthz"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_Healthz_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"healthz"}, "")) - pattern_AuthService_Ready_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ready"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_Ready_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"ready"}, "")) - pattern_AuthService_Validate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"validate"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_Validate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0}, []string{"validate"}, "")) - pattern_AuthService_GetMyUserSessions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"me", "usersessions"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyUserSessions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"me", "usersessions"}, "")) - pattern_AuthService_GetMyUserProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "profile"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyUserProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "profile"}, "")) - pattern_AuthService_UpdateMyUserProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "profile"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_UpdateMyUserProfile_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "profile"}, "")) - pattern_AuthService_GetMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "email"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "email"}, "")) - pattern_AuthService_ChangeMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "email"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_ChangeMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "email"}, "")) - pattern_AuthService_VerifyMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "email", "_verify"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_VerifyMyUserEmail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "email", "_verify"}, "")) - pattern_AuthService_ResendMyEmailVerificationMail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "email", "_resendverification"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_ResendMyEmailVerificationMail_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "email", "_resendverification"}, "")) - pattern_AuthService_GetMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "phone"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "phone"}, "")) - pattern_AuthService_ChangeMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "phone"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_ChangeMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "phone"}, "")) - pattern_AuthService_VerifyMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "phone", "_verify"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_VerifyMyUserPhone_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "phone", "_verify"}, "")) - pattern_AuthService_ResendMyPhoneVerificationCode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "phone", "_resendverification"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_ResendMyPhoneVerificationCode_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "phone", "_resendverification"}, "")) - pattern_AuthService_GetMyUserAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "address"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyUserAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "address"}, "")) - pattern_AuthService_UpdateMyUserAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "address"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_UpdateMyUserAddress_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "address"}, "")) - pattern_AuthService_GetMyMfas_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "mfas"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyMfas_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"users", "me", "mfas"}, "")) - pattern_AuthService_ChangeMyPassword_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "passwords", "_change"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_ChangeMyPassword_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "passwords", "_change"}, "")) - pattern_AuthService_AddMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "mfa", "otp"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_AddMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "mfa", "otp"}, "")) - pattern_AuthService_VerifyMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"users", "me", "mfa", "otp", "_verify"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_VerifyMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"users", "me", "mfa", "otp", "_verify"}, "")) - pattern_AuthService_RemoveMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "mfa", "otp"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_RemoveMfaOTP_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"users", "me", "mfa", "otp"}, "")) - pattern_AuthService_SearchMyProjectOrgs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"global", "projectorgs", "_search"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_SearchMyUserGrant_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"usergrants", "me", "_search"}, "")) - pattern_AuthService_IsIamAdmin_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"global", "_isiamadmin"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_SearchMyProjectOrgs_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"global", "projectorgs", "_search"}, "")) - pattern_AuthService_GetMyZitadelPermissions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"permissions", "zitadel", "me"}, "", runtime.AssumeColonVerbOpt(true))) + pattern_AuthService_GetMyZitadelPermissions_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"permissions", "zitadel", "me"}, "")) ) var ( @@ -1755,9 +963,9 @@ var ( forward_AuthService_RemoveMfaOTP_0 = runtime.ForwardResponseMessage - forward_AuthService_SearchMyProjectOrgs_0 = runtime.ForwardResponseMessage + forward_AuthService_SearchMyUserGrant_0 = runtime.ForwardResponseMessage - forward_AuthService_IsIamAdmin_0 = runtime.ForwardResponseMessage + forward_AuthService_SearchMyProjectOrgs_0 = runtime.ForwardResponseMessage forward_AuthService_GetMyZitadelPermissions_0 = runtime.ForwardResponseMessage ) diff --git a/pkg/auth/api/grpc/auth.swagger.json b/pkg/auth/api/grpc/auth.swagger.json index df818781aa..98084c0057 100644 --- a/pkg/auth/api/grpc/auth.swagger.json +++ b/pkg/auth/api/grpc/auth.swagger.json @@ -19,22 +19,6 @@ "application/grpc" ], "paths": { - "/global/_isiamadmin": { - "get": { - "operationId": "IsIamAdmin", - "responses": { - "200": { - "description": "A successful response.", - "schema": { - "$ref": "#/definitions/v1IsAdminResponse" - } - } - }, - "tags": [ - "AuthService" - ] - } - }, "/global/projectorgs/_search": { "post": { "operationId": "SearchMyProjectOrgs", @@ -128,6 +112,32 @@ ] } }, + "/usergrants/me/_search": { + "post": { + "operationId": "SearchMyUserGrant", + "responses": { + "200": { + "description": "A successful response.", + "schema": { + "$ref": "#/definitions/v1UserGrantSearchResponse" + } + } + }, + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/v1UserGrantSearchRequest" + } + } + ], + "tags": [ + "AuthService" + ] + } + }, "/users/me/address": { "get": { "operationId": "GetMyUserAddress", @@ -510,7 +520,7 @@ "200": { "description": "A successful response.", "schema": { - "type": "object" + "$ref": "#/definitions/protobufStruct" } } }, @@ -521,6 +531,19 @@ } }, "definitions": { + "protobufListValue": { + "type": "object", + "properties": { + "values": { + "type": "array", + "items": { + "$ref": "#/definitions/protobufValue" + }, + "description": "Repeated field of dynamically typed values." + } + }, + "description": "`ListValue` is a wrapper around a repeated field of values.\n\nThe JSON representation for `ListValue` is JSON array." + }, "protobufNullValue": { "type": "string", "enum": [ @@ -529,6 +552,51 @@ "default": "NULL_VALUE", "description": "`NullValue` is a singleton enumeration to represent the null value for the\n`Value` type union.\n\n The JSON representation for `NullValue` is JSON `null`.\n\n - NULL_VALUE: Null value." }, + "protobufStruct": { + "type": "object", + "properties": { + "fields": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/protobufValue" + }, + "description": "Unordered map of dynamically typed values." + } + }, + "description": "`Struct` represents a structured data value, consisting of fields\nwhich map to dynamically typed values. In some languages, `Struct`\nmight be supported by a native representation. For example, in\nscripting languages like JS a struct is represented as an\nobject. The details of that representation are described together\nwith the proto support for the language.\n\nThe JSON representation for `Struct` is JSON object." + }, + "protobufValue": { + "type": "object", + "properties": { + "null_value": { + "$ref": "#/definitions/protobufNullValue", + "description": "Represents a null value." + }, + "number_value": { + "type": "number", + "format": "double", + "description": "Represents a double value." + }, + "string_value": { + "type": "string", + "description": "Represents a string value." + }, + "bool_value": { + "type": "boolean", + "format": "boolean", + "description": "Represents a boolean value." + }, + "struct_value": { + "$ref": "#/definitions/protobufStruct", + "description": "Represents a structured value." + }, + "list_value": { + "$ref": "#/definitions/protobufListValue", + "description": "Represents a repeated `Value`." + } + }, + "description": "`Value` represents a dynamically typed value which can be either\nnull, a number, a string, a boolean, a recursive struct value, or a\nlist of values. A producer of value is expected to set one of that\nvariants, absence of any variant indicates an error.\n\nThe JSON representation for `Value` is JSON value." + }, "v1Gender": { "type": "string", "enum": [ @@ -539,15 +607,6 @@ ], "default": "GENDER_UNSPECIFIED" }, - "v1IsAdminResponse": { - "type": "object", - "properties": { - "is_admin": { - "type": "boolean", - "format": "boolean" - } - } - }, "v1MFAState": { "type": "string", "enum": [ @@ -712,7 +771,10 @@ "enum": [ "SEARCHMETHOD_EQUALS", "SEARCHMETHOD_STARTS_WITH", - "SEARCHMETHOD_CONTAINS" + "SEARCHMETHOD_CONTAINS", + "SEARCHMETHOD_EQUALS_IGNORE_CASE", + "SEARCHMETHOD_STARTS_WITH_IGNORE_CASE", + "SEARCHMETHOD_CONTAINS_IGNORE_CASE" ], "default": "SEARCHMETHOD_EQUALS" }, @@ -837,6 +899,101 @@ } } }, + "v1UserGrantSearchKey": { + "type": "string", + "enum": [ + "UserGrantSearchKey_UNKNOWN", + "UserGrantSearchKey_ORG_ID", + "UserGrantSearchKey_PROJECT_ID" + ], + "default": "UserGrantSearchKey_UNKNOWN" + }, + "v1UserGrantSearchQuery": { + "type": "object", + "properties": { + "key": { + "$ref": "#/definitions/v1UserGrantSearchKey" + }, + "method": { + "$ref": "#/definitions/v1SearchMethod" + }, + "value": { + "type": "string" + } + } + }, + "v1UserGrantSearchRequest": { + "type": "object", + "properties": { + "offset": { + "type": "string", + "format": "uint64" + }, + "limit": { + "type": "string", + "format": "uint64" + }, + "sorting_column": { + "$ref": "#/definitions/v1UserGrantSearchKey" + }, + "asc": { + "type": "boolean", + "format": "boolean" + }, + "queries": { + "type": "array", + "items": { + "$ref": "#/definitions/v1UserGrantSearchQuery" + } + } + } + }, + "v1UserGrantSearchResponse": { + "type": "object", + "properties": { + "offset": { + "type": "string", + "format": "uint64" + }, + "limit": { + "type": "string", + "format": "uint64" + }, + "total_result": { + "type": "string", + "format": "uint64" + }, + "result": { + "type": "array", + "items": { + "$ref": "#/definitions/v1UserGrantView" + } + } + } + }, + "v1UserGrantView": { + "type": "object", + "properties": { + "OrgId": { + "type": "string" + }, + "ProjectId": { + "type": "string" + }, + "UserId": { + "type": "string" + }, + "Roles": { + "type": "array", + "items": { + "type": "string" + } + }, + "OrgName": { + "type": "string" + } + } + }, "v1UserPhone": { "type": "object", "properties": { diff --git a/pkg/auth/api/grpc/grant.go b/pkg/auth/api/grpc/grant.go deleted file mode 100644 index 8eb8681e06..0000000000 --- a/pkg/auth/api/grpc/grant.go +++ /dev/null @@ -1,15 +0,0 @@ -package grpc - -import ( - "context" - "github.com/caos/zitadel/internal/errors" - "github.com/golang/protobuf/ptypes/empty" -) - -func (s *Server) SearchMyProjectOrgs(ctx context.Context, request *MyProjectOrgSearchRequest) (*MyProjectOrgSearchResponse, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-8kdRf", "Not implemented") -} - -func (s *Server) IsIamAdmin(ctx context.Context, _ *empty.Empty) (*IsAdminResponse, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-9odFv", "Not implemented") -} diff --git a/pkg/auth/api/grpc/mock/auth.proto.mock.go b/pkg/auth/api/grpc/mock/auth.proto.mock.go index f829479430..347189b266 100644 --- a/pkg/auth/api/grpc/mock/auth.proto.mock.go +++ b/pkg/auth/api/grpc/mock/auth.proto.mock.go @@ -277,26 +277,6 @@ func (mr *MockAuthServiceClientMockRecorder) Healthz(arg0, arg1 interface{}, arg return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Healthz", reflect.TypeOf((*MockAuthServiceClient)(nil).Healthz), varargs...) } -// IsIamAdmin mocks base method -func (m *MockAuthServiceClient) IsIamAdmin(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*grpc.IsAdminResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{arg0, arg1} - for _, a := range arg2 { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "IsIamAdmin", varargs...) - ret0, _ := ret[0].(*grpc.IsAdminResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// IsIamAdmin indicates an expected call of IsIamAdmin -func (mr *MockAuthServiceClientMockRecorder) IsIamAdmin(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsIamAdmin", reflect.TypeOf((*MockAuthServiceClient)(nil).IsIamAdmin), varargs...) -} - // Ready mocks base method func (m *MockAuthServiceClient) Ready(arg0 context.Context, arg1 *emptypb.Empty, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) { m.ctrl.T.Helper() @@ -397,24 +377,24 @@ func (mr *MockAuthServiceClientMockRecorder) SearchMyProjectOrgs(arg0, arg1 inte return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchMyProjectOrgs", reflect.TypeOf((*MockAuthServiceClient)(nil).SearchMyProjectOrgs), varargs...) } -// SetMyPassword mocks base method -func (m *MockAuthServiceClient) SetMyPassword(arg0 context.Context, arg1 *grpc.PasswordRequest, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) { +// SearchUserGrant mocks base method +func (m *MockAuthServiceClient) SearchUserGrant(arg0 context.Context, arg1 *grpc.UserGrantSearchRequest, arg2 ...grpc0.CallOption) (*grpc.UserGrantSearchResponse, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } - ret := m.ctrl.Call(m, "SetMyPassword", varargs...) - ret0, _ := ret[0].(*emptypb.Empty) + ret := m.ctrl.Call(m, "SearchUserGrant", varargs...) + ret0, _ := ret[0].(*grpc.UserGrantSearchResponse) ret1, _ := ret[1].(error) return ret0, ret1 } -// SetMyPassword indicates an expected call of SetMyPassword -func (mr *MockAuthServiceClientMockRecorder) SetMyPassword(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { +// SearchUserGrant indicates an expected call of SearchUserGrant +func (mr *MockAuthServiceClientMockRecorder) SearchUserGrant(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() varargs := append([]interface{}{arg0, arg1}, arg2...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetMyPassword", reflect.TypeOf((*MockAuthServiceClient)(nil).SetMyPassword), varargs...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SearchUserGrant", reflect.TypeOf((*MockAuthServiceClient)(nil).SearchUserGrant), varargs...) } // UpdateMyUserAddress mocks base method @@ -478,14 +458,14 @@ func (mr *MockAuthServiceClientMockRecorder) Validate(arg0, arg1 interface{}, ar } // VerifyMfaOTP mocks base method -func (m *MockAuthServiceClient) VerifyMfaOTP(arg0 context.Context, arg1 *grpc.VerifyMfaOtp, arg2 ...grpc0.CallOption) (*grpc.MfaOtpResponse, error) { +func (m *MockAuthServiceClient) VerifyMfaOTP(arg0 context.Context, arg1 *grpc.VerifyMfaOtp, arg2 ...grpc0.CallOption) (*emptypb.Empty, error) { m.ctrl.T.Helper() varargs := []interface{}{arg0, arg1} for _, a := range arg2 { varargs = append(varargs, a) } ret := m.ctrl.Call(m, "VerifyMfaOTP", varargs...) - ret0, _ := ret[0].(*grpc.MfaOtpResponse) + ret0, _ := ret[0].(*emptypb.Empty) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/pkg/auth/api/grpc/permissions.go b/pkg/auth/api/grpc/permissions.go deleted file mode 100644 index 998ba2ee98..0000000000 --- a/pkg/auth/api/grpc/permissions.go +++ /dev/null @@ -1,50 +0,0 @@ -package grpc - -import ( - "context" - "github.com/caos/zitadel/internal/errors" - "github.com/golang/protobuf/ptypes/empty" -) - -func (s *Server) GetMyZitadelPermissions(ctx context.Context, _ *empty.Empty) (*MyPermissions, error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-or67G", "Not implemented") - //ctxData := auth.GetCtxData(ctx) - // - //grants, err := s.processor.ResolveGrants(ctx, ctxData.UserID, ctxData.OrgID) - //if err != nil { - // return nil, err - //} - // - //permissions := &MyPermissions{Permissions: []string{}} - // - //for _, grant := range grants { - // for _, role := range grant.Roles { - // roleName, ctxID := auth.SplitPermission(role) - // for _, mapping := range s.authConf.RolePermissionMappings { - // if mapping.Role == roleName { - // permissions.appendPermissions(ctxID, mapping.Permissions...) - // } - // } - // } - //} - // - //return permissions, nil -} - -func (p *MyPermissions) appendPermissions(ctxID string, permissions ...string) { - for _, permission := range permissions { - p.appendPermission(ctxID, permission) - } -} - -func (p *MyPermissions) appendPermission(ctxID, permission string) { - if ctxID != "" { - permission = permission + ":" + ctxID - } - for _, existingPermission := range p.Permissions { - if existingPermission == permission { - return - } - } - p.Permissions = append(p.Permissions, permission) -} diff --git a/pkg/auth/api/grpc/search_converter.go b/pkg/auth/api/grpc/search_converter.go new file mode 100644 index 0000000000..d50c224171 --- /dev/null +++ b/pkg/auth/api/grpc/search_converter.go @@ -0,0 +1,22 @@ +package grpc + +import "github.com/caos/zitadel/internal/model" + +func searchMethodToModel(method SearchMethod) model.SearchMethod { + switch method { + case SearchMethod_SEARCHMETHOD_EQUALS: + return model.SEARCHMETHOD_EQUALS + case SearchMethod_SEARCHMETHOD_CONTAINS: + return model.SEARCHMETHOD_CONTAINS + case SearchMethod_SEARCHMETHOD_STARTS_WITH: + return model.SEARCHMETHOD_STARTS_WITH + case SearchMethod_SEARCHMETHOD_EQUALS_IGNORE_CASE: + return model.SEARCHMETHOD_EQUALS_IGNORE_CASE + case SearchMethod_SEARCHMETHOD_CONTAINS_IGNORE_CASE: + return model.SEARCHMETHOD_CONTAINS_IGNORE_CASE + case SearchMethod_SEARCHMETHOD_STARTS_WITH_IGNORE_CASE: + return model.SEARCHMETHOD_STARTS_WITH_IGNORE_CASE + default: + return model.SEARCHMETHOD_EQUALS + } +} diff --git a/pkg/auth/api/grpc/server.go b/pkg/auth/api/grpc/server.go index 7c55eaf303..a9177e1a11 100644 --- a/pkg/auth/api/grpc/server.go +++ b/pkg/auth/api/grpc/server.go @@ -1,6 +1,7 @@ package grpc import ( + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" "google.golang.org/grpc" @@ -20,12 +21,12 @@ type Server struct { authZ auth_util.Config } -func StartServer(conf grpc_util.ServerConfig, authZ auth_util.Config, repo repository.Repository) *Server { +func StartServer(conf grpc_util.ServerConfig, authZRepo *authz_repo.EsRepository, authZ auth_util.Config, authRepo repository.Repository) *Server { return &Server{ port: conf.Port, - repo: repo, + repo: authRepo, authZ: authZ, - verifier: auth.Start(), + verifier: auth.Start(authZRepo), } } diff --git a/pkg/auth/api/grpc/user.go b/pkg/auth/api/grpc/user.go index 5788c82df2..2f387aac89 100644 --- a/pkg/auth/api/grpc/user.go +++ b/pkg/auth/api/grpc/user.go @@ -110,7 +110,7 @@ func (s *Server) AddMfaOTP(ctx context.Context, _ *empty.Empty) (_ *MfaOtpRespon } func (s *Server) VerifyMfaOTP(ctx context.Context, request *VerifyMfaOtp) (*empty.Empty, error) { - err := s.repo.VerifyMyMfaOTP(ctx, request.Code) + err := s.repo.VerifyMyMfaOTPSetup(ctx, request.Code) return &empty.Empty{}, err } diff --git a/pkg/auth/api/grpc/user_grant.go b/pkg/auth/api/grpc/user_grant.go new file mode 100644 index 0000000000..4035cfcf3b --- /dev/null +++ b/pkg/auth/api/grpc/user_grant.go @@ -0,0 +1,30 @@ +package grpc + +import ( + "context" + "github.com/golang/protobuf/ptypes/empty" +) + +func (s *Server) SearchMyUserGrant(ctx context.Context, in *UserGrantSearchRequest) (*UserGrantSearchResponse, error) { + response, err := s.repo.SearchMyUserGrants(ctx, userGrantSearchRequestsToModel(in)) + if err != nil { + return nil, err + } + return userGrantSearchResponseFromModel(response), nil +} + +func (s *Server) SearchMyProjectOrgs(ctx context.Context, in *MyProjectOrgSearchRequest) (*MyProjectOrgSearchResponse, error) { + response, err := s.repo.SearchMyProjectOrgs(ctx, myProjectOrgSearchRequestRequestsToModel(in)) + if err != nil { + return nil, err + } + return projectOrgSearchResponseFromModel(response), nil +} + +func (s *Server) GetMyZitadelPermissions(ctx context.Context, _ *empty.Empty) (*MyPermissions, error) { + perms, err := s.repo.SearchMyZitadelPermissions(ctx) + if err != nil { + return nil, err + } + return &MyPermissions{Permissions: perms}, nil +} diff --git a/pkg/auth/api/grpc/user_grant_converter.go b/pkg/auth/api/grpc/user_grant_converter.go new file mode 100644 index 0000000000..2de2b539bc --- /dev/null +++ b/pkg/auth/api/grpc/user_grant_converter.go @@ -0,0 +1,126 @@ +package grpc + +import ( + grant_model "github.com/caos/zitadel/internal/usergrant/model" +) + +func userGrantSearchRequestsToModel(request *UserGrantSearchRequest) *grant_model.UserGrantSearchRequest { + return &grant_model.UserGrantSearchRequest{ + Offset: request.Offset, + Limit: request.Limit, + Queries: userGrantSearchQueriesToModel(request.Queries), + } +} + +func userGrantSearchQueriesToModel(queries []*UserGrantSearchQuery) []*grant_model.UserGrantSearchQuery { + converted := make([]*grant_model.UserGrantSearchQuery, len(queries)) + for i, q := range queries { + converted[i] = userGrantSearchQueryToModel(q) + } + return converted +} + +func userGrantSearchQueryToModel(query *UserGrantSearchQuery) *grant_model.UserGrantSearchQuery { + return &grant_model.UserGrantSearchQuery{ + Key: userGrantSearchKeyToModel(query.Key), + Method: searchMethodToModel(query.Method), + Value: query.Value, + } +} + +func userGrantSearchKeyToModel(key UserGrantSearchKey) grant_model.UserGrantSearchKey { + switch key { + case UserGrantSearchKey_UserGrantSearchKey_ORG_ID: + return grant_model.USERGRANTSEARCHKEY_RESOURCEOWNER + case UserGrantSearchKey_UserGrantSearchKey_PROJECT_ID: + return grant_model.USERGRANTSEARCHKEY_PROJECT_ID + default: + return grant_model.USERGRANTSEARCHKEY_UNSPECIFIED + } +} + +func myProjectOrgSearchRequestRequestsToModel(request *MyProjectOrgSearchRequest) *grant_model.UserGrantSearchRequest { + return &grant_model.UserGrantSearchRequest{ + Offset: request.Offset, + Limit: request.Limit, + Asc: request.Asc, + SortingColumn: grant_model.USERGRANTSEARCHKEY_RESOURCEOWNER, + Queries: myProjectOrgSearchQueriesToModel(request.Queries), + } +} + +func myProjectOrgSearchQueriesToModel(queries []*MyProjectOrgSearchQuery) []*grant_model.UserGrantSearchQuery { + converted := make([]*grant_model.UserGrantSearchQuery, len(queries)) + for i, q := range queries { + converted[i] = myProjectOrgSearchQueryToModel(q) + } + return converted +} + +func myProjectOrgSearchQueryToModel(query *MyProjectOrgSearchQuery) *grant_model.UserGrantSearchQuery { + return &grant_model.UserGrantSearchQuery{ + Key: myProjectOrgSearchKeyToModel(query.Key), + Method: searchMethodToModel(query.Method), + Value: query.Value, + } +} + +func myProjectOrgSearchKeyToModel(key MyProjectOrgSearchKey) grant_model.UserGrantSearchKey { + switch key { + case MyProjectOrgSearchKey_MYPROJECTORGSEARCHKEY_ORG_NAME: + return grant_model.USERGRANTSEARCHKEY_ORG_NAME + default: + return grant_model.USERGRANTSEARCHKEY_UNSPECIFIED + } +} + +func userGrantSearchResponseFromModel(response *grant_model.UserGrantSearchResponse) *UserGrantSearchResponse { + return &UserGrantSearchResponse{ + Offset: response.Offset, + Limit: response.Limit, + TotalResult: response.TotalResult, + Result: userGrantViewsFromModel(response.Result), + } +} + +func userGrantViewsFromModel(users []*grant_model.UserGrantView) []*UserGrantView { + converted := make([]*UserGrantView, len(users)) + for i, user := range users { + converted[i] = userGrantViewFromModel(user) + } + return converted +} + +func userGrantViewFromModel(grant *grant_model.UserGrantView) *UserGrantView { + return &UserGrantView{ + UserId: grant.UserID, + OrgId: grant.ResourceOwner, + OrgName: grant.OrgName, + ProjectId: grant.ProjectID, + Roles: grant.RoleKeys, + } +} + +func projectOrgSearchResponseFromModel(response *grant_model.ProjectOrgSearchResponse) *MyProjectOrgSearchResponse { + return &MyProjectOrgSearchResponse{ + Offset: response.Offset, + Limit: response.Limit, + TotalResult: response.TotalResult, + Result: projectOrgsFromModel(response.Result), + } +} + +func projectOrgsFromModel(projectOrgs []*grant_model.Org) []*Org { + converted := make([]*Org, len(projectOrgs)) + for i, org := range projectOrgs { + converted[i] = projectOrgFromModel(org) + } + return converted +} + +func projectOrgFromModel(org *grant_model.Org) *Org { + return &Org{ + Id: org.OrgID, + Name: org.OrgName, + } +} diff --git a/pkg/auth/api/grpc/user_session.go b/pkg/auth/api/grpc/user_session.go index 05460f85ef..7df389d004 100644 --- a/pkg/auth/api/grpc/user_session.go +++ b/pkg/auth/api/grpc/user_session.go @@ -2,10 +2,13 @@ package grpc import ( "context" - "github.com/caos/zitadel/internal/errors" "github.com/golang/protobuf/ptypes/empty" ) func (s *Server) GetMyUserSessions(ctx context.Context, _ *empty.Empty) (_ *UserSessionViews, err error) { - return nil, errors.ThrowUnimplemented(nil, "GRPC-nc52s", "Not implemented") + userSessions, err := s.repo.GetMyUserSessions(ctx) + if err != nil { + return nil, err + } + return &UserSessionViews{UserSessions: userSessionViewsFromModel(userSessions)}, nil } diff --git a/pkg/auth/api/grpc/user_session_converter.go b/pkg/auth/api/grpc/user_session_converter.go new file mode 100644 index 0000000000..3b21ba6fcc --- /dev/null +++ b/pkg/auth/api/grpc/user_session_converter.go @@ -0,0 +1,35 @@ +package grpc + +import ( + auth_req_model "github.com/caos/zitadel/internal/auth_request/model" + usr_model "github.com/caos/zitadel/internal/user/model" +) + +func userSessionViewsFromModel(userSessions []*usr_model.UserSessionView) []*UserSessionView { + converted := make([]*UserSessionView, len(userSessions)) + for i, s := range userSessions { + converted[i] = userSessionViewFromModel(s) + } + return converted +} + +func userSessionViewFromModel(userSession *usr_model.UserSessionView) *UserSessionView { + return &UserSessionView{ + Sequence: userSession.Sequence, + AgentId: userSession.UserAgentID, + UserId: userSession.UserID, + UserName: userSession.UserName, + AuthState: userSessionStateFromModel(userSession.State), + } +} + +func userSessionStateFromModel(state auth_req_model.UserSessionState) UserSessionState { + switch state { + case auth_req_model.UserSessionStateActive: + return UserSessionState_USERSESSIONSTATE_ACTIVE + case auth_req_model.UserSessionStateTerminated: + return UserSessionState_USERSESSIONSTATE_TERMINATED + default: + return UserSessionState_USERSESSIONSTATE_UNSPECIFIED + } +} diff --git a/pkg/auth/api/oidc/auth_request.go b/pkg/auth/api/oidc/auth_request.go new file mode 100644 index 0000000000..62366797ed --- /dev/null +++ b/pkg/auth/api/oidc/auth_request.go @@ -0,0 +1,82 @@ +package oidc + +import ( + "context" + "time" + + "github.com/caos/oidc/pkg/oidc" + "github.com/caos/oidc/pkg/op" + "gopkg.in/square/go-jose.v2" + + "github.com/caos/zitadel/internal/auth_request/model" + "github.com/caos/zitadel/internal/errors" +) + +func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest, userID string) (op.AuthRequest, error) { + userAgentID, ok := UserAgentIDFromCtx(ctx) + if !ok { + return nil, errors.ThrowPreconditionFailed(nil, "OIDC-sd436", "no user agent id") + } + authRequest := CreateAuthRequestToBusiness(ctx, req, userAgentID, userID) + resp, err := o.repo.CreateAuthRequest(ctx, authRequest) + if err != nil { + return nil, err + } + return AuthRequestFromBusiness(resp) +} + +func (o *OPStorage) AuthRequestByID(ctx context.Context, id string) (op.AuthRequest, error) { + resp, err := o.repo.AuthRequestByIDCheckLoggedIn(ctx, id) + if err != nil { + return nil, err + } + return AuthRequestFromBusiness(resp) +} + +func (o *OPStorage) AuthRequestByCode(ctx context.Context, code string) (op.AuthRequest, error) { + resp, err := o.repo.AuthRequestByCode(ctx, code) + if err != nil { + return nil, err + } + return AuthRequestFromBusiness(resp) +} + +func (o *OPStorage) SaveAuthCode(ctx context.Context, id, code string) error { + return o.repo.SaveAuthCode(ctx, id, code) +} + +func (o *OPStorage) DeleteAuthRequest(ctx context.Context, id string) error { + return o.repo.DeleteAuthRequest(ctx, id) +} + +func (o *OPStorage) CreateToken(ctx context.Context, authReq op.AuthRequest) (string, time.Time, error) { + req, err := o.repo.AuthRequestByID(ctx, authReq.GetID()) + if err != nil { + return "", time.Time{}, err + } + resp, err := o.repo.CreateToken(ctx, req.AgentID, req.ApplicationID, req.UserID, req.Audience, req.Request.(*model.AuthRequestOIDC).Scopes, o.defaultAccessTokenLifetime) //PLANNED: lifetime from client + if err != nil { + return "", time.Time{}, err + } + return resp.ID, resp.Expiration, nil +} + +func (o *OPStorage) TerminateSession(ctx context.Context, userID, clientID string) error { + userAgentID, ok := UserAgentIDFromCtx(ctx) + if !ok { + return errors.ThrowPreconditionFailed(nil, "OIDC-fso7F", "no user agent id") + } + return o.repo.SignOut(ctx, userAgentID, userID) +} + +func (o *OPStorage) GetSigningKey(ctx context.Context, keyCh chan<- jose.SigningKey, errCh chan<- error, timer <-chan time.Time) { + o.repo.GetSigningKey(ctx, keyCh, errCh, timer) +} + +func (o *OPStorage) GetKeySet(ctx context.Context) (*jose.JSONWebKeySet, error) { + return o.repo.GetKeySet(ctx) +} + +func (o *OPStorage) SaveNewKeyPair(ctx context.Context) error { + return o.repo.GenerateSigningKeyPair(ctx, o.signingKeyAlgorithm) +} diff --git a/pkg/auth/api/oidc/auth_request_converter.go b/pkg/auth/api/oidc/auth_request_converter.go new file mode 100644 index 0000000000..a837046809 --- /dev/null +++ b/pkg/auth/api/oidc/auth_request_converter.go @@ -0,0 +1,254 @@ +package oidc + +import ( + "context" + "net" + "time" + + "github.com/caos/oidc/pkg/oidc" + "github.com/caos/oidc/pkg/op" + "golang.org/x/text/language" + + api_utils "github.com/caos/zitadel/internal/api" + http_utils "github.com/caos/zitadel/internal/api/http" + "github.com/caos/zitadel/internal/auth_request/model" + "github.com/caos/zitadel/internal/errors" +) + +const ( + amrPassword = "password" + amrMFA = "mfa" + amrOTP = "otp" +) + +type AuthRequest struct { + *model.AuthRequest +} + +func (a *AuthRequest) GetID() string { + return a.ID +} + +func (a *AuthRequest) GetACR() string { + // return a. + return "" //PLANNED: impl +} + +func (a *AuthRequest) GetAMR() []string { + amr := make([]string, 0) + if a.PasswordVerified { + amr = append(amr, amrPassword) + } + if len(a.MfasVerified) > 0 { + amr = append(amr, amrMFA) + for _, mfa := range a.MfasVerified { + if amrMfa := AMRFromMFAType(mfa); amrMfa != "" { + amr = append(amr, amrMfa) + } + } + } + return amr +} + +func (a *AuthRequest) GetAudience() []string { + return a.Audience +} + +func (a *AuthRequest) GetAuthTime() time.Time { + return a.AuthTime +} + +func (a *AuthRequest) GetClientID() string { + return a.ApplicationID +} + +func (a *AuthRequest) GetCodeChallenge() *oidc.CodeChallenge { + return CodeChallengeToOIDC(a.oidc().CodeChallenge) +} + +func (a *AuthRequest) GetNonce() string { + return a.oidc().Nonce +} + +func (a *AuthRequest) GetRedirectURI() string { + return a.CallbackURI +} + +func (a *AuthRequest) GetResponseType() oidc.ResponseType { + return ResponseTypeToOIDC(a.oidc().ResponseType) +} + +func (a *AuthRequest) GetScopes() []string { + return a.oidc().Scopes +} + +func (a *AuthRequest) GetState() string { + return a.TransferState +} + +func (a *AuthRequest) GetSubject() string { + return a.UserID +} + +func (a *AuthRequest) Done() bool { + for _, step := range a.PossibleSteps { + if step.Type() == model.NextStepRedirectToCallback { + return true + } + } + return false +} + +func (a *AuthRequest) oidc() *model.AuthRequestOIDC { + return a.Request.(*model.AuthRequestOIDC) +} + +func AuthRequestFromBusiness(authReq *model.AuthRequest) (_ op.AuthRequest, err error) { + if _, ok := authReq.Request.(*model.AuthRequestOIDC); !ok { + return nil, errors.ThrowInvalidArgument(nil, "OIDC-Haz7A", "auth request is not of type oidc") + } + return &AuthRequest{authReq}, nil +} + +func CreateAuthRequestToBusiness(ctx context.Context, authReq *oidc.AuthRequest, userAgentID, userID string) *model.AuthRequest { + return &model.AuthRequest{ + AgentID: userAgentID, + BrowserInfo: ParseBrowserInfoFromContext(ctx), + ApplicationID: authReq.ClientID, + CallbackURI: authReq.RedirectURI, + TransferState: authReq.State, + Prompt: PromptToBusiness(authReq.Prompt), + PossibleLOAs: ACRValuesToBusiness(authReq.ACRValues), + UiLocales: UILocalesToBusiness(authReq.UILocales), + LoginHint: authReq.LoginHint, + MaxAuthAge: authReq.MaxAge, + UserID: userID, + Request: &model.AuthRequestOIDC{ + Scopes: authReq.Scopes, + ResponseType: ResponseTypeToBusiness(authReq.ResponseType), + Nonce: authReq.Nonce, + CodeChallenge: CodeChallengeToBusiness(authReq.CodeChallenge, authReq.CodeChallengeMethod), + }, + } +} + +func ParseBrowserInfoFromContext(ctx context.Context) *model.BrowserInfo { + userAgent, acceptLang := HttpHeadersFromContext(ctx) + ip := IpFromContext(ctx) + return &model.BrowserInfo{RemoteIP: ip, UserAgent: userAgent, AcceptLanguage: acceptLang} +} + +func HttpHeadersFromContext(ctx context.Context) (userAgent, acceptLang string) { + ctxHeaders, ok := http_utils.HeadersFromCtx(ctx) + if !ok { + return + } + if agents, ok := ctxHeaders[api_utils.UserAgent]; ok { + userAgent = agents[0] + } + if langs, ok := ctxHeaders[api_utils.AcceptLanguage]; ok { + acceptLang = langs[0] + } + return userAgent, acceptLang +} + +func IpFromContext(ctx context.Context) net.IP { + ipString := http_utils.RemoteIPFromCtx(ctx) + if ipString == "" { + return nil + } + return net.ParseIP(ipString) +} + +func PromptToBusiness(prompt oidc.Prompt) model.Prompt { + switch prompt { + case oidc.PromptNone: + return model.PromptNone + case oidc.PromptLogin: + return model.PromptLogin + case oidc.PromptConsent: + return model.PromptConsent + case oidc.PromptSelectAccount: + return model.PromptSelectAccount + default: + return model.PromptUnspecified + } +} + +func ACRValuesToBusiness(values []string) []model.LevelOfAssurance { + return nil +} + +func UILocalesToBusiness(tags []language.Tag) []string { + if tags == nil { + return nil + } + locales := make([]string, len(tags)) + for i, tag := range tags { + locales[i] = tag.String() + } + return locales +} + +func ResponseTypeToBusiness(responseType oidc.ResponseType) model.OIDCResponseType { + switch responseType { + case oidc.ResponseTypeCode: + return model.OIDCResponseTypeCode + case oidc.ResponseTypeIDToken: + return model.OIDCResponseTypeIdToken + case oidc.ResponseTypeIDTokenOnly: + return model.OIDCResponseTypeToken + default: + return model.OIDCResponseTypeCode + } +} + +func ResponseTypeToOIDC(responseType model.OIDCResponseType) oidc.ResponseType { + switch responseType { + case model.OIDCResponseTypeCode: + return oidc.ResponseTypeCode + case model.OIDCResponseTypeToken: + return oidc.ResponseTypeIDToken + case model.OIDCResponseTypeIdToken: + return oidc.ResponseTypeIDTokenOnly + default: + return oidc.ResponseTypeCode + } +} + +func CodeChallengeToBusiness(challenge string, method oidc.CodeChallengeMethod) *model.OIDCCodeChallenge { + if challenge == "" { + return nil + } + challengeMethod := model.CodeChallengeMethodPlain + if method == oidc.CodeChallengeMethodS256 { + challengeMethod = model.CodeChallengeMethodS256 + } + return &model.OIDCCodeChallenge{ + Challenge: challenge, + Method: challengeMethod, + } +} + +func CodeChallengeToOIDC(challenge *model.OIDCCodeChallenge) *oidc.CodeChallenge { + if challenge == nil { + return nil + } + challengeMethod := oidc.CodeChallengeMethodPlain + if challenge.Method == model.CodeChallengeMethodS256 { + challengeMethod = oidc.CodeChallengeMethodS256 + } + return &oidc.CodeChallenge{ + Challenge: challenge.Challenge, + Method: challengeMethod, + } +} + +func AMRFromMFAType(mfaType model.MfaType) string { + switch mfaType { + case model.MfaTypeOTP: + return amrOTP + default: + return "" + } +} diff --git a/pkg/auth/api/oidc/client.go b/pkg/auth/api/oidc/client.go new file mode 100644 index 0000000000..ba4a6aa0dc --- /dev/null +++ b/pkg/auth/api/oidc/client.go @@ -0,0 +1,97 @@ +package oidc + +import ( + "context" + + "github.com/caos/oidc/pkg/oidc" + "github.com/caos/oidc/pkg/op" + + "github.com/caos/zitadel/internal/user/model" +) + +const ( + scopeOpenID = "openid" + scopeProfile = "profile" + scopeEmail = "email" + scopePhone = "phone" + scopeAddress = "address" +) + +func (o *OPStorage) GetClientByClientID(ctx context.Context, id string) (op.Client, error) { + client, err := o.repo.ApplicationByClientID(ctx, id) + if err != nil { + return nil, err + } + return ClientFromBusiness(client, o.defaultLoginURL, o.defaultAccessTokenLifetime, o.defaultIdTokenLifetime) +} + +func (o *OPStorage) AuthorizeClientIDSecret(ctx context.Context, id string, secret string) error { + return o.repo.AuthorizeOIDCApplication(ctx, id, secret) +} + +func (o *OPStorage) GetUserinfoFromToken(ctx context.Context, tokenID string) (*oidc.Userinfo, error) { + token, err := o.repo.TokenByID(ctx, tokenID) + if err != nil { + return nil, err + } + return o.GetUserinfoFromScopes(ctx, token.UserID, token.Scopes) +} + +func (o *OPStorage) GetUserinfoFromScopes(ctx context.Context, userID string, scopes []string) (*oidc.Userinfo, error) { + user, err := o.repo.UserByID(ctx, userID) + if err != nil { + return nil, err + } + userInfo := new(oidc.Userinfo) + for _, scope := range scopes { + switch scope { + case scopeOpenID: + userInfo.Subject = user.AggregateID + case scopeEmail: + if user.Email == nil { + continue + } + userInfo.Email = user.EmailAddress + userInfo.EmailVerified = user.IsEmailVerified + case scopeProfile: + if user.Profile == nil { + continue + } + userInfo.Name = user.FirstName + " " + user.LastName + userInfo.FamilyName = user.LastName + userInfo.GivenName = user.FirstName + userInfo.Nickname = user.NickName + userInfo.PreferredUsername = user.UserName + userInfo.UpdatedAt = user.ChangeDate + userInfo.Gender = oidc.Gender(getGender(user.Gender)) + case scopePhone: + if user.Phone == nil { + continue + } + userInfo.PhoneNumber = user.PhoneNumber + userInfo.PhoneNumberVerified = user.IsPhoneVerified + case scopeAddress: + if user.Address == nil { + continue + } + userInfo.Address.StreetAddress = user.StreetAddress + userInfo.Address.Locality = user.Locality + userInfo.Address.Region = user.Region + userInfo.Address.PostalCode = user.PostalCode + userInfo.Address.Country = user.Country + } + } + return userInfo, nil +} + +func getGender(gender model.Gender) string { + switch gender { + case model.GENDER_FEMALE: + return "female" + case model.GENDER_MALE: + return "male" + case model.GENDER_DIVERSE: + return "diverse" + } + return "" +} diff --git a/pkg/auth/api/oidc/client_converter.go b/pkg/auth/api/oidc/client_converter.go new file mode 100644 index 0000000000..e2aaf3a4bf --- /dev/null +++ b/pkg/auth/api/oidc/client_converter.go @@ -0,0 +1,73 @@ +package oidc + +import ( + "time" + + "github.com/caos/oidc/pkg/op" + + "github.com/caos/zitadel/internal/errors" + "github.com/caos/zitadel/internal/project/model" +) + +type Client struct { + *model.ApplicationView + defaultLoginURL string + defaultAccessTokenLifetime time.Duration + defaultIdTokenLifetime time.Duration +} + +func ClientFromBusiness(app *model.ApplicationView, defaultLoginURL string, defaultAccessTokenLifetime, defaultIdTokenLifetime time.Duration) (op.Client, error) { + if !app.IsOIDC { + return nil, errors.ThrowInvalidArgument(nil, "OIDC-d5bhD", "client is not a proper oidc application") + } + return &Client{ApplicationView: app, defaultLoginURL: defaultLoginURL, defaultAccessTokenLifetime: defaultAccessTokenLifetime, defaultIdTokenLifetime: defaultIdTokenLifetime}, nil +} + +func (c *Client) ApplicationType() op.ApplicationType { + return op.ApplicationType(c.OIDCApplicationType) +} + +func (c *Client) GetAuthMethod() op.AuthMethod { + return authMethodToOIDC(c.OIDCAuthMethodType) +} + +func (c *Client) GetID() string { + return c.OIDCClientID +} + +func (c *Client) LoginURL(id string) string { + return c.defaultLoginURL + id +} + +func (c *Client) RedirectURIs() []string { + return c.OIDCRedirectUris +} + +func (c *Client) PostLogoutRedirectURIs() []string { + return c.OIDCPostLogoutRedirectUris +} + +func (c *Client) AccessTokenLifetime() time.Duration { + return c.defaultAccessTokenLifetime //PLANNED: impl from real client +} + +func (c *Client) IDTokenLifetime() time.Duration { + return c.defaultIdTokenLifetime //PLANNED: impl from real client +} + +func (c *Client) AccessTokenType() op.AccessTokenType { + return op.AccessTokenTypeBearer //PLANNED: impl from real client +} + +func authMethodToOIDC(authType model.OIDCAuthMethodType) op.AuthMethod { + switch authType { + case model.OIDCAUTHMETHODTYPE_BASIC: + return op.AuthMethodBasic + case model.OIDCAUTHMETHODTYPE_POST: + return op.AuthMethodPost + case model.OIDCAUTHMETHODTYPE_NONE: + return op.AuthMethodNone + default: + return op.AuthMethodBasic + } +} diff --git a/pkg/auth/api/oidc/cookie_interceptor.go b/pkg/auth/api/oidc/cookie_interceptor.go new file mode 100644 index 0000000000..9604d72047 --- /dev/null +++ b/pkg/auth/api/oidc/cookie_interceptor.go @@ -0,0 +1,37 @@ +package oidc + +import ( + "context" + "net/http" + + http_utils "github.com/caos/zitadel/internal/api/http" +) + +type key int + +var ( + userAgentKey key +) + +func UserAgentIDFromCtx(ctx context.Context) (string, bool) { + userAgentID, ok := ctx.Value(userAgentKey).(string) + return userAgentID, ok +} + +func UserAgentCookieHandler(cookieHandler *http_utils.UserAgentHandler, nextHandlerFunc func(http.HandlerFunc) http.HandlerFunc) func(http.HandlerFunc) http.HandlerFunc { + return func(handlerFunc http.HandlerFunc) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + ua, err := cookieHandler.GetUserAgent(r) + if err != nil { + ua, err = cookieHandler.NewUserAgent() + } + if err == nil { + ctx := context.WithValue(r.Context(), userAgentKey, ua.ID) + r = r.WithContext(ctx) + cookieHandler.SetUserAgent(w, ua) + } + handlerFunc(w, r) + nextHandlerFunc(handlerFunc) + } + } +} diff --git a/pkg/auth/api/oidc/op.go b/pkg/auth/api/oidc/op.go new file mode 100644 index 0000000000..628247849b --- /dev/null +++ b/pkg/auth/api/oidc/op.go @@ -0,0 +1,87 @@ +package oidc + +import ( + "context" + "time" + + "github.com/caos/logging" + "github.com/caos/oidc/pkg/op" + + http_utils "github.com/caos/zitadel/internal/api/http" + "github.com/caos/zitadel/internal/auth/repository" + "github.com/caos/zitadel/internal/config/types" + "github.com/caos/zitadel/internal/id" +) + +type OPHandlerConfig struct { + OPConfig *op.Config + StorageConfig StorageConfig + UserAgentCookieConfig *http_utils.UserAgentCookieConfig + Endpoints *EndpointConfig +} + +type StorageConfig struct { + DefaultLoginURL string + SigningKeyAlgorithm string + DefaultAccessTokenLifetime types.Duration + DefaultIdTokenLifetime types.Duration +} + +type EndpointConfig struct { + Auth *Endpoint + Token *Endpoint + Userinfo *Endpoint + EndSession *Endpoint + Keys *Endpoint +} + +type Endpoint struct { + Path string + URL string +} + +type OPStorage struct { + repo repository.Repository + defaultLoginURL string + defaultAccessTokenLifetime time.Duration + defaultIdTokenLifetime time.Duration + signingKeyAlgorithm string +} + +func NewProvider(ctx context.Context, config OPHandlerConfig, repo repository.Repository) op.OpenIDProvider { + cookieHandler, err := http_utils.NewUserAgentHandler(config.UserAgentCookieConfig, id.SonyFlakeGenerator) + logging.Log("OIDC-sd4fd").OnError(err).Panic("cannot user agent handler") + provider, err := op.NewDefaultOP( + ctx, + config.OPConfig, + newStorage(config.StorageConfig, repo), + op.WithHttpInterceptor( + UserAgentCookieHandler( + cookieHandler, + http_utils.CopyHeadersToContext, + ), + ), + op.WithCustomAuthEndpoint(op.NewEndpointWithURL(config.Endpoints.Auth.Path, config.Endpoints.Auth.URL)), + op.WithCustomTokenEndpoint(op.NewEndpointWithURL(config.Endpoints.Token.Path, config.Endpoints.Token.URL)), + op.WithCustomUserinfoEndpoint(op.NewEndpointWithURL(config.Endpoints.Userinfo.Path, config.Endpoints.Userinfo.URL)), + op.WithCustomEndSessionEndpoint(op.NewEndpointWithURL(config.Endpoints.EndSession.Path, config.Endpoints.EndSession.URL)), + op.WithCustomKeysEndpoint(op.NewEndpointWithURL(config.Endpoints.Keys.Path, config.Endpoints.Keys.URL)), + op.WithRetry(3, time.Duration(30*time.Second)), + ) + logging.Log("OIDC-asf13").OnError(err).Panic("cannot create provider") + return provider +} + +func newStorage(config StorageConfig, repo repository.Repository) *OPStorage { + return &OPStorage{ + repo: repo, + defaultLoginURL: config.DefaultLoginURL, + signingKeyAlgorithm: config.SigningKeyAlgorithm, + defaultAccessTokenLifetime: config.DefaultAccessTokenLifetime.Duration, + defaultIdTokenLifetime: config.DefaultIdTokenLifetime.Duration, + } +} + +func (o *OPStorage) Health(ctx context.Context) error { + return o.repo.Health(ctx) +} diff --git a/pkg/auth/api/proto/auth.proto b/pkg/auth/api/proto/auth.proto index 89fd78fe33..63f107c63d 100644 --- a/pkg/auth/api/proto/auth.proto +++ b/pkg/auth/api/proto/auth.proto @@ -243,20 +243,20 @@ service AuthService { }; } - rpc SearchMyProjectOrgs(MyProjectOrgSearchRequest) returns (MyProjectOrgSearchResponse) { + rpc SearchMyUserGrant(UserGrantSearchRequest) returns (UserGrantSearchResponse) { option (google.api.http) = { - post: "/global/projectorgs/_search" + post: "/usergrants/me/_search" body: "*" }; - option (caos.zitadel.utils.v1.auth_option) = { permission: "authenticated" }; } - rpc IsIamAdmin(google.protobuf.Empty) returns (IsAdminResponse) { + rpc SearchMyProjectOrgs(MyProjectOrgSearchRequest) returns (MyProjectOrgSearchResponse) { option (google.api.http) = { - get: "/global/_isiamadmin" + post: "/global/projectorgs/_search" + body: "*" }; option (caos.zitadel.utils.v1.auth_option) = { @@ -478,6 +478,41 @@ message OIDCClientAuth { string client_secret = 2; } +message UserGrantSearchRequest { + uint64 offset = 1; + uint64 limit = 2; + UserGrantSearchKey sorting_column = 3 [(validate.rules).enum = {not_in: [0]}];; + bool asc = 4; + repeated UserGrantSearchQuery queries = 5; +} + +message UserGrantSearchQuery { + UserGrantSearchKey key = 1 [(validate.rules).enum = {not_in: [0]}];; + SearchMethod method = 2; + string value = 3; +} + +enum UserGrantSearchKey { + UserGrantSearchKey_UNKNOWN = 0; + UserGrantSearchKey_ORG_ID = 1; + UserGrantSearchKey_PROJECT_ID = 2; +} + +message UserGrantSearchResponse { + uint64 offset = 1; + uint64 limit = 2; + uint64 total_result = 3; + repeated UserGrantView result = 4; +} + +message UserGrantView { + string OrgId = 1; + string ProjectId = 2; + string UserId = 3; + repeated string Roles = 4; + string OrgName = 5; +} + message MyProjectOrgSearchRequest { uint64 offset = 1; uint64 limit = 2; @@ -503,10 +538,6 @@ message MyProjectOrgSearchResponse { repeated Org result = 4; } -message IsAdminResponse { - bool is_admin = 1; -} - message Org { string id = 1; string name = 2; @@ -520,4 +551,7 @@ enum SearchMethod { SEARCHMETHOD_EQUALS = 0; SEARCHMETHOD_STARTS_WITH = 1; SEARCHMETHOD_CONTAINS = 2; -} \ No newline at end of file + SEARCHMETHOD_EQUALS_IGNORE_CASE = 3; + SEARCHMETHOD_STARTS_WITH_IGNORE_CASE = 4; + SEARCHMETHOD_CONTAINS_IGNORE_CASE = 5; +} diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go index 513ef76e03..948f23ae2d 100644 --- a/pkg/auth/auth.go +++ b/pkg/auth/auth.go @@ -2,8 +2,7 @@ package auth import ( "context" - - "github.com/caos/logging" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" "github.com/caos/zitadel/internal/api/auth" "github.com/caos/zitadel/internal/auth/repository/eventsourcing" @@ -16,9 +15,6 @@ type Config struct { Repository eventsourcing.Config } -func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) { - repo, err := eventsourcing.Start(config.Repository, systemDefaults) - logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app") - - api.Start(ctx, config.API, authZ, repo) +func Start(ctx context.Context, config Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, systemDefaults sd.SystemDefaults, authRepo *eventsourcing.EsRepository) { + api.Start(ctx, config.API, authZRepo, authZ, authRepo) } diff --git a/pkg/console/console.go b/pkg/console/console.go index c28cf8dae4..d68ededd75 100644 --- a/pkg/console/console.go +++ b/pkg/console/console.go @@ -1,5 +1,3 @@ -//go:generate statik -src=../../console/dist/app - package console import ( @@ -31,7 +29,7 @@ func (i *spaHandler) Open(name string) (http.File, error) { } func Start(ctx context.Context, config Config) error { - statikFS, err := fs.New() + statikFS, err := fs.NewWithNamespace("console") if err != nil { return err } diff --git a/pkg/console/statik/generate.go b/pkg/console/statik/generate.go new file mode 100644 index 0000000000..9156db8f23 --- /dev/null +++ b/pkg/console/statik/generate.go @@ -0,0 +1,3 @@ +package statik + +//go:generate statik -src=../../../console/dist/app -dest=.. -ns=console diff --git a/pkg/console/statik/statik.go b/pkg/console/statik/statik.go deleted file mode 100644 index defdb7673f..0000000000 --- a/pkg/console/statik/statik.go +++ /dev/null @@ -1 +0,0 @@ -package statik diff --git a/pkg/eventstore/eventstore.go b/pkg/eventstore/eventstore.go deleted file mode 100644 index d07f825e44..0000000000 --- a/pkg/eventstore/eventstore.go +++ /dev/null @@ -1,14 +0,0 @@ -package eventstore - -import ( - "context" - - "github.com/caos/zitadel/internal/errors" -) - -type Config struct { -} - -func Start(ctx context.Context, config Config) error { - return errors.ThrowUnimplemented(nil, "EVENT-1hfiu", "not implemented yet") //TODO: implement -} diff --git a/pkg/login/api/config.go b/pkg/login/api/config.go deleted file mode 100644 index feed11d83a..0000000000 --- a/pkg/login/api/config.go +++ /dev/null @@ -1,4 +0,0 @@ -package api - -type Config struct { -} diff --git a/pkg/login/login.go b/pkg/login/login.go deleted file mode 100644 index 462ba37aa1..0000000000 --- a/pkg/login/login.go +++ /dev/null @@ -1,18 +0,0 @@ -package login - -import ( - "context" - - "github.com/caos/zitadel/internal/errors" - app "github.com/caos/zitadel/internal/login" - "github.com/caos/zitadel/pkg/login/api" -) - -type Config struct { - App app.Config - API api.Config -} - -func Start(ctx context.Context, config Config) error { - return errors.ThrowUnimplemented(nil, "LOGIN-3fwvD", "not implemented yet") //TODO: implement -} diff --git a/pkg/management/api/api.go b/pkg/management/api/api.go index 0971c1b395..8bb54ccd3d 100644 --- a/pkg/management/api/api.go +++ b/pkg/management/api/api.go @@ -3,6 +3,7 @@ package api import ( "context" "github.com/caos/zitadel/internal/api/auth" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" "github.com/caos/zitadel/internal/management/repository" grpc_util "github.com/caos/zitadel/internal/api/grpc" @@ -14,8 +15,8 @@ type Config struct { GRPC grpc_util.Config } -func Start(ctx context.Context, conf Config, authZ auth.Config, repo repository.Repository) { - grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZ, repo) +func Start(ctx context.Context, conf Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) { + grpcServer := grpc.StartServer(conf.GRPC.ToServerConfig(), authZRepo, authZ, repo) grpcGateway := grpc.StartGateway(conf.GRPC.ToGatewayConfig()) server.StartServer(ctx, grpcServer) diff --git a/pkg/management/api/grpc/server.go b/pkg/management/api/grpc/server.go index f25c4309de..faa7276da8 100644 --- a/pkg/management/api/grpc/server.go +++ b/pkg/management/api/grpc/server.go @@ -4,6 +4,7 @@ import ( "github.com/caos/zitadel/internal/api/auth" grpc_util "github.com/caos/zitadel/internal/api/grpc" "github.com/caos/zitadel/internal/api/grpc/server/middleware" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" mgmt_auth "github.com/caos/zitadel/internal/management/auth" "github.com/caos/zitadel/internal/management/repository" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" @@ -23,7 +24,7 @@ type Server struct { authZ auth.Config } -func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository.Repository) *Server { +func StartServer(conf grpc_util.ServerConfig, authZRepo *authz_repo.EsRepository, authZ auth.Config, repo repository.Repository) *Server { return &Server{ port: conf.Port, project: repo, @@ -32,7 +33,7 @@ func StartServer(conf grpc_util.ServerConfig, authZ auth.Config, repo repository user: repo, usergrant: repo, authZ: authZ, - verifier: mgmt_auth.Start(), + verifier: mgmt_auth.Start(authZRepo), } } diff --git a/pkg/management/management.go b/pkg/management/management.go index f1134ce22c..355d7d796e 100644 --- a/pkg/management/management.go +++ b/pkg/management/management.go @@ -5,6 +5,7 @@ import ( "github.com/caos/logging" "github.com/caos/zitadel/internal/api/auth" + authz_repo "github.com/caos/zitadel/internal/authz/repository/eventsourcing" sd "github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/management/repository/eventsourcing" "github.com/caos/zitadel/pkg/management/api" @@ -15,7 +16,7 @@ type Config struct { API api.Config } -func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults sd.SystemDefaults) { +func Start(ctx context.Context, config Config, authZRepo *authz_repo.EsRepository, authZ auth.Config, systemDefaults sd.SystemDefaults) { roles := make([]string, len(authZ.RolePermissionMappings)) for i, role := range authZ.RolePermissionMappings { roles[i] = role.Role @@ -23,5 +24,5 @@ func Start(ctx context.Context, config Config, authZ auth.Config, systemDefaults repo, err := eventsourcing.Start(config.Repository, systemDefaults, roles) logging.Log("MAIN-9uBxp").OnError(err).Panic("unable to start app") - api.Start(ctx, config.API, authZ, repo) + api.Start(ctx, config.API, authZRepo, authZ, repo) }