Merge branch 'master' into new-eventstore

# Conflicts:
#	go.sum
This commit is contained in:
Fabiennne 2020-12-03 10:11:18 +01:00
commit 2a25c0b617
331 changed files with 6536 additions and 2046 deletions

View File

@ -32,3 +32,11 @@ updates:
commit-message: commit-message:
prefix: chore prefix: chore
include: scope include: scope
- package-ecosystem: "docker"
directory: "/site/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
commit-message:
prefix: chore
include: scope

View File

@ -17,15 +17,19 @@ jobs:
steps: steps:
- name: Checkout Repo - name: Checkout Repo
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Install and Build - uses: docker/build-push-action@v2
run: | with:
npm install context: .
npx sapper export --legacy file: ./site/dockerfile
platforms: linux/amd64
tags: zitadel:docs
push: false
outputs: type=local,dest=output
- name: Archive Production Artifact - name: Archive Production Artifact
uses: actions/upload-artifact@master uses: actions/upload-artifact@master
with: with:
name: export name: export
path: site/__sapper__/export path: output
deploydocs: deploydocs:
name: Deploy name: Deploy
needs: builddocs needs: builddocs

View File

@ -1,19 +0,0 @@
name: Spellcheck
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
spellcheck:
name: Typo CI (GitHub Action)
runs-on: ubuntu-latest
timeout-minutes: 4
if: "!contains(github.event.head_commit.message, '[ci skip]')"
steps:
- name: TypoCheck
uses: typoci/spellcheck-action@master
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@ -1,42 +0,0 @@
# What language dictionaries should it use? Currently Typo CI supports:
# de
# en
# en_GB
# es
# fr
# it
# pt
# pt_BR
dictionaries:
- en
- en_GB
- de
# Any files/folders we should ignore?
excluded_files:
- ".codecov/*"
- ".github/*"
- "build/*"
- "k8s/*"
- "*.min.css"
- "*.css.map"
- "*.min.js"
- "*.js.map"
- "package-lock.json"
- "package.json"
- ".releaserc.js"
- ".typo-ci.yml"
- ".gitignore"
- "go.mod"
- "go.sum"
# Any typos we should ignore?
excluded_words:
- typoci
- idps
- ZITADEL's
- otel
- otlp
# Would you like filenames to also be spellchecked?
spellcheck_filenames: false

View File

@ -37,7 +37,7 @@ Go check it out under [zitadel.ch](https://zitadel.ch)
### Run your own IAM ### Run your own IAM
Stay tuned, we will soon publish a guide how you can deploy a **hyperconverged** system with our automation tooling called [**ORBOS**](https://github.com/caos/orbos/). Stay tuned, we will soon publish a guide how you can deploy a **hyperconverged** system with our automation tooling called [**ORBOS**](https://github.com/caos/orbos/).
With [**ORBOS**](https://github.com/caos/orbos/) you will be able to run [**Kubernetes**](https://kubernetes.io/) on **GCE** or **StaticProvider** within 20 minutes. To achieve this, [[**ORBOS**](https://github.com/caos/orbos/) will bootstrap and maintain a [**Kubernetes**](https://kubernetes.io/) cluster, essential platform components (logging, metrics, ingress, ...), a secure [**CockroachDB**](https://www.cockroachlabs.com/) cluster and **ZITADEL** itself. With [**ORBOS**](https://github.com/caos/orbos/) you will be able to run [**Kubernetes**](https://kubernetes.io/) with Google on **[GCEProvider](https://cloud.google.com/compute)**, on **[StaticProvider](https://github.com/caos/orbos/blob/master/docs/orbiter/static.md)** for in-house scenarios or on the Swiss based **[CloudscaleProvider](https://www.cloudscale.ch/)** within 20 minutes. To achieve this, [**ORBOS**](https://github.com/caos/orbos/) will bootstrap and maintain a [**Kubernetes**](https://kubernetes.io/) cluster, essential platform components (logging, metrics, ingress, ...), a secure [**CockroachDB**](https://www.cockroachlabs.com/) cluster and **ZITADEL** itself.
The combination of the tools [**ORBOS**](https://github.com/caos/orbos/) and **ZITADEL** is what makes the operation easy and scalable. The combination of the tools [**ORBOS**](https://github.com/caos/orbos/) and **ZITADEL** is what makes the operation easy and scalable.

View File

@ -34,7 +34,7 @@ COPY internal/protoc/protoc-gen-authoption/authoption/options.proto authoption/o
## With this step we prepare all node_modules, this helps caching the build ## With this step we prepare all node_modules, this helps caching the build
## Speed up this step by mounting your local node_modules directory ## Speed up this step by mounting your local node_modules directory
####################### #######################
FROM node:12 as npm-base FROM node:15 as npm-base
WORKDIR console WORKDIR console
COPY console/package.json console/package-lock.json ./ COPY console/package.json console/package-lock.json ./
RUN npm install \ RUN npm install \

View File

@ -11,6 +11,8 @@ export ZITADEL_TRACING_FRACTION=0.1
export ZITADEL_TRACING_ENDPOINT=localhost:9096 export ZITADEL_TRACING_ENDPOINT=localhost:9096
export ZITADEL_TRACING_TYPE=google export ZITADEL_TRACING_TYPE=google
export ZITADEL_METRICS_TYPE=otel
# Log # Log
export ZITADEL_LOG_LEVEL=debug export ZITADEL_LOG_LEVEL=debug

View File

@ -3,6 +3,7 @@ package main
import ( import (
"context" "context"
"flag" "flag"
metrics "github.com/caos/zitadel/internal/telemetry/metrics/config"
"github.com/caos/logging" "github.com/caos/logging"
admin_es "github.com/caos/zitadel/internal/admin/repository/eventsourcing" admin_es "github.com/caos/zitadel/internal/admin/repository/eventsourcing"
@ -21,7 +22,7 @@ import (
mgmt_es "github.com/caos/zitadel/internal/management/repository/eventsourcing" mgmt_es "github.com/caos/zitadel/internal/management/repository/eventsourcing"
"github.com/caos/zitadel/internal/notification" "github.com/caos/zitadel/internal/notification"
"github.com/caos/zitadel/internal/setup" "github.com/caos/zitadel/internal/setup"
tracing "github.com/caos/zitadel/internal/tracing/config" tracing "github.com/caos/zitadel/internal/telemetry/tracing/config"
"github.com/caos/zitadel/internal/ui" "github.com/caos/zitadel/internal/ui"
"github.com/caos/zitadel/internal/ui/console" "github.com/caos/zitadel/internal/ui/console"
"github.com/caos/zitadel/internal/ui/login" "github.com/caos/zitadel/internal/ui/login"
@ -30,6 +31,7 @@ import (
type Config struct { type Config struct {
Log logging.Config Log logging.Config
Tracing tracing.TracingConfig Tracing tracing.TracingConfig
Metrics metrics.MetricsConfig
InternalAuthZ internal_authz.Config InternalAuthZ internal_authz.Config
SystemDefaults sd.SystemDefaults SystemDefaults sd.SystemDefaults
@ -125,14 +127,16 @@ func startUI(ctx context.Context, conf *Config, authRepo *auth_es.EsRepository)
} }
func startAPI(ctx context.Context, conf *Config, authZRepo *authz_repo.EsRepository, authRepo *auth_es.EsRepository) { func startAPI(ctx context.Context, conf *Config, authZRepo *authz_repo.EsRepository, authRepo *auth_es.EsRepository) {
apis := api.Create(conf.API, conf.InternalAuthZ, authZRepo, conf.SystemDefaults)
roles := make([]string, len(conf.InternalAuthZ.RolePermissionMappings)) roles := make([]string, len(conf.InternalAuthZ.RolePermissionMappings))
for i, role := range conf.InternalAuthZ.RolePermissionMappings { for i, role := range conf.InternalAuthZ.RolePermissionMappings {
roles[i] = role.Role roles[i] = role.Role
} }
if *adminEnabled {
adminRepo, err := admin_es.Start(ctx, conf.Admin, conf.SystemDefaults, roles) adminRepo, err := admin_es.Start(ctx, conf.Admin, conf.SystemDefaults, roles)
logging.Log("API-D42tq").OnError(err).Fatal("error starting auth repo") logging.Log("API-D42tq").OnError(err).Fatal("error starting auth repo")
apis := api.Create(conf.API, conf.InternalAuthZ, authZRepo, authRepo, adminRepo, conf.SystemDefaults)
if *adminEnabled {
apis.RegisterServer(ctx, admin.CreateServer(adminRepo)) apis.RegisterServer(ctx, admin.CreateServer(adminRepo))
} }
if *managementEnabled { if *managementEnabled {

View File

@ -97,3 +97,5 @@ SetUp:
SecondaryColor: '#ffffff' SecondaryColor: '#ffffff'
Step7: Step7:
DefaultSecondFactor: 1 #SecondFactorTypeOTP DefaultSecondFactor: 1 #SecondFactorTypeOTP
Step8:
DefaultSecondFactor: 2 #SecondFactorTypeU2F

View File

@ -11,6 +11,11 @@ Tracing:
Fraction: $ZITADEL_TRACING_FRACTION Fraction: $ZITADEL_TRACING_FRACTION
Endpoint: $ZITADEL_TRACING_ENDPOINT Endpoint: $ZITADEL_TRACING_ENDPOINT
Metrics:
Type: 'otel'
Config:
MeterName: 'github.com/caos/zitadel'
AuthZ: AuthZ:
Repository: Repository:
Eventstore: Eventstore:
@ -224,7 +229,7 @@ UI:
Login: Login:
Handler: Handler:
BaseURL: '$ZITADEL_ACCOUNTS' BaseURL: '$ZITADEL_ACCOUNTS'
OidcAuthCallbackURL: '$ZITADEL_AUTHORIZE/authorize/' OidcAuthCallbackURL: '$ZITADEL_AUTHORIZE/authorize/callback?id='
ZitadelURL: '$ZITADEL_CONSOLE' ZitadelURL: '$ZITADEL_CONSOLE'
LanguageCookieName: 'caos.zitadel.login.lang' LanguageCookieName: 'caos.zitadel.login.lang'
DefaultLanguage: 'de' DefaultLanguage: 'de'

View File

@ -53,7 +53,7 @@ SystemDefaults:
VerificationLifetimes: VerificationLifetimes:
PasswordCheck: 240h #10d PasswordCheck: 240h #10d
ExternalLoginCheck: 240h #10d ExternalLoginCheck: 240h #10d
MfaInitSkip: 720h #30d MFAInitSkip: 720h #30d
SecondFactorCheck: 18h SecondFactorCheck: 18h
MultiFactorCheck: 12h MultiFactorCheck: 12h
IamID: 'IAM' IamID: 'IAM'
@ -125,3 +125,7 @@ SystemDefaults:
Greeting: 'DomainClaimed.Greeting' Greeting: 'DomainClaimed.Greeting'
Text: 'DomainClaimed.Text' Text: 'DomainClaimed.Text'
ButtonText: 'DomainClaimed.ButtonText' ButtonText: 'DomainClaimed.ButtonText'
WebAuthN:
ID: $ZITADEL_COOKIE_DOMAIN
Origin: $ZITADEL_ACCOUNTS
DisplayName: ZITADEL

View File

@ -18,10 +18,17 @@
<td mat-cell *matCellDef="let view"> {{view.processedSequence}} </td> <td mat-cell *matCellDef="let view"> {{view.processedSequence}} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="timestamp"> <ng-container matColumnDef="eventTimestamp">
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.VIEWS.TIMESTAMP' | translate }} </th> <th mat-header-cell *matHeaderCellDef> {{ 'IAM.VIEWS.EVENTTIMESTAMP' | translate }} </th>
<td mat-cell *matCellDef="let view"> <td mat-cell *matCellDef="let view">
<span>{{view?.viewTimestamp | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span> <span>{{view?.eventTimestamp | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
</td>
</ng-container>
<ng-container matColumnDef="lastSuccessfulSpoolerRun">
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.VIEWS.LASTSPOOL' | translate }} </th>
<td mat-cell *matCellDef="let view">
<span>{{view?.lastSuccessfulSpoolerRun | timestampToDate | localizedDate: 'EEE dd. MMM, HH:mm' }}</span>
</td> </td>
</ng-container> </ng-container>

View File

@ -21,7 +21,7 @@ export class IamViewsComponent implements AfterViewInit {
@ViewChild(MatPaginator) public paginator!: MatPaginator; @ViewChild(MatPaginator) public paginator!: MatPaginator;
public dataSource!: MatTableDataSource<View.AsObject>; public dataSource!: MatTableDataSource<View.AsObject>;
public displayedColumns: string[] = ['viewName', 'database', 'sequence', 'timestamp', 'actions']; public displayedColumns: string[] = ['viewName', 'database', 'sequence', 'eventTimestamp', 'lastSuccessfulSpoolerRun', 'actions'];
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false); private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
public loading$: Observable<boolean> = this.loadingSubject.asObservable(); public loading$: Observable<boolean> = this.loadingSubject.asObservable();

View File

@ -164,8 +164,8 @@
"OTP_DIALOG_DESCRIPTION": "Scanne den QR-Code mit einer Authenticator App und verifiziere den erhaltenen Code, um OTP zu aktivieren.", "OTP_DIALOG_DESCRIPTION": "Scanne den QR-Code mit einer Authenticator App und verifiziere den erhaltenen Code, um OTP zu aktivieren.",
"TYPE": { "TYPE": {
"0":"Keine MFA definiert", "0":"Keine MFA definiert",
"1":"SMS", "1":"OTP",
"2":"OTP" "2":"U2F"
}, },
"STATE": { "STATE": {
"0": "Kein Status", "0": "Kein Status",
@ -392,7 +392,8 @@
"VIEWNAME":"Name", "VIEWNAME":"Name",
"DATABASE":"Datenbank", "DATABASE":"Datenbank",
"SEQUENCE":"Sequenz", "SEQUENCE":"Sequenz",
"TIMESTAMP":"Zeitstempel", "EVENTTIMESTAMP":"Event Zeitstempel",
"LASTSPOOL": "Erfolgreicher Durchlauf",
"ACTIONS":"Aktionen", "ACTIONS":"Aktionen",
"CLEAR":"Aufräumen", "CLEAR":"Aufräumen",
"CLEARED":"View wurde erfolgreich zurückgesetzt!", "CLEARED":"View wurde erfolgreich zurückgesetzt!",

View File

@ -164,8 +164,8 @@
"OTP_DIALOG_DESCRIPTION": "Scan the QR code with an authenticator app and enter the code below to verify and activate the OTP method.", "OTP_DIALOG_DESCRIPTION": "Scan the QR code with an authenticator app and enter the code below to verify and activate the OTP method.",
"TYPE": { "TYPE": {
"0": "No MFA defined", "0": "No MFA defined",
"1": "SMS", "1": "OTP",
"2": "OTP" "2": "U2F"
}, },
"STATE": { "STATE": {
"0": "No State", "0": "No State",
@ -392,7 +392,8 @@
"VIEWNAME":"Name", "VIEWNAME":"Name",
"DATABASE":"Database", "DATABASE":"Database",
"SEQUENCE":"Sequence", "SEQUENCE":"Sequence",
"TIMESTAMP":"Timestamp", "EVENTTIMESTAMP":"Timestamp",
"LASTSPOOL": "Successful spool",
"ACTIONS":"Actions", "ACTIONS":"Actions",
"CLEAR":"Clear", "CLEAR":"Clear",
"CLEARED":"View was successfully cleared!", "CLEARED":"View was successfully cleared!",

9
go.mod
View File

@ -15,14 +15,16 @@ require (
github.com/allegro/bigcache v1.2.1 github.com/allegro/bigcache v1.2.1
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc
github.com/caos/logging v0.0.2 github.com/caos/logging v0.0.2
github.com/caos/oidc v0.13.0 github.com/caos/oidc v0.13.1
github.com/cockroachdb/cockroach-go/v2 v2.0.8 github.com/cockroachdb/cockroach-go/v2 v2.0.8
github.com/duo-labs/webauthn v0.0.0-20200714211715-1daaee874e43
github.com/envoyproxy/protoc-gen-validate v0.4.1 github.com/envoyproxy/protoc-gen-validate v0.4.1
github.com/ghodss/yaml v1.0.0 github.com/ghodss/yaml v1.0.0
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/mock v1.4.4 github.com/golang/mock v1.4.4
github.com/golang/protobuf v1.4.3 github.com/golang/protobuf v1.4.3
github.com/golang/snappy v0.0.2 // indirect github.com/golang/snappy v0.0.2 // indirect
github.com/google/go-cmp v0.5.3 // indirect
github.com/gorilla/csrf v1.7.0 github.com/gorilla/csrf v1.7.0
github.com/gorilla/mux v1.8.0 github.com/gorilla/mux v1.8.0
github.com/gorilla/schema v1.2.0 github.com/gorilla/schema v1.2.0
@ -45,6 +47,8 @@ require (
github.com/mitchellh/reflectwalk v1.0.1 // indirect github.com/mitchellh/reflectwalk v1.0.1 // indirect
github.com/nicksnyder/go-i18n/v2 v2.1.1 github.com/nicksnyder/go-i18n/v2 v2.1.1
github.com/pquerna/otp v1.2.0 github.com/pquerna/otp v1.2.0
github.com/prometheus/client_golang v1.8.0 // indirect
github.com/prometheus/common v0.15.0 // indirect
github.com/rakyll/statik v0.1.7 github.com/rakyll/statik v0.1.7
github.com/rs/cors v1.7.0 github.com/rs/cors v1.7.0
github.com/sony/sonyflake v1.0.0 github.com/sony/sonyflake v1.0.0
@ -54,12 +58,13 @@ require (
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.13.0 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.13.0
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.13.0 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.13.0
go.opentelemetry.io/otel v0.13.0 go.opentelemetry.io/otel v0.13.0
go.opentelemetry.io/otel/exporters/metric/prometheus v0.13.0
go.opentelemetry.io/otel/exporters/otlp v0.13.0 go.opentelemetry.io/otel/exporters/otlp v0.13.0
go.opentelemetry.io/otel/exporters/stdout v0.13.0 go.opentelemetry.io/otel/exporters/stdout v0.13.0
go.opentelemetry.io/otel/sdk v0.13.0 go.opentelemetry.io/otel/sdk v0.13.0
golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897 golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 // indirect golang.org/x/net v0.0.0-20201031054903-ff519b6c9102 // indirect
golang.org/x/sys v0.0.0-20201101102859-da207088b7d1 // indirect golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect
golang.org/x/text v0.3.4 golang.org/x/text v0.3.4
golang.org/x/tools v0.0.0-20201103235415-b653051172e4 golang.org/x/tools v0.0.0-20201103235415-b653051172e4
google.golang.org/appengine v1.6.7 // indirect google.golang.org/appengine v1.6.7 // indirect

428
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@ import (
type AdministratorRepository interface { type AdministratorRepository interface {
GetFailedEvents(context.Context) ([]*model.FailedEvent, error) GetFailedEvents(context.Context) ([]*model.FailedEvent, error)
RemoveFailedEvent(context.Context, *model.FailedEvent) error RemoveFailedEvent(context.Context, *model.FailedEvent) error
GetViews(context.Context) ([]*model.View, error) GetViews() ([]*model.View, error)
ClearView(ctx context.Context, db, view string) error GetSpoolerDiv(db, viewName string) int64
ClearView(ctx context.Context, db, viewName string) error
} }

View File

@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/admin/repository/eventsourcing/view" "github.com/caos/zitadel/internal/admin/repository/eventsourcing/view"
view_model "github.com/caos/zitadel/internal/view/model" view_model "github.com/caos/zitadel/internal/view/model"
"github.com/caos/zitadel/internal/view/repository" "github.com/caos/zitadel/internal/view/repository"
"time"
) )
var dbList = []string{"management", "auth", "authz", "adminapi", "notification"} var dbList = []string{"management", "auth", "authz", "adminapi", "notification"}
@ -31,7 +32,7 @@ func (repo *AdministratorRepo) RemoveFailedEvent(ctx context.Context, failedEven
return repo.View.RemoveFailedEvent(failedEvent.Database, repository.FailedEventFromModel(failedEvent)) return repo.View.RemoveFailedEvent(failedEvent.Database, repository.FailedEventFromModel(failedEvent))
} }
func (repo *AdministratorRepo) GetViews(ctx context.Context) ([]*view_model.View, error) { func (repo *AdministratorRepo) GetViews() ([]*view_model.View, error) {
views := make([]*view_model.View, 0) views := make([]*view_model.View, 0)
for _, db := range dbList { for _, db := range dbList {
sequences, err := repo.View.AllCurrentSequences(db) sequences, err := repo.View.AllCurrentSequences(db)
@ -45,6 +46,16 @@ func (repo *AdministratorRepo) GetViews(ctx context.Context) ([]*view_model.View
return views, nil return views, nil
} }
func (repo *AdministratorRepo) GetSpoolerDiv(database, view string) int64 {
sequence, err := repo.View.GetCurrentSequence(database, view)
if err != nil {
return 0
}
divDuration := time.Now().Sub(sequence.LastSuccessfulSpoolerRun)
return divDuration.Milliseconds()
}
func (repo *AdministratorRepo) ClearView(ctx context.Context, database, view string) error { func (repo *AdministratorRepo) ClearView(ctx context.Context, database, view string) error {
return repo.View.ClearView(database, view) return repo.View.ClearView(database, view)
} }

View File

@ -15,7 +15,7 @@ import (
iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing" iam_es "github.com/caos/zitadel/internal/iam/repository/eventsourcing"
iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model" iam_es_model "github.com/caos/zitadel/internal/iam/repository/view/model"
org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_es "github.com/caos/zitadel/internal/org/repository/eventsourcing"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model" usr_model "github.com/caos/zitadel/internal/user/model"
usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing" usr_es "github.com/caos/zitadel/internal/user/repository/eventsourcing"
iam_business "github.com/caos/zitadel/internal/v2/business/iam" iam_business "github.com/caos/zitadel/internal/v2/business/iam"
@ -81,7 +81,7 @@ func (repo *IAMRepository) SearchIAMMembers(ctx context.Context, request *iam_mo
} }
if err == nil { if err == nil {
result.Sequence = sequence.CurrentSequence result.Sequence = sequence.CurrentSequence
result.Timestamp = sequence.CurrentTimestamp result.Timestamp = sequence.LastSuccessfulSpoolerRun
} }
return result, nil return result, nil
} }
@ -206,7 +206,7 @@ func (repo *IAMRepository) SearchIDPConfigs(ctx context.Context, request *iam_mo
} }
if err == nil { if err == nil {
result.Sequence = sequence.CurrentSequence result.Sequence = sequence.CurrentSequence
result.Timestamp = sequence.CurrentTimestamp result.Timestamp = sequence.LastSuccessfulSpoolerRun
} }
return result, nil return result, nil
} }
@ -298,7 +298,7 @@ func (repo *IAMRepository) SearchDefaultIDPProviders(ctx context.Context, reques
} }
if err == nil { if err == nil {
result.Sequence = sequence.CurrentSequence result.Sequence = sequence.CurrentSequence
result.Timestamp = sequence.CurrentTimestamp result.Timestamp = sequence.LastSuccessfulSpoolerRun
} }
return result, nil return result, nil
} }

View File

@ -6,7 +6,7 @@ import (
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model" iam_model "github.com/caos/zitadel/internal/iam/model"
iam_view "github.com/caos/zitadel/internal/iam/repository/view/model" iam_view "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/logging" "github.com/caos/logging"
admin_model "github.com/caos/zitadel/internal/admin/model" admin_model "github.com/caos/zitadel/internal/admin/model"
@ -101,7 +101,7 @@ func (repo *OrgRepo) SearchOrgs(ctx context.Context, query *org_model.OrgSearchR
} }
if err == nil { if err == nil {
result.Sequence = sequence.CurrentSequence result.Sequence = sequence.CurrentSequence
result.Timestamp = sequence.CurrentTimestamp result.Timestamp = sequence.LastSuccessfulSpoolerRun
} }
return result, nil return result, nil
} }

View File

@ -41,7 +41,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, ev
&IDPConfig{handler: handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount}}, &IDPConfig{handler: handler{view, bulkLimit, configs.cycleDuration("IDPConfig"), errorCount}},
&LabelPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("LabelPolicy"), errorCount}}, &LabelPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("LabelPolicy"), errorCount}},
&LoginPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("LoginPolicy"), errorCount}}, &LoginPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("LoginPolicy"), errorCount}},
&IDPProvider{handler: handler{view, bulkLimit, configs.cycleDuration("LoginPolicy"), errorCount}, &IDPProvider{handler: handler{view, bulkLimit, configs.cycleDuration("IDPProvider"), errorCount},
systemDefaults: defaults, iamEvents: repos.IamEvents, orgEvents: repos.OrgEvents}, systemDefaults: defaults, iamEvents: repos.IamEvents, orgEvents: repos.OrgEvents},
&User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount}, &User{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount},
eventstore: eventstore, orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents, systemDefaults: defaults}, eventstore: eventstore, orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents, systemDefaults: defaults},
@ -49,7 +49,7 @@ func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, ev
&PasswordAgePolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordAgePolicy"), errorCount}}, &PasswordAgePolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordAgePolicy"), errorCount}},
&PasswordLockoutPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordLockoutPolicy"), errorCount}}, &PasswordLockoutPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("PasswordLockoutPolicy"), errorCount}},
&OrgIAMPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount}}, &OrgIAMPolicy{handler: handler{view, bulkLimit, configs.cycleDuration("OrgIAMPolicy"), errorCount}},
&ExternalIDP{handler: handler{view, bulkLimit, configs.cycleDuration("User"), errorCount}, &ExternalIDP{handler: handler{view, bulkLimit, configs.cycleDuration("ExternalIDP"), errorCount},
orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents, systemDefaults: defaults}, orgEvents: repos.OrgEvents, iamEvents: repos.IamEvents, systemDefaults: defaults},
} }
} }

View File

@ -72,14 +72,14 @@ func (m *IamMember) processIamMember(event *models.Event) (err error) {
if err != nil { if err != nil {
return err return err
} }
return m.view.DeleteIAMMember(event.AggregateID, member.UserID, event.Sequence) return m.view.DeleteIAMMember(event.AggregateID, member.UserID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedIAMMemberSequence(event.Sequence) return m.view.ProcessedIAMMemberSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutIAMMember(member, member.Sequence) return m.view.PutIAMMember(member, member.Sequence, event.CreationDate)
} }
func (m *IamMember) processUser(event *models.Event) (err error) { func (m *IamMember) processUser(event *models.Event) (err error) {
@ -94,7 +94,7 @@ func (m *IamMember) processUser(event *models.Event) (err error) {
return err return err
} }
if len(members) == 0 { if len(members) == 0 {
return m.view.ProcessedIAMMemberSequence(event.Sequence) return m.view.ProcessedIAMMemberSequence(event.Sequence, event.CreationDate)
} }
user, err := m.userEvents.UserByID(context.Background(), event.AggregateID) user, err := m.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil { if err != nil {
@ -103,11 +103,11 @@ func (m *IamMember) processUser(event *models.Event) (err error) {
for _, member := range members { for _, member := range members {
m.fillUserData(member, user) m.fillUserData(member, user)
} }
return m.view.PutIAMMembers(members, event.Sequence) return m.view.PutIAMMembers(members, event.Sequence, event.CreationDate)
case usr_es_model.UserRemoved: case usr_es_model.UserRemoved:
return m.view.DeleteIAMMembersByUserID(event.AggregateID, event.Sequence) return m.view.DeleteIAMMembersByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedIAMMemberSequence(event.Sequence) return m.view.ProcessedIAMMemberSequence(event.Sequence, event.CreationDate)
} }
return nil return nil
} }
@ -137,3 +137,7 @@ func (m *IamMember) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Ld9ow", "id", event.AggregateID).WithError(err).Warn("something went wrong in iammember handler") logging.LogWithFields("SPOOL-Ld9ow", "id", event.AggregateID).WithError(err).Warn("something went wrong in iammember handler")
return spooler.HandleError(event, err, m.view.GetLatestIAMMemberFailedEvent, m.view.ProcessedIAMMemberFailedEvent, m.view.ProcessedIAMMemberSequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, m.view.GetLatestIAMMemberFailedEvent, m.view.ProcessedIAMMemberFailedEvent, m.view.ProcessedIAMMemberSequence, m.errorCountUntilSkip)
} }
func (m *IamMember) OnSuccess() error {
return spooler.HandleSuccess(m.view.UpdateIAMMemberSpoolerRunTimestamp)
}

View File

@ -19,12 +19,12 @@ const (
idpConfigTable = "adminapi.idp_configs" idpConfigTable = "adminapi.idp_configs"
) )
func (m *IDPConfig) ViewModel() string { func (i *IDPConfig) ViewModel() string {
return idpConfigTable return idpConfigTable
} }
func (m *IDPConfig) EventQuery() (*models.SearchQuery, error) { func (i *IDPConfig) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestIDPConfigSequence() sequence, err := i.view.GetLatestIDPConfigSequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -33,15 +33,15 @@ func (m *IDPConfig) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *IDPConfig) Reduce(event *models.Event) (err error) { func (i *IDPConfig) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.IAMAggregate: case model.IAMAggregate:
err = m.processIDPConfig(event) err = i.processIDPConfig(event)
} }
return err return err
} }
func (m *IDPConfig) processIDPConfig(event *models.Event) (err error) { func (i *IDPConfig) processIDPConfig(event *models.Event) (err error) {
idp := new(iam_view_model.IDPConfigView) idp := new(iam_view_model.IDPConfigView)
switch event.Type { switch event.Type {
case model.IDPConfigAdded: case model.IDPConfigAdded:
@ -53,7 +53,7 @@ func (m *IDPConfig) processIDPConfig(event *models.Event) (err error) {
if err != nil { if err != nil {
return err return err
} }
idp, err = m.view.IDPConfigByID(idp.IDPConfigID) idp, err = i.view.IDPConfigByID(idp.IDPConfigID)
if err != nil { if err != nil {
return err return err
} }
@ -63,17 +63,21 @@ func (m *IDPConfig) processIDPConfig(event *models.Event) (err error) {
if err != nil { if err != nil {
return err return err
} }
return m.view.DeleteIDPConfig(idp.IDPConfigID, event.Sequence) return i.view.DeleteIDPConfig(idp.IDPConfigID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedIDPConfigSequence(event.Sequence) return i.view.ProcessedIDPConfigSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutIDPConfig(idp, idp.Sequence) return i.view.PutIDPConfig(idp, idp.Sequence, event.CreationDate)
} }
func (m *IDPConfig) OnError(event *models.Event, err error) error { func (i *IDPConfig) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Mslo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp config handler") logging.LogWithFields("SPOOL-Mslo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp config handler")
return spooler.HandleError(event, err, m.view.GetLatestIDPConfigFailedEvent, m.view.ProcessedIDPConfigFailedEvent, m.view.ProcessedIDPConfigSequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, i.view.GetLatestIDPConfigFailedEvent, i.view.ProcessedIDPConfigFailedEvent, i.view.ProcessedIDPConfigSequence, i.errorCountUntilSkip)
}
func (i *IDPConfig) OnSuccess() error {
return spooler.HandleSuccess(i.view.UpdateIDPConfigSpoolerRunTimestamp)
} }

View File

@ -27,12 +27,12 @@ const (
idpProviderTable = "adminapi.idp_providers" idpProviderTable = "adminapi.idp_providers"
) )
func (m *IDPProvider) ViewModel() string { func (i *IDPProvider) ViewModel() string {
return idpProviderTable return idpProviderTable
} }
func (m *IDPProvider) EventQuery() (*models.SearchQuery, error) { func (i *IDPProvider) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestIDPProviderSequence() sequence, err := i.view.GetLatestIDPProviderSequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -41,15 +41,15 @@ func (m *IDPProvider) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *IDPProvider) Reduce(event *models.Event) (err error) { func (i *IDPProvider) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.IAMAggregate, org_es_model.OrgAggregate: case model.IAMAggregate, org_es_model.OrgAggregate:
err = m.processIdpProvider(event) err = i.processIdpProvider(event)
} }
return err return err
} }
func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) { func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) {
provider := new(iam_view_model.IDPProviderView) provider := new(iam_view_model.IDPProviderView)
switch event.Type { switch event.Type {
case model.LoginPolicyIDPProviderAdded, org_es_model.LoginPolicyIDPProviderAdded: case model.LoginPolicyIDPProviderAdded, org_es_model.LoginPolicyIDPProviderAdded:
@ -57,64 +57,68 @@ func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) {
if err != nil { if err != nil {
return err return err
} }
err = m.fillData(provider) err = i.fillData(provider)
case model.LoginPolicyIDPProviderRemoved, model.LoginPolicyIDPProviderCascadeRemoved, case model.LoginPolicyIDPProviderRemoved, model.LoginPolicyIDPProviderCascadeRemoved,
org_es_model.LoginPolicyIDPProviderRemoved, org_es_model.LoginPolicyIDPProviderCascadeRemoved: org_es_model.LoginPolicyIDPProviderRemoved, org_es_model.LoginPolicyIDPProviderCascadeRemoved:
err = provider.SetData(event) err = provider.SetData(event)
if err != nil { if err != nil {
return err return err
} }
return m.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event.Sequence) return i.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event.Sequence, event.CreationDate)
case model.IDPConfigChanged, org_es_model.IDPConfigChanged: case model.IDPConfigChanged, org_es_model.IDPConfigChanged:
esConfig := new(iam_view_model.IDPConfigView) esConfig := new(iam_view_model.IDPConfigView)
providerType := iam_model.IDPProviderTypeSystem providerType := iam_model.IDPProviderTypeSystem
if event.AggregateID != m.systemDefaults.IamID { if event.AggregateID != i.systemDefaults.IamID {
providerType = iam_model.IDPProviderTypeOrg providerType = iam_model.IDPProviderTypeOrg
} }
esConfig.AppendEvent(providerType, event) esConfig.AppendEvent(providerType, event)
providers, err := m.view.IDPProvidersByIdpConfigID(esConfig.IDPConfigID) providers, err := i.view.IDPProvidersByIdpConfigID(esConfig.IDPConfigID)
if err != nil { if err != nil {
return err return err
} }
config, err := m.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID) config, err := i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID)
if err != nil { if err != nil {
return err return err
} }
for _, provider := range providers { for _, provider := range providers {
m.fillConfigData(provider, config) i.fillConfigData(provider, config)
} }
return m.view.PutIDPProviders(event.Sequence, providers...) return i.view.PutIDPProviders(event.Sequence, event.CreationDate, providers...)
default: default:
return m.view.ProcessedIDPProviderSequence(event.Sequence) return i.view.ProcessedIDPProviderSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutIDPProvider(provider, provider.Sequence) return i.view.PutIDPProvider(provider, provider.Sequence, event.CreationDate)
} }
func (m *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) { func (i *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) {
var config *iam_model.IDPConfig var config *iam_model.IDPConfig
if provider.IDPProviderType == int32(iam_model.IDPProviderTypeSystem) { if provider.IDPProviderType == int32(iam_model.IDPProviderTypeSystem) {
config, err = m.iamEvents.GetIDPConfig(context.Background(), m.systemDefaults.IamID, provider.IDPConfigID) config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, provider.IDPConfigID)
} else { } else {
config, err = m.orgEvents.GetIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID) config, err = i.orgEvents.GetIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID)
} }
if err != nil { if err != nil {
return err return err
} }
m.fillConfigData(provider, config) i.fillConfigData(provider, config)
return nil return nil
} }
func (m *IDPProvider) fillConfigData(provider *iam_view_model.IDPProviderView, config *iam_model.IDPConfig) { func (i *IDPProvider) fillConfigData(provider *iam_view_model.IDPProviderView, config *iam_model.IDPConfig) {
provider.Name = config.Name provider.Name = config.Name
provider.StylingType = int32(config.StylingType) provider.StylingType = int32(config.StylingType)
provider.IDPConfigType = int32(config.Type) provider.IDPConfigType = int32(config.Type)
provider.IDPState = int32(config.State) provider.IDPState = int32(config.State)
} }
func (m *IDPProvider) OnError(event *models.Event, err error) error { func (i *IDPProvider) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Msj8c", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler") logging.LogWithFields("SPOOL-Msj8c", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler")
return spooler.HandleError(event, err, m.view.GetLatestIDPProviderFailedEvent, m.view.ProcessedIDPProviderFailedEvent, m.view.ProcessedIDPProviderSequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, i.view.GetLatestIDPProviderFailedEvent, i.view.ProcessedIDPProviderFailedEvent, i.view.ProcessedIDPProviderSequence, i.errorCountUntilSkip)
}
func (i *IDPProvider) OnSuccess() error {
return spooler.HandleSuccess(i.view.UpdateIDPProviderSpoolerRunTimestamp)
} }

View File

@ -18,12 +18,12 @@ const (
labelPolicyTable = "adminapi.label_policies" labelPolicyTable = "adminapi.label_policies"
) )
func (m *LabelPolicy) ViewModel() string { func (p *LabelPolicy) ViewModel() string {
return labelPolicyTable return labelPolicyTable
} }
func (m *LabelPolicy) EventQuery() (*models.SearchQuery, error) { func (p *LabelPolicy) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestLabelPolicySequence() sequence, err := p.view.GetLatestLabelPolicySequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -32,35 +32,39 @@ func (m *LabelPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *LabelPolicy) Reduce(event *models.Event) (err error) { func (p *LabelPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.IAMAggregate: case model.IAMAggregate:
err = m.processLabelPolicy(event) err = p.processLabelPolicy(event)
} }
return err return err
} }
func (m *LabelPolicy) processLabelPolicy(event *models.Event) (err error) { func (p *LabelPolicy) processLabelPolicy(event *models.Event) (err error) {
policy := new(iam_model.LabelPolicyView) policy := new(iam_model.LabelPolicyView)
switch event.Type { switch event.Type {
case model.LabelPolicyAdded: case model.LabelPolicyAdded:
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case model.LabelPolicyChanged: case model.LabelPolicyChanged:
policy, err = m.view.LabelPolicyByAggregateID(event.AggregateID) policy, err = p.view.LabelPolicyByAggregateID(event.AggregateID)
if err != nil { if err != nil {
return err return err
} }
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
default: default:
return m.view.ProcessedLabelPolicySequence(event.Sequence) return p.view.ProcessedLabelPolicySequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutLabelPolicy(policy, policy.Sequence) return p.view.PutLabelPolicy(policy, policy.Sequence, event.CreationDate)
} }
func (m *LabelPolicy) OnError(event *models.Event, err error) error { func (p *LabelPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Wj8sf", "id", event.AggregateID).WithError(err).Warn("something went wrong in label policy handler") logging.LogWithFields("SPOOL-Wj8sf", "id", event.AggregateID).WithError(err).Warn("something went wrong in label policy handler")
return spooler.HandleError(event, err, m.view.GetLatestLabelPolicyFailedEvent, m.view.ProcessedLabelPolicyFailedEvent, m.view.ProcessedLabelPolicySequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, p.view.GetLatestLabelPolicyFailedEvent, p.view.ProcessedLabelPolicyFailedEvent, p.view.ProcessedLabelPolicySequence, p.errorCountUntilSkip)
}
func (p *LabelPolicy) OnSuccess() error {
return spooler.HandleSuccess(p.view.UpdateLabelPolicySpoolerRunTimestamp)
} }

View File

@ -18,12 +18,12 @@ const (
loginPolicyTable = "adminapi.login_policies" loginPolicyTable = "adminapi.login_policies"
) )
func (m *LoginPolicy) ViewModel() string { func (p *LoginPolicy) ViewModel() string {
return loginPolicyTable return loginPolicyTable
} }
func (m *LoginPolicy) EventQuery() (*models.SearchQuery, error) { func (p *LoginPolicy) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestLoginPolicySequence() sequence, err := p.view.GetLatestLoginPolicySequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -32,15 +32,15 @@ func (m *LoginPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *LoginPolicy) Reduce(event *models.Event) (err error) { func (p *LoginPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.IAMAggregate: case model.IAMAggregate:
err = m.processLoginPolicy(event) err = p.processLoginPolicy(event)
} }
return err return err
} }
func (m *LoginPolicy) processLoginPolicy(event *models.Event) (err error) { func (p *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
policy := new(iam_model.LoginPolicyView) policy := new(iam_model.LoginPolicyView)
switch event.Type { switch event.Type {
case model.LoginPolicyAdded: case model.LoginPolicyAdded:
@ -50,21 +50,25 @@ func (m *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
model.LoginPolicySecondFactorRemoved, model.LoginPolicySecondFactorRemoved,
model.LoginPolicyMultiFactorAdded, model.LoginPolicyMultiFactorAdded,
model.LoginPolicyMultiFactorRemoved: model.LoginPolicyMultiFactorRemoved:
policy, err = m.view.LoginPolicyByAggregateID(event.AggregateID) policy, err = p.view.LoginPolicyByAggregateID(event.AggregateID)
if err != nil { if err != nil {
return err return err
} }
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
default: default:
return m.view.ProcessedLoginPolicySequence(event.Sequence) return p.view.ProcessedLoginPolicySequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutLoginPolicy(policy, policy.Sequence) return p.view.PutLoginPolicy(policy, policy.Sequence, event.CreationDate)
} }
func (m *LoginPolicy) OnError(event *models.Event, err error) error { func (p *LoginPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Wj8sf", "id", event.AggregateID).WithError(err).Warn("something went wrong in login policy handler") logging.LogWithFields("SPOOL-Wj8sf", "id", event.AggregateID).WithError(err).Warn("something went wrong in login policy handler")
return spooler.HandleError(event, err, m.view.GetLatestLoginPolicyFailedEvent, m.view.ProcessedLoginPolicyFailedEvent, m.view.ProcessedLoginPolicySequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, p.view.GetLatestLoginPolicyFailedEvent, p.view.ProcessedLoginPolicyFailedEvent, p.view.ProcessedLoginPolicySequence, p.errorCountUntilSkip)
}
func (p *LoginPolicy) OnSuccess() error {
return spooler.HandleSuccess(p.view.UpdateLoginPolicySpoolerRunTimestamp)
} }

View File

@ -53,13 +53,17 @@ func (o *Org) Reduce(event *es_models.Event) error {
return err return err
} }
default: default:
return o.view.ProcessedOrgSequence(event.Sequence) return o.view.ProcessedOrgSequence(event.Sequence, event.CreationDate)
} }
return o.view.PutOrg(org) return o.view.PutOrg(org, event.CreationDate)
} }
func (o *Org) OnError(event *es_models.Event, spoolerErr error) error { func (o *Org) OnError(event *es_models.Event, spoolerErr error) error {
logging.LogWithFields("SPOOL-ls9ew", "id", event.AggregateID).WithError(spoolerErr).Warn("something went wrong in project app handler") logging.LogWithFields("SPOOL-ls9ew", "id", event.AggregateID).WithError(spoolerErr).Warn("something went wrong in project app handler")
return spooler.HandleError(event, spoolerErr, o.view.GetLatestOrgFailedEvent, o.view.ProcessedOrgFailedEvent, o.view.ProcessedOrgSequence, o.errorCountUntilSkip) return spooler.HandleError(event, spoolerErr, o.view.GetLatestOrgFailedEvent, o.view.ProcessedOrgFailedEvent, o.view.ProcessedOrgSequence, o.errorCountUntilSkip)
} }
func (o *Org) OnSuccess() error {
return spooler.HandleSuccess(o.view.UpdateOrgSpoolerRunTimestamp)
}

View File

@ -19,12 +19,12 @@ const (
orgIAMPolicyTable = "adminapi.org_iam_policies" orgIAMPolicyTable = "adminapi.org_iam_policies"
) )
func (m *OrgIAMPolicy) ViewModel() string { func (p *OrgIAMPolicy) ViewModel() string {
return orgIAMPolicyTable return orgIAMPolicyTable
} }
func (m *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) { func (p *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestOrgIAMPolicySequence() sequence, err := p.view.GetLatestOrgIAMPolicySequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -33,37 +33,41 @@ func (m *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *OrgIAMPolicy) Reduce(event *models.Event) (err error) { func (p *OrgIAMPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate: case model.OrgAggregate, iam_es_model.IAMAggregate:
err = m.processOrgIAMPolicy(event) err = p.processOrgIAMPolicy(event)
} }
return err return err
} }
func (m *OrgIAMPolicy) processOrgIAMPolicy(event *models.Event) (err error) { func (p *OrgIAMPolicy) processOrgIAMPolicy(event *models.Event) (err error) {
policy := new(iam_model.OrgIAMPolicyView) policy := new(iam_model.OrgIAMPolicyView)
switch event.Type { switch event.Type {
case iam_es_model.OrgIAMPolicyAdded, model.OrgIAMPolicyAdded: case iam_es_model.OrgIAMPolicyAdded, model.OrgIAMPolicyAdded:
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case iam_es_model.OrgIAMPolicyChanged, model.OrgIAMPolicyChanged: case iam_es_model.OrgIAMPolicyChanged, model.OrgIAMPolicyChanged:
policy, err = m.view.OrgIAMPolicyByAggregateID(event.AggregateID) policy, err = p.view.OrgIAMPolicyByAggregateID(event.AggregateID)
if err != nil { if err != nil {
return err return err
} }
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case model.OrgIAMPolicyRemoved: case model.OrgIAMPolicyRemoved:
return m.view.DeleteOrgIAMPolicy(event.AggregateID, event.Sequence) return p.view.DeleteOrgIAMPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedOrgIAMPolicySequence(event.Sequence) return p.view.ProcessedOrgIAMPolicySequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutOrgIAMPolicy(policy, policy.Sequence) return p.view.PutOrgIAMPolicy(policy, policy.Sequence, event.CreationDate)
} }
func (m *OrgIAMPolicy) OnError(event *models.Event, err error) error { func (p *OrgIAMPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Wm8fs", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgIAM policy handler") logging.LogWithFields("SPOOL-Wm8fs", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgIAM policy handler")
return spooler.HandleError(event, err, m.view.GetLatestOrgIAMPolicyFailedEvent, m.view.ProcessedOrgIAMPolicyFailedEvent, m.view.ProcessedOrgIAMPolicySequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, p.view.GetLatestOrgIAMPolicyFailedEvent, p.view.ProcessedOrgIAMPolicyFailedEvent, p.view.ProcessedOrgIAMPolicySequence, p.errorCountUntilSkip)
}
func (p *OrgIAMPolicy) OnSuccess() error {
return spooler.HandleSuccess(p.view.UpdateOrgIAMPolicySpoolerRunTimestamp)
} }

View File

@ -19,12 +19,12 @@ const (
passwordAgePolicyTable = "adminapi.password_age_policies" passwordAgePolicyTable = "adminapi.password_age_policies"
) )
func (m *PasswordAgePolicy) ViewModel() string { func (p *PasswordAgePolicy) ViewModel() string {
return passwordAgePolicyTable return passwordAgePolicyTable
} }
func (m *PasswordAgePolicy) EventQuery() (*models.SearchQuery, error) { func (p *PasswordAgePolicy) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestPasswordAgePolicySequence() sequence, err := p.view.GetLatestPasswordAgePolicySequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -33,37 +33,41 @@ func (m *PasswordAgePolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *PasswordAgePolicy) Reduce(event *models.Event) (err error) { func (p *PasswordAgePolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate: case model.OrgAggregate, iam_es_model.IAMAggregate:
err = m.processPasswordAgePolicy(event) err = p.processPasswordAgePolicy(event)
} }
return err return err
} }
func (m *PasswordAgePolicy) processPasswordAgePolicy(event *models.Event) (err error) { func (p *PasswordAgePolicy) processPasswordAgePolicy(event *models.Event) (err error) {
policy := new(iam_model.PasswordAgePolicyView) policy := new(iam_model.PasswordAgePolicyView)
switch event.Type { switch event.Type {
case iam_es_model.PasswordAgePolicyAdded, model.PasswordAgePolicyAdded: case iam_es_model.PasswordAgePolicyAdded, model.PasswordAgePolicyAdded:
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case iam_es_model.PasswordAgePolicyChanged, model.PasswordAgePolicyChanged: case iam_es_model.PasswordAgePolicyChanged, model.PasswordAgePolicyChanged:
policy, err = m.view.PasswordAgePolicyByAggregateID(event.AggregateID) policy, err = p.view.PasswordAgePolicyByAggregateID(event.AggregateID)
if err != nil { if err != nil {
return err return err
} }
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case model.PasswordAgePolicyRemoved: case model.PasswordAgePolicyRemoved:
return m.view.DeletePasswordAgePolicy(event.AggregateID, event.Sequence) return p.view.DeletePasswordAgePolicy(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedPasswordAgePolicySequence(event.Sequence) return p.view.ProcessedPasswordAgePolicySequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutPasswordAgePolicy(policy, policy.Sequence) return p.view.PutPasswordAgePolicy(policy, policy.Sequence, event.CreationDate)
} }
func (m *PasswordAgePolicy) OnError(event *models.Event, err error) error { func (p *PasswordAgePolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-nD8sie", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordAge policy handler") logging.LogWithFields("SPOOL-nD8sie", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordAge policy handler")
return spooler.HandleError(event, err, m.view.GetLatestPasswordAgePolicyFailedEvent, m.view.ProcessedPasswordAgePolicyFailedEvent, m.view.ProcessedPasswordAgePolicySequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, p.view.GetLatestPasswordAgePolicyFailedEvent, p.view.ProcessedPasswordAgePolicyFailedEvent, p.view.ProcessedPasswordAgePolicySequence, p.errorCountUntilSkip)
}
func (p *PasswordAgePolicy) OnSuccess() error {
return spooler.HandleSuccess(p.view.UpdateProcessedPasswordAgePolicySpoolerRunTimestamp)
} }

View File

@ -19,12 +19,12 @@ const (
passwordComplexityPolicyTable = "adminapi.password_complexity_policies" passwordComplexityPolicyTable = "adminapi.password_complexity_policies"
) )
func (m *PasswordComplexityPolicy) ViewModel() string { func (p *PasswordComplexityPolicy) ViewModel() string {
return passwordComplexityPolicyTable return passwordComplexityPolicyTable
} }
func (m *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) { func (p *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestPasswordComplexityPolicySequence() sequence, err := p.view.GetLatestPasswordComplexityPolicySequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -33,37 +33,41 @@ func (m *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *PasswordComplexityPolicy) Reduce(event *models.Event) (err error) { func (p *PasswordComplexityPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate: case model.OrgAggregate, iam_es_model.IAMAggregate:
err = m.processPasswordComplexityPolicy(event) err = p.processPasswordComplexityPolicy(event)
} }
return err return err
} }
func (m *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *models.Event) (err error) { func (p *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *models.Event) (err error) {
policy := new(iam_model.PasswordComplexityPolicyView) policy := new(iam_model.PasswordComplexityPolicyView)
switch event.Type { switch event.Type {
case iam_es_model.PasswordComplexityPolicyAdded, model.PasswordComplexityPolicyAdded: case iam_es_model.PasswordComplexityPolicyAdded, model.PasswordComplexityPolicyAdded:
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case iam_es_model.PasswordComplexityPolicyChanged, model.PasswordComplexityPolicyChanged: case iam_es_model.PasswordComplexityPolicyChanged, model.PasswordComplexityPolicyChanged:
policy, err = m.view.PasswordComplexityPolicyByAggregateID(event.AggregateID) policy, err = p.view.PasswordComplexityPolicyByAggregateID(event.AggregateID)
if err != nil { if err != nil {
return err return err
} }
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case model.PasswordComplexityPolicyRemoved: case model.PasswordComplexityPolicyRemoved:
return m.view.DeletePasswordComplexityPolicy(event.AggregateID, event.Sequence) return p.view.DeletePasswordComplexityPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedPasswordComplexityPolicySequence(event.Sequence) return p.view.ProcessedPasswordComplexityPolicySequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutPasswordComplexityPolicy(policy, policy.Sequence) return p.view.PutPasswordComplexityPolicy(policy, policy.Sequence, event.CreationDate)
} }
func (m *PasswordComplexityPolicy) OnError(event *models.Event, err error) error { func (p *PasswordComplexityPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Wm8fs", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordComplexity policy handler") logging.LogWithFields("SPOOL-Wm8fs", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordComplexity policy handler")
return spooler.HandleError(event, err, m.view.GetLatestPasswordComplexityPolicyFailedEvent, m.view.ProcessedPasswordComplexityPolicyFailedEvent, m.view.ProcessedPasswordComplexityPolicySequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, p.view.GetLatestPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicySequence, p.errorCountUntilSkip)
}
func (p *PasswordComplexityPolicy) OnSuccess() error {
return spooler.HandleSuccess(p.view.UpdatePasswordComplexityPolicySpoolerRunTimestamp)
} }

View File

@ -19,12 +19,12 @@ const (
passwordLockoutPolicyTable = "adminapi.password_lockout_policies" passwordLockoutPolicyTable = "adminapi.password_lockout_policies"
) )
func (m *PasswordLockoutPolicy) ViewModel() string { func (p *PasswordLockoutPolicy) ViewModel() string {
return passwordLockoutPolicyTable return passwordLockoutPolicyTable
} }
func (m *PasswordLockoutPolicy) EventQuery() (*models.SearchQuery, error) { func (p *PasswordLockoutPolicy) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestPasswordLockoutPolicySequence() sequence, err := p.view.GetLatestPasswordLockoutPolicySequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -33,37 +33,41 @@ func (m *PasswordLockoutPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *PasswordLockoutPolicy) Reduce(event *models.Event) (err error) { func (p *PasswordLockoutPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate: case model.OrgAggregate, iam_es_model.IAMAggregate:
err = m.processPasswordLockoutPolicy(event) err = p.processPasswordLockoutPolicy(event)
} }
return err return err
} }
func (m *PasswordLockoutPolicy) processPasswordLockoutPolicy(event *models.Event) (err error) { func (p *PasswordLockoutPolicy) processPasswordLockoutPolicy(event *models.Event) (err error) {
policy := new(iam_model.PasswordLockoutPolicyView) policy := new(iam_model.PasswordLockoutPolicyView)
switch event.Type { switch event.Type {
case iam_es_model.PasswordLockoutPolicyAdded, model.PasswordLockoutPolicyAdded: case iam_es_model.PasswordLockoutPolicyAdded, model.PasswordLockoutPolicyAdded:
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case iam_es_model.PasswordLockoutPolicyChanged, model.PasswordLockoutPolicyChanged: case iam_es_model.PasswordLockoutPolicyChanged, model.PasswordLockoutPolicyChanged:
policy, err = m.view.PasswordLockoutPolicyByAggregateID(event.AggregateID) policy, err = p.view.PasswordLockoutPolicyByAggregateID(event.AggregateID)
if err != nil { if err != nil {
return err return err
} }
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case model.PasswordLockoutPolicyRemoved: case model.PasswordLockoutPolicyRemoved:
return m.view.DeletePasswordLockoutPolicy(event.AggregateID, event.Sequence) return p.view.DeletePasswordLockoutPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedPasswordLockoutPolicySequence(event.Sequence) return p.view.ProcessedPasswordLockoutPolicySequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutPasswordLockoutPolicy(policy, policy.Sequence) return p.view.PutPasswordLockoutPolicy(policy, policy.Sequence, event.CreationDate)
} }
func (m *PasswordLockoutPolicy) OnError(event *models.Event, err error) error { func (p *PasswordLockoutPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-nD8sie", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordLockout policy handler") logging.LogWithFields("SPOOL-nD8sie", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordLockout policy handler")
return spooler.HandleError(event, err, m.view.GetLatestPasswordLockoutPolicyFailedEvent, m.view.ProcessedPasswordLockoutPolicyFailedEvent, m.view.ProcessedPasswordLockoutPolicySequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, p.view.GetLatestPasswordLockoutPolicyFailedEvent, p.view.ProcessedPasswordLockoutPolicyFailedEvent, p.view.ProcessedPasswordLockoutPolicySequence, p.errorCountUntilSkip)
}
func (p *PasswordLockoutPolicy) OnSuccess() error {
return spooler.HandleSuccess(p.view.UpdatePasswordLockoutPolicySpoolerRunTimestamp)
} }

View File

@ -92,6 +92,12 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
es_model.HumanMFAOTPAdded, es_model.HumanMFAOTPAdded,
es_model.HumanMFAOTPVerified, es_model.HumanMFAOTPVerified,
es_model.HumanMFAOTPRemoved, es_model.HumanMFAOTPRemoved,
es_model.HumanMFAU2FTokenAdded,
es_model.HumanMFAU2FTokenVerified,
es_model.HumanMFAU2FTokenRemoved,
es_model.HumanPasswordlessTokenAdded,
es_model.HumanPasswordlessTokenVerified,
es_model.HumanPasswordlessTokenRemoved,
es_model.MachineChanged: es_model.MachineChanged:
user, err = u.view.UserByID(event.AggregateID) user, err = u.view.UserByID(event.AggregateID)
if err != nil { if err != nil {
@ -110,14 +116,14 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
} }
err = u.fillLoginNames(user) err = u.fillLoginNames(user)
case es_model.UserRemoved: case es_model.UserRemoved:
return u.view.DeleteUser(event.AggregateID, event.Sequence) return u.view.DeleteUser(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return u.view.ProcessedUserSequence(event.Sequence) return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return u.view.PutUser(user, user.Sequence) return u.view.PutUser(user, user.Sequence, event.CreationDate)
} }
func (u *User) ProcessOrg(event *models.Event) (err error) { func (u *User) ProcessOrg(event *models.Event) (err error) {
@ -131,7 +137,7 @@ func (u *User) ProcessOrg(event *models.Event) (err error) {
case org_es_model.OrgDomainPrimarySet: case org_es_model.OrgDomainPrimarySet:
return u.fillPreferredLoginNamesOnOrgUsers(event) return u.fillPreferredLoginNamesOnOrgUsers(event)
default: default:
return u.view.ProcessedUserSequence(event.Sequence) return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
} }
} }
@ -154,7 +160,7 @@ func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users { for _, user := range users {
user.SetLoginNames(policy, org.Domains) user.SetLoginNames(policy, org.Domains)
} }
return u.view.PutUsers(users, event.Sequence) return u.view.PutUsers(users, event.Sequence, event.CreationDate)
} }
func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error { func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
@ -179,7 +185,7 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users { for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain) user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
} }
return u.view.PutUsers(users, event.Sequence) return u.view.PutUsers(users, event.Sequence, event.CreationDate)
} }
func (u *User) fillLoginNames(user *view_model.UserView) (err error) { func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
@ -203,3 +209,7 @@ func (u *User) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-vLmwQ", "id", event.AggregateID).WithError(err).Warn("something went wrong in user handler") logging.LogWithFields("SPOOL-vLmwQ", "id", event.AggregateID).WithError(err).Warn("something went wrong in user handler")
return spooler.HandleError(event, err, u.view.GetLatestUserFailedEvent, u.view.ProcessedUserFailedEvent, u.view.ProcessedUserSequence, u.errorCountUntilSkip) return spooler.HandleError(event, err, u.view.GetLatestUserFailedEvent, u.view.ProcessedUserFailedEvent, u.view.ProcessedUserSequence, u.errorCountUntilSkip)
} }
func (u *User) OnSuccess() error {
return spooler.HandleSuccess(u.view.UpdateUserSpoolerRunTimestamp)
}

View File

@ -30,12 +30,12 @@ const (
externalIDPTable = "adminapi.user_external_idps" externalIDPTable = "adminapi.user_external_idps"
) )
func (m *ExternalIDP) ViewModel() string { func (i *ExternalIDP) ViewModel() string {
return externalIDPTable return externalIDPTable
} }
func (m *ExternalIDP) EventQuery() (*models.SearchQuery, error) { func (i *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestExternalIDPSequence() sequence, err := i.view.GetLatestExternalIDPSequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -44,17 +44,17 @@ func (m *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *ExternalIDP) Reduce(event *models.Event) (err error) { func (i *ExternalIDP) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.UserAggregate: case model.UserAggregate:
err = m.processUser(event) err = i.processUser(event)
case iam_es_model.IAMAggregate, org_es_model.OrgAggregate: case iam_es_model.IAMAggregate, org_es_model.OrgAggregate:
err = m.processIdpConfig(event) err = i.processIdpConfig(event)
} }
return err return err
} }
func (m *ExternalIDP) processUser(event *models.Event) (err error) { func (i *ExternalIDP) processUser(event *models.Event) (err error) {
externalIDP := new(usr_view_model.ExternalIDPView) externalIDP := new(usr_view_model.ExternalIDPView)
switch event.Type { switch event.Type {
case model.HumanExternalIDPAdded: case model.HumanExternalIDPAdded:
@ -62,25 +62,25 @@ func (m *ExternalIDP) processUser(event *models.Event) (err error) {
if err != nil { if err != nil {
return err return err
} }
err = m.fillData(externalIDP) err = i.fillData(externalIDP)
case model.HumanExternalIDPRemoved, model.HumanExternalIDPCascadeRemoved: case model.HumanExternalIDPRemoved, model.HumanExternalIDPCascadeRemoved:
err = externalIDP.SetData(event) err = externalIDP.SetData(event)
if err != nil { if err != nil {
return err return err
} }
return m.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event.Sequence) return i.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event.Sequence, event.CreationDate)
case model.UserRemoved: case model.UserRemoved:
return m.view.DeleteExternalIDPsByUserID(event.AggregateID, event.Sequence) return i.view.DeleteExternalIDPsByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedExternalIDPSequence(event.Sequence) return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutExternalIDP(externalIDP, externalIDP.Sequence) return i.view.PutExternalIDP(externalIDP, externalIDP.Sequence, event.CreationDate)
} }
func (m *ExternalIDP) processIdpConfig(event *models.Event) (err error) { func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
switch event.Type { switch event.Type {
case iam_es_model.IDPConfigChanged, org_es_model.IDPConfigChanged: case iam_es_model.IDPConfigChanged, org_es_model.IDPConfigChanged:
configView := new(iam_view_model.IDPConfigView) configView := new(iam_view_model.IDPConfigView)
@ -90,45 +90,49 @@ func (m *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
} else { } else {
configView.AppendEvent(iam_model.IDPProviderTypeOrg, event) configView.AppendEvent(iam_model.IDPProviderTypeOrg, event)
} }
exterinalIDPs, err := m.view.ExternalIDPsByIDPConfigID(configView.IDPConfigID) exterinalIDPs, err := i.view.ExternalIDPsByIDPConfigID(configView.IDPConfigID)
if err != nil { if err != nil {
return err return err
} }
if event.AggregateType == iam_es_model.IAMAggregate { if event.AggregateType == iam_es_model.IAMAggregate {
config, err = m.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID) config, err = i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
} else { } else {
config, err = m.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID) config, err = i.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
} }
if err != nil { if err != nil {
return err return err
} }
for _, provider := range exterinalIDPs { for _, provider := range exterinalIDPs {
m.fillConfigData(provider, config) i.fillConfigData(provider, config)
} }
return m.view.PutExternalIDPs(event.Sequence, exterinalIDPs...) return i.view.PutExternalIDPs(event.Sequence, event.CreationDate, exterinalIDPs...)
default: default:
return m.view.ProcessedExternalIDPSequence(event.Sequence) return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
} }
return nil return nil
} }
func (m *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error { func (i *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error {
config, err := m.orgEvents.GetIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID) config, err := i.orgEvents.GetIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID)
if caos_errs.IsNotFound(err) { if caos_errs.IsNotFound(err) {
config, err = m.iamEvents.GetIDPConfig(context.Background(), m.systemDefaults.IamID, externalIDP.IDPConfigID) config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, externalIDP.IDPConfigID)
} }
if err != nil { if err != nil {
return err return err
} }
m.fillConfigData(externalIDP, config) i.fillConfigData(externalIDP, config)
return nil return nil
} }
func (m *ExternalIDP) fillConfigData(externalIDP *usr_view_model.ExternalIDPView, config *iam_model.IDPConfig) { func (i *ExternalIDP) fillConfigData(externalIDP *usr_view_model.ExternalIDPView, config *iam_model.IDPConfig) {
externalIDP.IDPName = config.Name externalIDP.IDPName = config.Name
} }
func (m *ExternalIDP) OnError(event *models.Event, err error) error { func (i *ExternalIDP) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-4Rsu8", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler") logging.LogWithFields("SPOOL-4Rsu8", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler")
return spooler.HandleError(event, err, m.view.GetLatestExternalIDPFailedEvent, m.view.ProcessedExternalIDPFailedEvent, m.view.ProcessedExternalIDPSequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, i.view.GetLatestExternalIDPFailedEvent, i.view.ProcessedExternalIDPFailedEvent, i.view.ProcessedExternalIDPSequence, i.errorCountUntilSkip)
}
func (i *ExternalIDP) OnSuccess() error {
return spooler.HandleSuccess(i.view.UpdateExternalIDPSpoolerRunTimestamp)
} }

View File

@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view" "github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model" "github.com/caos/zitadel/internal/user/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository" global_view "github.com/caos/zitadel/internal/view/repository"
"time"
) )
const ( const (
@ -32,44 +33,48 @@ func (v *View) SearchExternalIDPs(request *usr_model.ExternalIDPSearchRequest) (
return view.SearchExternalIDPs(v.Db, externalIDPTable, request) return view.SearchExternalIDPs(v.Db, externalIDPTable, request)
} }
func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, sequence uint64) error { func (v *View) PutExternalIDP(externalIDP *model.ExternalIDPView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutExternalIDP(v.Db, externalIDPTable, externalIDP) err := view.PutExternalIDP(v.Db, externalIDPTable, externalIDP)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedExternalIDPSequence(sequence) return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
} }
func (v *View) PutExternalIDPs(sequence uint64, externalIDPs ...*model.ExternalIDPView) error { func (v *View) PutExternalIDPs(sequence uint64, eventTimestamp time.Time, externalIDPs ...*model.ExternalIDPView) error {
err := view.PutExternalIDPs(v.Db, externalIDPTable, externalIDPs...) err := view.PutExternalIDPs(v.Db, externalIDPTable, externalIDPs...)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedExternalIDPSequence(sequence) return v.ProcessedExternalIDPSequence(sequence, eventTimestamp)
} }
func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, eventSequence uint64) error { func (v *View) DeleteExternalIDP(externalUserID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteExternalIDP(v.Db, externalIDPTable, externalUserID, idpConfigID) err := view.DeleteExternalIDP(v.Db, externalIDPTable, externalUserID, idpConfigID)
if err != nil && !errors.IsNotFound(err) { if err != nil && !errors.IsNotFound(err) {
return err return err
} }
return v.ProcessedExternalIDPSequence(eventSequence) return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
} }
func (v *View) DeleteExternalIDPsByUserID(userID string, eventSequence uint64) error { func (v *View) DeleteExternalIDPsByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteExternalIDPsByUserID(v.Db, externalIDPTable, userID) err := view.DeleteExternalIDPsByUserID(v.Db, externalIDPTable, userID)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedExternalIDPSequence(eventSequence) return v.ProcessedExternalIDPSequence(eventSequence, eventTimestamp)
} }
func (v *View) GetLatestExternalIDPSequence() (*global_view.CurrentSequence, error) { func (v *View) GetLatestExternalIDPSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(externalIDPTable) return v.latestSequence(externalIDPTable)
} }
func (v *View) ProcessedExternalIDPSequence(eventSequence uint64) error { func (v *View) ProcessedExternalIDPSequence(eventSequence uint64, eventTimestamp time.Time) error {
return v.saveCurrentSequence(externalIDPTable, eventSequence) return v.saveCurrentSequence(externalIDPTable, eventSequence, eventTimestamp)
}
func (v *View) UpdateExternalIDPSpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(externalIDPTable)
} }
func (v *View) GetLatestExternalIDPFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { func (v *View) GetLatestExternalIDPFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {

View File

@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view" "github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model" "github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository" global_view "github.com/caos/zitadel/internal/view/repository"
"time"
) )
const ( const (
@ -24,44 +25,48 @@ func (v *View) IAMMembersByUserID(userID string) ([]*model.IAMMemberView, error)
return view.IAMMembersByUserID(v.Db, iamMemberTable, userID) return view.IAMMembersByUserID(v.Db, iamMemberTable, userID)
} }
func (v *View) PutIAMMember(org *model.IAMMemberView, sequence uint64) error { func (v *View) PutIAMMember(org *model.IAMMemberView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutIAMMember(v.Db, iamMemberTable, org) err := view.PutIAMMember(v.Db, iamMemberTable, org)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedIAMMemberSequence(sequence) return v.ProcessedIAMMemberSequence(sequence, eventTimestamp)
} }
func (v *View) PutIAMMembers(members []*model.IAMMemberView, sequence uint64) error { func (v *View) PutIAMMembers(members []*model.IAMMemberView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutIAMMembers(v.Db, iamMemberTable, members...) err := view.PutIAMMembers(v.Db, iamMemberTable, members...)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedIAMMemberSequence(sequence) return v.ProcessedIAMMemberSequence(sequence, eventTimestamp)
} }
func (v *View) DeleteIAMMember(iamID, userID string, eventSequence uint64) error { func (v *View) DeleteIAMMember(iamID, userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIAMMember(v.Db, iamMemberTable, iamID, userID) err := view.DeleteIAMMember(v.Db, iamMemberTable, iamID, userID)
if err != nil && !errors.IsNotFound(err) { if err != nil && !errors.IsNotFound(err) {
return err return err
} }
return v.ProcessedIAMMemberSequence(eventSequence) return v.ProcessedIAMMemberSequence(eventSequence, eventTimestamp)
} }
func (v *View) DeleteIAMMembersByUserID(userID string, eventSequence uint64) error { func (v *View) DeleteIAMMembersByUserID(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIAMMembersByUserID(v.Db, iamMemberTable, userID) err := view.DeleteIAMMembersByUserID(v.Db, iamMemberTable, userID)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedIAMMemberSequence(eventSequence) return v.ProcessedIAMMemberSequence(eventSequence, eventTimestamp)
} }
func (v *View) GetLatestIAMMemberSequence() (*global_view.CurrentSequence, error) { func (v *View) GetLatestIAMMemberSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(iamMemberTable) return v.latestSequence(iamMemberTable)
} }
func (v *View) ProcessedIAMMemberSequence(eventSequence uint64) error { func (v *View) ProcessedIAMMemberSequence(eventSequence uint64, eventTimestamp time.Time) error {
return v.saveCurrentSequence(iamMemberTable, eventSequence) return v.saveCurrentSequence(iamMemberTable, eventSequence, eventTimestamp)
}
func (v *View) UpdateIAMMemberSpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(iamMemberTable)
} }
func (v *View) GetLatestIAMMemberFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { func (v *View) GetLatestIAMMemberFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {

View File

@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view" "github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model" "github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository" global_view "github.com/caos/zitadel/internal/view/repository"
"time"
) )
const ( const (
@ -20,28 +21,32 @@ func (v *View) SearchIDPConfigs(request *iam_model.IDPConfigSearchRequest) ([]*m
return view.SearchIDPs(v.Db, idpConfigTable, request) return view.SearchIDPs(v.Db, idpConfigTable, request)
} }
func (v *View) PutIDPConfig(idp *model.IDPConfigView, sequence uint64) error { func (v *View) PutIDPConfig(idp *model.IDPConfigView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutIDP(v.Db, idpConfigTable, idp) err := view.PutIDP(v.Db, idpConfigTable, idp)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedIDPConfigSequence(sequence) return v.ProcessedIDPConfigSequence(sequence, eventTimestamp)
} }
func (v *View) DeleteIDPConfig(idpID string, eventSequence uint64) error { func (v *View) DeleteIDPConfig(idpID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIDP(v.Db, idpConfigTable, idpID) err := view.DeleteIDP(v.Db, idpConfigTable, idpID)
if err != nil && !errors.IsNotFound(err) { if err != nil && !errors.IsNotFound(err) {
return err return err
} }
return v.ProcessedIDPConfigSequence(eventSequence) return v.ProcessedIDPConfigSequence(eventSequence, eventTimestamp)
} }
func (v *View) GetLatestIDPConfigSequence() (*global_view.CurrentSequence, error) { func (v *View) GetLatestIDPConfigSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(idpConfigTable) return v.latestSequence(idpConfigTable)
} }
func (v *View) ProcessedIDPConfigSequence(eventSequence uint64) error { func (v *View) ProcessedIDPConfigSequence(eventSequence uint64, eventTimestamp time.Time) error {
return v.saveCurrentSequence(idpConfigTable, eventSequence) return v.saveCurrentSequence(idpConfigTable, eventSequence, eventTimestamp)
}
func (v *View) UpdateIDPConfigSpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(idpConfigTable)
} }
func (v *View) GetLatestIDPConfigFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { func (v *View) GetLatestIDPConfigFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {

View File

@ -6,6 +6,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view" "github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model" "github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository" global_view "github.com/caos/zitadel/internal/view/repository"
"time"
) )
const ( const (
@ -24,36 +25,40 @@ func (v *View) SearchIDPProviders(request *iam_model.IDPProviderSearchRequest) (
return view.SearchIDPProviders(v.Db, idpProviderTable, request) return view.SearchIDPProviders(v.Db, idpProviderTable, request)
} }
func (v *View) PutIDPProvider(provider *model.IDPProviderView, sequence uint64) error { func (v *View) PutIDPProvider(provider *model.IDPProviderView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutIDPProvider(v.Db, idpProviderTable, provider) err := view.PutIDPProvider(v.Db, idpProviderTable, provider)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedIDPProviderSequence(sequence) return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
} }
func (v *View) PutIDPProviders(sequence uint64, providers ...*model.IDPProviderView) error { func (v *View) PutIDPProviders(sequence uint64, eventTimestamp time.Time, providers ...*model.IDPProviderView) error {
err := view.PutIDPProviders(v.Db, idpProviderTable, providers...) err := view.PutIDPProviders(v.Db, idpProviderTable, providers...)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedIDPProviderSequence(sequence) return v.ProcessedIDPProviderSequence(sequence, eventTimestamp)
} }
func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, eventSequence uint64) error { func (v *View) DeleteIDPProvider(aggregateID, idpConfigID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteIDPProvider(v.Db, idpProviderTable, aggregateID, idpConfigID) err := view.DeleteIDPProvider(v.Db, idpProviderTable, aggregateID, idpConfigID)
if err != nil && !errors.IsNotFound(err) { if err != nil && !errors.IsNotFound(err) {
return err return err
} }
return v.ProcessedIDPProviderSequence(eventSequence) return v.ProcessedIDPProviderSequence(eventSequence, eventTimestamp)
} }
func (v *View) GetLatestIDPProviderSequence() (*global_view.CurrentSequence, error) { func (v *View) GetLatestIDPProviderSequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(idpProviderTable) return v.latestSequence(idpProviderTable)
} }
func (v *View) ProcessedIDPProviderSequence(eventSequence uint64) error { func (v *View) ProcessedIDPProviderSequence(eventSequence uint64, eventTimestamp time.Time) error {
return v.saveCurrentSequence(idpProviderTable, eventSequence) return v.saveCurrentSequence(idpProviderTable, eventSequence, eventTimestamp)
}
func (v *View) UpdateIDPProviderSpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(idpProviderTable)
} }
func (v *View) GetLatestIDPProviderFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { func (v *View) GetLatestIDPProviderFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {

View File

@ -4,6 +4,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view" "github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model" "github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository" global_view "github.com/caos/zitadel/internal/view/repository"
"time"
) )
const ( const (
@ -14,20 +15,24 @@ func (v *View) LabelPolicyByAggregateID(aggregateID string) (*model.LabelPolicyV
return view.GetLabelPolicyByAggregateID(v.Db, labelPolicyTable, aggregateID) return view.GetLabelPolicyByAggregateID(v.Db, labelPolicyTable, aggregateID)
} }
func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, sequence uint64) error { func (v *View) PutLabelPolicy(policy *model.LabelPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutLabelPolicy(v.Db, labelPolicyTable, policy) err := view.PutLabelPolicy(v.Db, labelPolicyTable, policy)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedLabelPolicySequence(sequence) return v.ProcessedLabelPolicySequence(sequence, eventTimestamp)
} }
func (v *View) GetLatestLabelPolicySequence() (*global_view.CurrentSequence, error) { func (v *View) GetLatestLabelPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(labelPolicyTable) return v.latestSequence(labelPolicyTable)
} }
func (v *View) ProcessedLabelPolicySequence(eventSequence uint64) error { func (v *View) ProcessedLabelPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
return v.saveCurrentSequence(labelPolicyTable, eventSequence) return v.saveCurrentSequence(labelPolicyTable, eventSequence, eventTimestamp)
}
func (v *View) UpdateLabelPolicySpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(labelPolicyTable)
} }
func (v *View) GetLatestLabelPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { func (v *View) GetLatestLabelPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {

View File

@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view" "github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model" "github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository" global_view "github.com/caos/zitadel/internal/view/repository"
"time"
) )
const ( const (
@ -15,28 +16,32 @@ func (v *View) LoginPolicyByAggregateID(aggregateID string) (*model.LoginPolicyV
return view.GetLoginPolicyByAggregateID(v.Db, loginPolicyTable, aggregateID) return view.GetLoginPolicyByAggregateID(v.Db, loginPolicyTable, aggregateID)
} }
func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, sequence uint64) error { func (v *View) PutLoginPolicy(policy *model.LoginPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutLoginPolicy(v.Db, loginPolicyTable, policy) err := view.PutLoginPolicy(v.Db, loginPolicyTable, policy)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedLoginPolicySequence(sequence) return v.ProcessedLoginPolicySequence(sequence, eventTimestamp)
} }
func (v *View) DeleteLoginPolicy(aggregateID string, eventSequence uint64) error { func (v *View) DeleteLoginPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteLoginPolicy(v.Db, loginPolicyTable, aggregateID) err := view.DeleteLoginPolicy(v.Db, loginPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) { if err != nil && !errors.IsNotFound(err) {
return err return err
} }
return v.ProcessedLoginPolicySequence(eventSequence) return v.ProcessedLoginPolicySequence(eventSequence, eventTimestamp)
} }
func (v *View) GetLatestLoginPolicySequence() (*global_view.CurrentSequence, error) { func (v *View) GetLatestLoginPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(loginPolicyTable) return v.latestSequence(loginPolicyTable)
} }
func (v *View) ProcessedLoginPolicySequence(eventSequence uint64) error { func (v *View) ProcessedLoginPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
return v.saveCurrentSequence(loginPolicyTable, eventSequence) return v.saveCurrentSequence(loginPolicyTable, eventSequence, eventTimestamp)
}
func (v *View) UpdateLoginPolicySpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(loginPolicyTable)
} }
func (v *View) GetLatestLoginPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { func (v *View) GetLatestLoginPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {

View File

@ -5,6 +5,7 @@ import (
org_view "github.com/caos/zitadel/internal/org/repository/view" org_view "github.com/caos/zitadel/internal/org/repository/view"
"github.com/caos/zitadel/internal/org/repository/view/model" "github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/view/repository" "github.com/caos/zitadel/internal/view/repository"
"time"
) )
const ( const (
@ -19,12 +20,12 @@ func (v *View) SearchOrgs(query *org_model.OrgSearchRequest) ([]*model.OrgView,
return org_view.SearchOrgs(v.Db, orgTable, query) return org_view.SearchOrgs(v.Db, orgTable, query)
} }
func (v *View) PutOrg(org *model.OrgView) error { func (v *View) PutOrg(org *model.OrgView, eventTimestamp time.Time) error {
err := org_view.PutOrg(v.Db, orgTable, org) err := org_view.PutOrg(v.Db, orgTable, org)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedOrgSequence(org.Sequence) return v.ProcessedOrgSequence(org.Sequence, eventTimestamp)
} }
func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*repository.FailedEvent, error) { func (v *View) GetLatestOrgFailedEvent(sequence uint64) (*repository.FailedEvent, error) {
@ -35,10 +36,14 @@ func (v *View) ProcessedOrgFailedEvent(failedEvent *repository.FailedEvent) erro
return v.saveFailedEvent(failedEvent) return v.saveFailedEvent(failedEvent)
} }
func (v *View) UpdateOrgSpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(orgTable)
}
func (v *View) GetLatestOrgSequence() (*repository.CurrentSequence, error) { func (v *View) GetLatestOrgSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(orgTable) return v.latestSequence(orgTable)
} }
func (v *View) ProcessedOrgSequence(eventSequence uint64) error { func (v *View) ProcessedOrgSequence(eventSequence uint64, eventTimestamp time.Time) error {
return v.saveCurrentSequence(orgTable, eventSequence) return v.saveCurrentSequence(orgTable, eventSequence, eventTimestamp)
} }

View File

@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view" "github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model" "github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository" global_view "github.com/caos/zitadel/internal/view/repository"
"time"
) )
const ( const (
@ -15,28 +16,32 @@ func (v *View) OrgIAMPolicyByAggregateID(aggregateID string) (*model.OrgIAMPolic
return view.GetOrgIAMPolicyByAggregateID(v.Db, orgIAMPolicyTable, aggregateID) return view.GetOrgIAMPolicyByAggregateID(v.Db, orgIAMPolicyTable, aggregateID)
} }
func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, sequence uint64) error { func (v *View) PutOrgIAMPolicy(policy *model.OrgIAMPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutOrgIAMPolicy(v.Db, orgIAMPolicyTable, policy) err := view.PutOrgIAMPolicy(v.Db, orgIAMPolicyTable, policy)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedOrgIAMPolicySequence(sequence) return v.ProcessedOrgIAMPolicySequence(sequence, eventTimestamp)
} }
func (v *View) DeleteOrgIAMPolicy(aggregateID string, eventSequence uint64) error { func (v *View) DeleteOrgIAMPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteOrgIAMPolicy(v.Db, orgIAMPolicyTable, aggregateID) err := view.DeleteOrgIAMPolicy(v.Db, orgIAMPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) { if err != nil && !errors.IsNotFound(err) {
return err return err
} }
return v.ProcessedOrgIAMPolicySequence(eventSequence) return v.ProcessedOrgIAMPolicySequence(eventSequence, eventTimestamp)
} }
func (v *View) GetLatestOrgIAMPolicySequence() (*global_view.CurrentSequence, error) { func (v *View) GetLatestOrgIAMPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(orgIAMPolicyTable) return v.latestSequence(orgIAMPolicyTable)
} }
func (v *View) ProcessedOrgIAMPolicySequence(eventSequence uint64) error { func (v *View) ProcessedOrgIAMPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
return v.saveCurrentSequence(orgIAMPolicyTable, eventSequence) return v.saveCurrentSequence(orgIAMPolicyTable, eventSequence, eventTimestamp)
}
func (v *View) UpdateOrgIAMPolicySpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(orgIAMPolicyTable)
} }
func (v *View) GetLatestOrgIAMPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { func (v *View) GetLatestOrgIAMPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {

View File

@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view" "github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model" "github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository" global_view "github.com/caos/zitadel/internal/view/repository"
"time"
) )
const ( const (
@ -15,28 +16,32 @@ func (v *View) PasswordAgePolicyByAggregateID(aggregateID string) (*model.Passwo
return view.GetPasswordAgePolicyByAggregateID(v.Db, passwordAgePolicyTable, aggregateID) return view.GetPasswordAgePolicyByAggregateID(v.Db, passwordAgePolicyTable, aggregateID)
} }
func (v *View) PutPasswordAgePolicy(policy *model.PasswordAgePolicyView, sequence uint64) error { func (v *View) PutPasswordAgePolicy(policy *model.PasswordAgePolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutPasswordAgePolicy(v.Db, passwordAgePolicyTable, policy) err := view.PutPasswordAgePolicy(v.Db, passwordAgePolicyTable, policy)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedPasswordAgePolicySequence(sequence) return v.ProcessedPasswordAgePolicySequence(sequence, eventTimestamp)
} }
func (v *View) DeletePasswordAgePolicy(aggregateID string, eventSequence uint64) error { func (v *View) DeletePasswordAgePolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeletePasswordAgePolicy(v.Db, passwordAgePolicyTable, aggregateID) err := view.DeletePasswordAgePolicy(v.Db, passwordAgePolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) { if err != nil && !errors.IsNotFound(err) {
return err return err
} }
return v.ProcessedPasswordAgePolicySequence(eventSequence) return v.ProcessedPasswordAgePolicySequence(eventSequence, eventTimestamp)
} }
func (v *View) GetLatestPasswordAgePolicySequence() (*global_view.CurrentSequence, error) { func (v *View) GetLatestPasswordAgePolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(passwordAgePolicyTable) return v.latestSequence(passwordAgePolicyTable)
} }
func (v *View) ProcessedPasswordAgePolicySequence(eventSequence uint64) error { func (v *View) ProcessedPasswordAgePolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
return v.saveCurrentSequence(passwordAgePolicyTable, eventSequence) return v.saveCurrentSequence(passwordAgePolicyTable, eventSequence, eventTimestamp)
}
func (v *View) UpdateProcessedPasswordAgePolicySpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(passwordAgePolicyTable)
} }
func (v *View) GetLatestPasswordAgePolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { func (v *View) GetLatestPasswordAgePolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {

View File

@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view" "github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model" "github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository" global_view "github.com/caos/zitadel/internal/view/repository"
"time"
) )
const ( const (
@ -15,28 +16,32 @@ func (v *View) PasswordComplexityPolicyByAggregateID(aggregateID string) (*model
return view.GetPasswordComplexityPolicyByAggregateID(v.Db, passwordComplexityPolicyTable, aggregateID) return view.GetPasswordComplexityPolicyByAggregateID(v.Db, passwordComplexityPolicyTable, aggregateID)
} }
func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, sequence uint64) error { func (v *View) PutPasswordComplexityPolicy(policy *model.PasswordComplexityPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutPasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, policy) err := view.PutPasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, policy)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedPasswordComplexityPolicySequence(sequence) return v.ProcessedPasswordComplexityPolicySequence(sequence, eventTimestamp)
} }
func (v *View) DeletePasswordComplexityPolicy(aggregateID string, eventSequence uint64) error { func (v *View) DeletePasswordComplexityPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeletePasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, aggregateID) err := view.DeletePasswordComplexityPolicy(v.Db, passwordComplexityPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) { if err != nil && !errors.IsNotFound(err) {
return err return err
} }
return v.ProcessedPasswordComplexityPolicySequence(eventSequence) return v.ProcessedPasswordComplexityPolicySequence(eventSequence, eventTimestamp)
} }
func (v *View) GetLatestPasswordComplexityPolicySequence() (*global_view.CurrentSequence, error) { func (v *View) GetLatestPasswordComplexityPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(passwordComplexityPolicyTable) return v.latestSequence(passwordComplexityPolicyTable)
} }
func (v *View) ProcessedPasswordComplexityPolicySequence(eventSequence uint64) error { func (v *View) ProcessedPasswordComplexityPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
return v.saveCurrentSequence(passwordComplexityPolicyTable, eventSequence) return v.saveCurrentSequence(passwordComplexityPolicyTable, eventSequence, eventTimestamp)
}
func (v *View) UpdatePasswordComplexityPolicySpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(passwordComplexityPolicyTable)
} }
func (v *View) GetLatestPasswordComplexityPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { func (v *View) GetLatestPasswordComplexityPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {

View File

@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/iam/repository/view" "github.com/caos/zitadel/internal/iam/repository/view"
"github.com/caos/zitadel/internal/iam/repository/view/model" "github.com/caos/zitadel/internal/iam/repository/view/model"
global_view "github.com/caos/zitadel/internal/view/repository" global_view "github.com/caos/zitadel/internal/view/repository"
"time"
) )
const ( const (
@ -15,28 +16,32 @@ func (v *View) PasswordLockoutPolicyByAggregateID(aggregateID string) (*model.Pa
return view.GetPasswordLockoutPolicyByAggregateID(v.Db, passwordLockoutPolicyTable, aggregateID) return view.GetPasswordLockoutPolicyByAggregateID(v.Db, passwordLockoutPolicyTable, aggregateID)
} }
func (v *View) PutPasswordLockoutPolicy(policy *model.PasswordLockoutPolicyView, sequence uint64) error { func (v *View) PutPasswordLockoutPolicy(policy *model.PasswordLockoutPolicyView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutPasswordLockoutPolicy(v.Db, passwordLockoutPolicyTable, policy) err := view.PutPasswordLockoutPolicy(v.Db, passwordLockoutPolicyTable, policy)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedPasswordLockoutPolicySequence(sequence) return v.ProcessedPasswordLockoutPolicySequence(sequence, eventTimestamp)
} }
func (v *View) DeletePasswordLockoutPolicy(aggregateID string, eventSequence uint64) error { func (v *View) DeletePasswordLockoutPolicy(aggregateID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeletePasswordLockoutPolicy(v.Db, passwordLockoutPolicyTable, aggregateID) err := view.DeletePasswordLockoutPolicy(v.Db, passwordLockoutPolicyTable, aggregateID)
if err != nil && !errors.IsNotFound(err) { if err != nil && !errors.IsNotFound(err) {
return err return err
} }
return v.ProcessedPasswordLockoutPolicySequence(eventSequence) return v.ProcessedPasswordLockoutPolicySequence(eventSequence, eventTimestamp)
} }
func (v *View) GetLatestPasswordLockoutPolicySequence() (*global_view.CurrentSequence, error) { func (v *View) GetLatestPasswordLockoutPolicySequence() (*global_view.CurrentSequence, error) {
return v.latestSequence(passwordLockoutPolicyTable) return v.latestSequence(passwordLockoutPolicyTable)
} }
func (v *View) ProcessedPasswordLockoutPolicySequence(eventSequence uint64) error { func (v *View) ProcessedPasswordLockoutPolicySequence(eventSequence uint64, eventTimestamp time.Time) error {
return v.saveCurrentSequence(passwordLockoutPolicyTable, eventSequence) return v.saveCurrentSequence(passwordLockoutPolicyTable, eventSequence, eventTimestamp)
}
func (v *View) UpdatePasswordLockoutPolicySpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(passwordLockoutPolicyTable)
} }
func (v *View) GetLatestPasswordLockoutPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) { func (v *View) GetLatestPasswordLockoutPolicyFailedEvent(sequence uint64) (*global_view.FailedEvent, error) {

View File

@ -2,14 +2,15 @@ package view
import ( import (
"github.com/caos/zitadel/internal/view/repository" "github.com/caos/zitadel/internal/view/repository"
"time"
) )
const ( const (
sequencesTable = "adminapi.current_sequences" sequencesTable = "adminapi.current_sequences"
) )
func (v *View) saveCurrentSequence(viewName string, sequence uint64) error { func (v *View) saveCurrentSequence(viewName string, sequence uint64, eventTimeStamp time.Time) error {
return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence) return repository.SaveCurrentSequence(v.Db, sequencesTable, viewName, sequence, eventTimeStamp)
} }
func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) { func (v *View) latestSequence(viewName string) (*repository.CurrentSequence, error) {
@ -20,6 +21,24 @@ func (v *View) AllCurrentSequences(db string) ([]*repository.CurrentSequence, er
return repository.AllCurrentSequences(v.Db, db+".current_sequences") return repository.AllCurrentSequences(v.Db, db+".current_sequences")
} }
func (v *View) updateSpoolerRunSequence(viewName string) error {
currentSequence, err := repository.LatestSequence(v.Db, sequencesTable, viewName)
if err != nil {
return err
}
if currentSequence.ViewName == "" {
currentSequence.ViewName = viewName
}
currentSequence.LastSuccessfulSpoolerRun = time.Now()
return repository.UpdateCurrentSequence(v.Db, sequencesTable, currentSequence)
}
func (v *View) GetCurrentSequence(db, viewName string) (*repository.CurrentSequence, error) {
sequenceTable := db + ".current_sequences"
fullView := db + "." + viewName
return repository.LatestSequence(v.Db, sequenceTable, fullView)
}
func (v *View) ClearView(db, viewName string) error { func (v *View) ClearView(db, viewName string) error {
truncateView := db + "." + viewName truncateView := db + "." + viewName
sequenceTable := db + ".current_sequences" sequenceTable := db + ".current_sequences"

View File

@ -5,6 +5,7 @@ import (
"github.com/caos/zitadel/internal/user/repository/view" "github.com/caos/zitadel/internal/user/repository/view"
"github.com/caos/zitadel/internal/user/repository/view/model" "github.com/caos/zitadel/internal/user/repository/view/model"
"github.com/caos/zitadel/internal/view/repository" "github.com/caos/zitadel/internal/view/repository"
"time"
) )
const ( const (
@ -35,43 +36,47 @@ func (v *View) IsUserUnique(userName, email string) (bool, error) {
return view.IsUserUnique(v.Db, userTable, userName, email) return view.IsUserUnique(v.Db, userTable, userName, email)
} }
func (v *View) UserMfas(userID string) ([]*usr_model.MultiFactor, error) { func (v *View) UserMFAs(userID string) ([]*usr_model.MultiFactor, error) {
return view.UserMfas(v.Db, userTable, userID) return view.UserMFAs(v.Db, userTable, userID)
} }
func (v *View) PutUsers(user []*model.UserView, sequence uint64) error { func (v *View) PutUsers(user []*model.UserView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUsers(v.Db, userTable, user...) err := view.PutUsers(v.Db, userTable, user...)
if err != nil { if err != nil {
return err return err
} }
return v.ProcessedUserSequence(sequence) return v.ProcessedUserSequence(sequence, eventTimestamp)
} }
func (v *View) PutUser(user *model.UserView, sequence uint64) error { func (v *View) PutUser(user *model.UserView, sequence uint64, eventTimestamp time.Time) error {
err := view.PutUser(v.Db, userTable, user) err := view.PutUser(v.Db, userTable, user)
if err != nil { if err != nil {
return err return err
} }
if sequence != 0 { if sequence != 0 {
return v.ProcessedUserSequence(sequence) return v.ProcessedUserSequence(sequence, eventTimestamp)
} }
return nil return nil
} }
func (v *View) DeleteUser(userID string, eventSequence uint64) error { func (v *View) DeleteUser(userID string, eventSequence uint64, eventTimestamp time.Time) error {
err := view.DeleteUser(v.Db, userTable, userID) err := view.DeleteUser(v.Db, userTable, userID)
if err != nil { if err != nil {
return nil return nil
} }
return v.ProcessedUserSequence(eventSequence) return v.ProcessedUserSequence(eventSequence, eventTimestamp)
} }
func (v *View) GetLatestUserSequence() (*repository.CurrentSequence, error) { func (v *View) GetLatestUserSequence() (*repository.CurrentSequence, error) {
return v.latestSequence(userTable) return v.latestSequence(userTable)
} }
func (v *View) ProcessedUserSequence(eventSequence uint64) error { func (v *View) ProcessedUserSequence(eventSequence uint64, eventTimestamp time.Time) error {
return v.saveCurrentSequence(userTable, eventSequence) return v.saveCurrentSequence(userTable, eventSequence, eventTimestamp)
}
func (v *View) UpdateUserSpoolerRunTimestamp() error {
return v.updateSpoolerRunSequence(userTable)
} }
func (v *View) GetLatestUserFailedEvent(sequence uint64) (*repository.FailedEvent, error) { func (v *View) GetLatestUserFailedEvent(sequence uint64) (*repository.FailedEvent, error) {

View File

@ -2,6 +2,12 @@ package api
import ( import (
"context" "context"
admin_es "github.com/caos/zitadel/internal/admin/repository/eventsourcing"
auth_es "github.com/caos/zitadel/internal/auth/repository/eventsourcing"
"github.com/caos/zitadel/internal/telemetry/metrics"
"github.com/caos/zitadel/internal/telemetry/metrics/otel"
view_model "github.com/caos/zitadel/internal/view/model"
"go.opentelemetry.io/otel/api/metric"
"net/http" "net/http"
"github.com/caos/logging" "github.com/caos/logging"
@ -16,7 +22,7 @@ import (
"github.com/caos/zitadel/internal/config/systemdefaults" "github.com/caos/zitadel/internal/config/systemdefaults"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model" iam_model "github.com/caos/zitadel/internal/iam/model"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
) )
type Config struct { type Config struct {
@ -30,19 +36,33 @@ type API struct {
verifier *authz.TokenVerifier verifier *authz.TokenVerifier
serverPort string serverPort string
health health health health
auth auth
admin admin
} }
type health interface { type health interface {
Health(ctx context.Context) error Health(ctx context.Context) error
IamByID(ctx context.Context) (*iam_model.IAM, error) IamByID(ctx context.Context) (*iam_model.IAM, error)
VerifierClientID(ctx context.Context, appName string) (string, error) VerifierClientID(ctx context.Context, appName string) (string, error)
} }
func Create(config Config, authZ authz.Config, authZRepo *authz_es.EsRepository, sd systemdefaults.SystemDefaults) *API { type auth interface {
ActiveUserSessionCount() int64
}
type admin interface {
GetViews() ([]*view_model.View, error)
GetSpoolerDiv(database, viewName string) int64
}
func Create(config Config, authZ authz.Config, authZRepo *authz_es.EsRepository, authRepo *auth_es.EsRepository, adminRepo *admin_es.EsRepository, sd systemdefaults.SystemDefaults) *API {
api := &API{ api := &API{
serverPort: config.GRPC.ServerPort, serverPort: config.GRPC.ServerPort,
} }
api.verifier = authz.Start(authZRepo) api.verifier = authz.Start(authZRepo)
api.health = authZRepo api.health = authZRepo
api.auth = authRepo
api.admin = adminRepo
api.grpcServer = server.CreateServer(api.verifier, authZ, sd.DefaultLanguage) api.grpcServer = server.CreateServer(api.verifier, authZ, sd.DefaultLanguage)
api.gatewayHandler = server.CreateGatewayHandler(config.GRPC) api.gatewayHandler = server.CreateGatewayHandler(config.GRPC)
api.RegisterHandler("", api.healthHandler()) api.RegisterHandler("", api.healthHandler())
@ -92,6 +112,7 @@ func (a *API) healthHandler() http.Handler {
handler.HandleFunc("/ready", handleReadiness(checks)) handler.HandleFunc("/ready", handleReadiness(checks))
handler.HandleFunc("/validate", handleValidate(checks)) handler.HandleFunc("/validate", handleValidate(checks))
handler.HandleFunc("/clientID", a.handleClientID) handler.HandleFunc("/clientID", a.handleClientID)
handler.Handle("/metrics", a.handleMetrics())
return handler return handler
} }
@ -132,6 +153,48 @@ func (a *API) handleClientID(w http.ResponseWriter, r *http.Request) {
http_util.MarshalJSON(w, id, nil, http.StatusOK) http_util.MarshalJSON(w, id, nil, http.StatusOK)
} }
func (a *API) handleMetrics() http.Handler {
a.registerActiveSessionCounters()
a.registerSpoolerDivCounters()
return metrics.GetExporter()
}
func (a *API) registerActiveSessionCounters() {
metrics.RegisterValueObserver(
metrics.ActiveSessionCounter,
metrics.ActiveSessionCounterDescription,
func(ctx context.Context, result metric.Int64ObserverResult) {
result.Observe(
a.auth.ActiveUserSessionCount(),
)
},
)
}
func (a *API) registerSpoolerDivCounters() {
views, err := a.admin.GetViews()
if err != nil {
logging.Log("API-3M8sd").WithError(err).Error("could not read views for metrics")
return
}
metrics.RegisterValueObserver(
metrics.SpoolerDivCounter,
metrics.SpoolerDivCounterDescription,
func(ctx context.Context, result metric.Int64ObserverResult) {
for _, view := range views {
labels := map[string]interface{}{
metrics.Database: view.Database,
metrics.ViewName: view.ViewName,
}
result.Observe(
a.admin.GetSpoolerDiv(view.Database, view.ViewName),
otel.MapToKeyValue(labels)...,
)
}
},
)
}
type ValidationFunction func(ctx context.Context) error type ValidationFunction func(ctx context.Context) error
func validate(ctx context.Context, validations []ValidationFunction) []error { func validate(ctx context.Context, validations []ValidationFunction) []error {

View File

@ -7,7 +7,7 @@ import (
"strings" "strings"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
) )
const ( const (

View File

@ -6,7 +6,7 @@ import (
"github.com/caos/zitadel/internal/api/grpc" "github.com/caos/zitadel/internal/api/grpc"
http_util "github.com/caos/zitadel/internal/api/http" http_util "github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
) )
type key int type key int

View File

@ -4,7 +4,7 @@ import (
"context" "context"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
) )
func getUserMethodPermissions(ctx context.Context, t *TokenVerifier, requiredPerm string, authConfig Config) (_ context.Context, _ []string, err error) { func getUserMethodPermissions(ctx context.Context, t *TokenVerifier, requiredPerm string, authConfig Config) (_ context.Context, _ []string, err error) {

View File

@ -6,7 +6,7 @@ import (
"sync" "sync"
caos_errs "github.com/caos/zitadel/internal/errors" caos_errs "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
) )
const ( const (

View File

@ -10,7 +10,7 @@ import (
) )
func (s *Server) GetViews(ctx context.Context, _ *empty.Empty) (_ *admin.Views, err error) { func (s *Server) GetViews(ctx context.Context, _ *empty.Empty) (_ *admin.Views, err error) {
views, err := s.administrator.GetViews(ctx) views, err := s.administrator.GetViews()
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -26,14 +26,17 @@ func failedEventsFromModel(failedEvents []*view_model.FailedEvent) []*admin.Fail
} }
func viewFromModel(view *view_model.View) *admin.View { func viewFromModel(view *view_model.View) *admin.View {
timestamp, err := ptypes.TimestampProto(view.CurrentTimestamp) eventTimestamp, err := ptypes.TimestampProto(view.EventTimestamp)
logging.Log("GRPC-KSo03").OnError(err).Debug("unable to parse timestamp")
lastSpool, err := ptypes.TimestampProto(view.EventTimestamp)
logging.Log("GRPC-KSo03").OnError(err).Debug("unable to parse timestamp") logging.Log("GRPC-KSo03").OnError(err).Debug("unable to parse timestamp")
return &admin.View{ return &admin.View{
Database: view.Database, Database: view.Database,
ViewName: view.ViewName, ViewName: view.ViewName,
ProcessedSequence: view.CurrentSequence, ProcessedSequence: view.CurrentSequence,
ViewTimestamp: timestamp, EventTimestamp: eventTimestamp,
LastSuccessfulSpoolerRun: lastSpool,
} }
} }

View File

@ -13,6 +13,7 @@ func loginPolicyToModel(policy *admin.DefaultLoginPolicyRequest) *iam_model.Logi
AllowExternalIdp: policy.AllowExternalIdp, AllowExternalIdp: policy.AllowExternalIdp,
AllowRegister: policy.AllowRegister, AllowRegister: policy.AllowRegister,
ForceMFA: policy.ForceMfa, ForceMFA: policy.ForceMfa,
PasswordlessType: passwordlessTypeToModel(policy.PasswordlessType),
} }
} }
@ -28,6 +29,7 @@ func loginPolicyFromModel(policy *iam_model.LoginPolicy) *admin.DefaultLoginPoli
AllowExternalIdp: policy.AllowExternalIdp, AllowExternalIdp: policy.AllowExternalIdp,
AllowRegister: policy.AllowRegister, AllowRegister: policy.AllowRegister,
ForceMfa: policy.ForceMFA, ForceMfa: policy.ForceMFA,
PasswordlessType: passwordlessTypeFromModel(policy.PasswordlessType),
CreationDate: creationDate, CreationDate: creationDate,
ChangeDate: changeDate, ChangeDate: changeDate,
} }
@ -45,6 +47,7 @@ func loginPolicyViewFromModel(policy *iam_model.LoginPolicyView) *admin.DefaultL
AllowExternalIdp: policy.AllowExternalIDP, AllowExternalIdp: policy.AllowExternalIDP,
AllowRegister: policy.AllowRegister, AllowRegister: policy.AllowRegister,
ForceMfa: policy.ForceMFA, ForceMfa: policy.ForceMFA,
PasswordlessType: passwordlessTypeFromModel(policy.PasswordlessType),
CreationDate: creationDate, CreationDate: creationDate,
ChangeDate: changeDate, ChangeDate: changeDate,
} }
@ -145,6 +148,24 @@ func secondFactorTypeToModel(mfaType *admin.SecondFactor) iam_model.SecondFactor
} }
} }
func passwordlessTypeFromModel(passwordlessType iam_model.PasswordlessType) admin.PasswordlessType {
switch passwordlessType {
case iam_model.PasswordlessTypeAllowed:
return admin.PasswordlessType_PASSWORDLESSTYPE_ALLOWED
default:
return admin.PasswordlessType_PASSWORDLESSTYPE_NOT_ALLOWED
}
}
func passwordlessTypeToModel(passwordlessType admin.PasswordlessType) iam_model.PasswordlessType {
switch passwordlessType {
case admin.PasswordlessType_PASSWORDLESSTYPE_ALLOWED:
return iam_model.PasswordlessTypeAllowed
default:
return iam_model.PasswordlessTypeNotAllowed
}
}
func multiFactorResultFromModel(result *iam_model.MultiFactorsSearchResponse) *admin.MultiFactorsResult { func multiFactorResultFromModel(result *iam_model.MultiFactorsSearchResponse) *admin.MultiFactorsResult {
converted := make([]admin.MultiFactorType, len(result.Result)) converted := make([]admin.MultiFactorType, len(result.Result))
for i, mfaType := range result.Result { for i, mfaType := range result.Result {

View File

@ -2,7 +2,6 @@ package admin
import ( import (
"context" "context"
"github.com/golang/protobuf/ptypes/empty" "github.com/golang/protobuf/ptypes/empty"
) )

View File

@ -2,7 +2,6 @@ package auth
import ( import (
"context" "context"
"github.com/golang/protobuf/ptypes/empty" "github.com/golang/protobuf/ptypes/empty"
"github.com/caos/zitadel/pkg/grpc/auth" "github.com/caos/zitadel/pkg/grpc/auth"
@ -54,7 +53,7 @@ func (s *Server) GetMyUserAddress(ctx context.Context, _ *empty.Empty) (*auth.Us
} }
func (s *Server) GetMyMfas(ctx context.Context, _ *empty.Empty) (*auth.MultiFactors, error) { func (s *Server) GetMyMfas(ctx context.Context, _ *empty.Empty) (*auth.MultiFactors, error) {
mfas, err := s.repo.MyUserMfas(ctx) mfas, err := s.repo.MyUserMFAs(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -144,7 +143,7 @@ func (s *Server) GetMyPasswordComplexityPolicy(ctx context.Context, _ *empty.Emp
} }
func (s *Server) AddMfaOTP(ctx context.Context, _ *empty.Empty) (_ *auth.MfaOtpResponse, err error) { func (s *Server) AddMfaOTP(ctx context.Context, _ *empty.Empty) (_ *auth.MfaOtpResponse, err error) {
otp, err := s.repo.AddMyMfaOTP(ctx) otp, err := s.repo.AddMyMFAOTP(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -152,12 +151,42 @@ func (s *Server) AddMfaOTP(ctx context.Context, _ *empty.Empty) (_ *auth.MfaOtpR
} }
func (s *Server) VerifyMfaOTP(ctx context.Context, request *auth.VerifyMfaOtp) (*empty.Empty, error) { func (s *Server) VerifyMfaOTP(ctx context.Context, request *auth.VerifyMfaOtp) (*empty.Empty, error) {
err := s.repo.VerifyMyMfaOTPSetup(ctx, request.Code) err := s.repo.VerifyMyMFAOTPSetup(ctx, request.Code)
return &empty.Empty{}, err return &empty.Empty{}, err
} }
func (s *Server) RemoveMfaOTP(ctx context.Context, _ *empty.Empty) (_ *empty.Empty, err error) { func (s *Server) RemoveMfaOTP(ctx context.Context, _ *empty.Empty) (_ *empty.Empty, err error) {
s.repo.RemoveMyMfaOTP(ctx) err = s.repo.RemoveMyMFAOTP(ctx)
return &empty.Empty{}, err
}
func (s *Server) AddMyMfaU2F(ctx context.Context, _ *empty.Empty) (_ *auth.WebAuthNResponse, err error) {
u2f, err := s.repo.AddMyMFAU2F(ctx)
return verifyWebAuthNFromModel(u2f), err
}
func (s *Server) VerifyMyMfaU2F(ctx context.Context, request *auth.VerifyWebAuthN) (*empty.Empty, error) {
err := s.repo.VerifyMyMFAU2FSetup(ctx, request.TokenName, request.PublicKeyCredential)
return &empty.Empty{}, err
}
func (s *Server) RemoveMyMfaU2F(ctx context.Context, id *auth.WebAuthNTokenID) (*empty.Empty, error) {
err := s.repo.RemoveMyMFAU2F(ctx, id.Id)
return &empty.Empty{}, err
}
func (s *Server) AddMyPasswordless(ctx context.Context, _ *empty.Empty) (_ *auth.WebAuthNResponse, err error) {
u2f, err := s.repo.AddMyPasswordless(ctx)
return verifyWebAuthNFromModel(u2f), err
}
func (s *Server) VerifyMyPasswordless(ctx context.Context, request *auth.VerifyWebAuthN) (*empty.Empty, error) {
err := s.repo.VerifyMyPasswordlessSetup(ctx, request.TokenName, request.PublicKeyCredential)
return &empty.Empty{}, err
}
func (s *Server) RemoveMyPasswordless(ctx context.Context, id *auth.WebAuthNTokenID) (*empty.Empty, error) {
err := s.repo.RemoveMyPasswordless(ctx, id.Id)
return &empty.Empty{}, err return &empty.Empty{}, err
} }

View File

@ -12,7 +12,7 @@ import (
"github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model" usr_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/pkg/grpc/auth" "github.com/caos/zitadel/pkg/grpc/auth"
"github.com/caos/zitadel/pkg/grpc/message" "github.com/caos/zitadel/pkg/grpc/message"
@ -358,11 +358,11 @@ func genderToModel(gender auth.Gender) usr_model.Gender {
} }
} }
func mfaStateFromModel(state usr_model.MfaState) auth.MFAState { func mfaStateFromModel(state usr_model.MFAState) auth.MFAState {
switch state { switch state {
case usr_model.MfaStateReady: case usr_model.MFAStateReady:
return auth.MFAState_MFASTATE_READY return auth.MFAState_MFASTATE_READY
case usr_model.MfaStateNotReady: case usr_model.MFAStateNotReady:
return auth.MFAState_MFASTATE_NOT_READY return auth.MFAState_MFASTATE_NOT_READY
default: default:
return auth.MFAState_MFASTATE_UNSPECIFIED return auth.MFAState_MFASTATE_UNSPECIFIED
@ -381,15 +381,16 @@ func mfaFromModel(mfa *usr_model.MultiFactor) *auth.MultiFactor {
return &auth.MultiFactor{ return &auth.MultiFactor{
State: mfaStateFromModel(mfa.State), State: mfaStateFromModel(mfa.State),
Type: mfaTypeFromModel(mfa.Type), Type: mfaTypeFromModel(mfa.Type),
Attribute: mfa.Attribute,
} }
} }
func mfaTypeFromModel(mfatype usr_model.MfaType) auth.MfaType { func mfaTypeFromModel(mfaType usr_model.MFAType) auth.MfaType {
switch mfatype { switch mfaType {
case usr_model.MfaTypeOTP: case usr_model.MFATypeOTP:
return auth.MfaType_MFATYPE_OTP return auth.MfaType_MFATYPE_OTP
case usr_model.MfaTypeSMS: case usr_model.MFATypeU2F:
return auth.MfaType_MFATYPE_SMS return auth.MfaType_MFATYPE_U2F
default: default:
return auth.MfaType_MFATYPE_UNSPECIFIED return auth.MfaType_MFATYPE_UNSPECIFIED
} }
@ -426,3 +427,11 @@ func userChangesToAPI(changes *usr_model.UserChanges) (_ []*auth.Change) {
return result return result
} }
func verifyWebAuthNFromModel(u2f *usr_model.WebAuthNToken) *auth.WebAuthNResponse {
return &auth.WebAuthNResponse{
Id: u2f.WebAuthNTokenID,
PublicKey: u2f.PublicKey,
State: mfaStateFromModel(u2f.State),
}
}

View File

@ -13,6 +13,7 @@ func loginPolicyRequestToModel(policy *management.LoginPolicyRequest) *iam_model
AllowExternalIdp: policy.AllowExternalIdp, AllowExternalIdp: policy.AllowExternalIdp,
AllowRegister: policy.AllowRegister, AllowRegister: policy.AllowRegister,
ForceMFA: policy.ForceMfa, ForceMFA: policy.ForceMfa,
PasswordlessType: passwordlessTypeToModel(policy.PasswordlessType),
} }
} }
@ -30,6 +31,7 @@ func loginPolicyFromModel(policy *iam_model.LoginPolicy) *management.LoginPolicy
CreationDate: creationDate, CreationDate: creationDate,
ChangeDate: changeDate, ChangeDate: changeDate,
ForceMfa: policy.ForceMFA, ForceMfa: policy.ForceMFA,
PasswordlessType: passwordlessTypeFromModel(policy.PasswordlessType),
} }
} }
@ -48,6 +50,7 @@ func loginPolicyViewFromModel(policy *iam_model.LoginPolicyView) *management.Log
CreationDate: creationDate, CreationDate: creationDate,
ChangeDate: changeDate, ChangeDate: changeDate,
ForceMfa: policy.ForceMFA, ForceMfa: policy.ForceMFA,
PasswordlessType: passwordlessTypeFromModel(policy.PasswordlessType),
} }
} }
@ -215,3 +218,21 @@ func multiFactorTypeToModel(mfaType *management.MultiFactor) iam_model.MultiFact
return iam_model.MultiFactorTypeUnspecified return iam_model.MultiFactorTypeUnspecified
} }
} }
func passwordlessTypeFromModel(passwordlessType iam_model.PasswordlessType) management.PasswordlessType {
switch passwordlessType {
case iam_model.PasswordlessTypeAllowed:
return management.PasswordlessType_PASSWORDLESSTYPE_ALLOWED
default:
return management.PasswordlessType_PASSWORDLESSTYPE_NOT_ALLOWED
}
}
func passwordlessTypeToModel(passwordlessType management.PasswordlessType) iam_model.PasswordlessType {
switch passwordlessType {
case management.PasswordlessType_PASSWORDLESSTYPE_ALLOWED:
return iam_model.PasswordlessTypeAllowed
default:
return iam_model.PasswordlessTypeNotAllowed
}
}

View File

@ -214,7 +214,7 @@ func (s *Server) RemoveExternalIDP(ctx context.Context, request *management.Exte
} }
func (s *Server) GetUserMfas(ctx context.Context, userID *management.UserID) (*management.UserMultiFactors, error) { func (s *Server) GetUserMfas(ctx context.Context, userID *management.UserID) (*management.UserMultiFactors, error) {
mfas, err := s.user.UserMfas(ctx, userID.Id) mfas, err := s.user.UserMFAs(ctx, userID.Id)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -572,22 +572,22 @@ func genderToModel(gender management.Gender) usr_model.Gender {
} }
} }
func mfaTypeFromModel(mfatype usr_model.MfaType) management.MfaType { func mfaTypeFromModel(mfatype usr_model.MFAType) management.MfaType {
switch mfatype { switch mfatype {
case usr_model.MfaTypeOTP: case usr_model.MFATypeOTP:
return management.MfaType_MFATYPE_OTP return management.MfaType_MFATYPE_OTP
case usr_model.MfaTypeSMS: case usr_model.MFATypeU2F:
return management.MfaType_MFATYPE_SMS return management.MfaType_MFATYPE_U2F
default: default:
return management.MfaType_MFATYPE_UNSPECIFIED return management.MfaType_MFATYPE_UNSPECIFIED
} }
} }
func mfaStateFromModel(state usr_model.MfaState) management.MFAState { func mfaStateFromModel(state usr_model.MFAState) management.MFAState {
switch state { switch state {
case usr_model.MfaStateReady: case usr_model.MFAStateReady:
return management.MFAState_MFASTATE_READY return management.MFAState_MFASTATE_READY
case usr_model.MfaStateNotReady: case usr_model.MFAStateNotReady:
return management.MFAState_MFASTATE_NOT_READY return management.MFAState_MFASTATE_NOT_READY
default: default:
return management.MFAState_MFASTATE_UNSPECIFIED return management.MFAState_MFASTATE_UNSPECIFIED

View File

@ -14,7 +14,7 @@ import (
client_middleware "github.com/caos/zitadel/internal/api/grpc/client/middleware" client_middleware "github.com/caos/zitadel/internal/api/grpc/client/middleware"
http_util "github.com/caos/zitadel/internal/api/http" http_util "github.com/caos/zitadel/internal/api/http"
http_mw "github.com/caos/zitadel/internal/api/http/middleware" http_mw "github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
) )
const ( const (
@ -129,7 +129,8 @@ func createDialOptions(g Gateway) []grpc.DialOption {
} }
func addInterceptors(handler http.Handler, g Gateway) http.Handler { func addInterceptors(handler http.Handler, g Gateway) http.Handler {
handler = http_mw.DefaultTraceHandler(handler) handler = http_mw.DefaultMetricsHandler(handler)
handler = http_mw.DefaultTelemetryHandler(handler)
handler = http_mw.NoCacheInterceptor(handler) handler = http_mw.NoCacheInterceptor(handler)
if interceptor, ok := g.(grpcGatewayCustomInterceptor); ok { if interceptor, ok := g.(grpcGatewayCustomInterceptor); ok {
handler = interceptor.GatewayHTTPInterceptor(handler) handler = interceptor.GatewayHTTPInterceptor(handler)

View File

@ -10,7 +10,7 @@ import (
"github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/api/authz"
grpc_util "github.com/caos/zitadel/internal/api/grpc" grpc_util "github.com/caos/zitadel/internal/api/grpc"
"github.com/caos/zitadel/internal/api/http" "github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
) )
func AuthorizationInterceptor(verifier *authz.TokenVerifier, authConfig authz.Config) grpc.UnaryServerInterceptor { func AuthorizationInterceptor(verifier *authz.TokenVerifier, authConfig authz.Config) grpc.UnaryServerInterceptor {

View File

@ -0,0 +1,86 @@
package middleware
import (
"context"
"strings"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
"google.golang.org/grpc"
"google.golang.org/grpc/status"
_ "github.com/caos/zitadel/internal/statik"
"github.com/caos/zitadel/internal/telemetry/metrics"
)
const (
GrpcMethod = "grpc_method"
ReturnCode = "return_code"
GrpcRequestCounter = "grpc.server.request_counter"
GrpcRequestCounterDescription = "Grpc request counter"
TotalGrpcRequestCounter = "grpc.server.total_request_counter"
TotalGrpcRequestCounterDescription = "Total grpc request counter"
GrpcStatusCodeCounter = "grpc.server.grpc_status_code"
GrpcStatusCodeCounterDescription = "Grpc status code counter"
)
func MetricsHandler(metricTypes []metrics.MetricType, ignoredMethodSuffixes ...string) grpc.UnaryServerInterceptor {
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
return RegisterMetrics(ctx, req, info, handler, metricTypes, ignoredMethodSuffixes...)
}
}
func RegisterMetrics(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler, metricTypes []metrics.MetricType, ignoredMethodSuffixes ...string) (_ interface{}, err error) {
if len(metricTypes) == 0 {
return handler(ctx, req)
}
for _, ignore := range ignoredMethodSuffixes {
if strings.HasSuffix(info.FullMethod, ignore) {
return handler(ctx, req)
}
}
resp, err := handler(ctx, req)
if containsMetricsMethod(metrics.MetricTypeRequestCount, metricTypes) {
RegisterGrpcRequestCounter(ctx, info)
}
if containsMetricsMethod(metrics.MetricTypeTotalCount, metricTypes) {
RegisterGrpcTotalRequestCounter(ctx)
}
if containsMetricsMethod(metrics.MetricTypeStatusCode, metricTypes) {
RegisterGrpcRequestCodeCounter(ctx, info, err)
}
return resp, err
}
func RegisterGrpcRequestCounter(ctx context.Context, info *grpc.UnaryServerInfo) {
var labels = map[string]interface{}{
GrpcMethod: info.FullMethod,
}
metrics.RegisterCounter(GrpcRequestCounter, GrpcRequestCounterDescription)
metrics.AddCount(ctx, GrpcRequestCounter, 1, labels)
}
func RegisterGrpcTotalRequestCounter(ctx context.Context) {
metrics.RegisterCounter(TotalGrpcRequestCounter, TotalGrpcRequestCounterDescription)
metrics.AddCount(ctx, TotalGrpcRequestCounter, 1, nil)
}
func RegisterGrpcRequestCodeCounter(ctx context.Context, info *grpc.UnaryServerInfo, err error) {
statusCode := status.Code(err)
var labels = map[string]interface{}{
GrpcMethod: info.FullMethod,
ReturnCode: runtime.HTTPStatusFromCode(statusCode),
}
metrics.RegisterCounter(GrpcStatusCodeCounter, GrpcStatusCodeCounterDescription)
metrics.AddCount(ctx, GrpcStatusCodeCounter, 1, labels)
}
func containsMetricsMethod(metricType metrics.MetricType, metricTypes []metrics.MetricType) bool {
for _, m := range metricTypes {
if m == metricType {
return true
}
}
return false
}

View File

@ -9,7 +9,7 @@ import (
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/proto" "github.com/caos/zitadel/internal/proto"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
) )
type ValidationFunction func(ctx context.Context) error type ValidationFunction func(ctx context.Context) error

View File

@ -2,6 +2,8 @@ package server
import ( import (
"context" "context"
grpc_api "github.com/caos/zitadel/internal/api/grpc"
"github.com/caos/zitadel/internal/telemetry/metrics"
"github.com/caos/logging" "github.com/caos/logging"
grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware" grpc_middleware "github.com/grpc-ecosystem/go-grpc-middleware"
@ -11,7 +13,7 @@ import (
"github.com/caos/zitadel/internal/api/authz" "github.com/caos/zitadel/internal/api/authz"
"github.com/caos/zitadel/internal/api/grpc/server/middleware" "github.com/caos/zitadel/internal/api/grpc/server/middleware"
"github.com/caos/zitadel/internal/api/http" "github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
) )
const ( const (
@ -27,10 +29,12 @@ type Server interface {
} }
func CreateServer(verifier *authz.TokenVerifier, authConfig authz.Config, lang language.Tag) *grpc.Server { func CreateServer(verifier *authz.TokenVerifier, authConfig authz.Config, lang language.Tag) *grpc.Server {
metricTypes := []metrics.MetricType{metrics.MetricTypeTotalCount, metrics.MetricTypeRequestCount, metrics.MetricTypeStatusCode}
return grpc.NewServer( return grpc.NewServer(
grpc.UnaryInterceptor( grpc.UnaryInterceptor(
grpc_middleware.ChainUnaryServer( grpc_middleware.ChainUnaryServer(
middleware.DefaultTracingServer(), middleware.DefaultTracingServer(),
middleware.MetricsHandler(metricTypes, grpc_api.Probes...),
middleware.ErrorHandler(), middleware.ErrorHandler(),
middleware.AuthorizationInterceptor(verifier, authConfig), middleware.AuthorizationInterceptor(verifier, authConfig),
middleware.TranslationHandler(lang), middleware.TranslationHandler(lang),

View File

@ -0,0 +1,19 @@
package middleware
import (
"github.com/caos/zitadel/internal/telemetry/metrics"
"net/http"
http_utils "github.com/caos/zitadel/internal/api/http"
)
func DefaultMetricsHandler(handler http.Handler) http.Handler {
metricTypes := []metrics.MetricType{metrics.MetricTypeTotalCount}
return MetricsHandler(metricTypes, http_utils.Probes...)(handler)
}
func MetricsHandler(metricTypes []metrics.MetricType, ignoredMethods ...string) func(http.Handler) http.Handler {
return func(handler http.Handler) http.Handler {
return metrics.NewMetricsHandler(handler, metricTypes, ignoredMethods...)
}
}

View File

@ -0,0 +1,18 @@
package middleware
import (
"github.com/caos/zitadel/internal/telemetry"
"net/http"
http_utils "github.com/caos/zitadel/internal/api/http"
)
func DefaultTelemetryHandler(handler http.Handler) http.Handler {
return TelemetryHandler(http_utils.Probes...)(handler)
}
func TelemetryHandler(ignoredMethods ...string) func(http.Handler) http.Handler {
return func(handler http.Handler) http.Handler {
return telemetry.TelemetryHandler(handler, ignoredMethods...)
}
}

View File

@ -1,18 +0,0 @@
package middleware
import (
"net/http"
http_utils "github.com/caos/zitadel/internal/api/http"
"github.com/caos/zitadel/internal/tracing"
)
func DefaultTraceHandler(handler http.Handler) http.Handler {
return TraceHandler(http_utils.Probes...)(handler)
}
func TraceHandler(ignoredMethods ...string) func(http.Handler) http.Handler {
return func(handler http.Handler) http.Handler {
return tracing.TraceHandler(handler, ignoredMethods...)
}
}

View File

@ -5,7 +5,7 @@ import (
"net/http" "net/http"
"github.com/caos/logging" "github.com/caos/logging"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
) )
func Serve(ctx context.Context, handler http.Handler, port, servername string) { func Serve(ctx context.Context, handler http.Handler, port, servername string) {

View File

@ -13,7 +13,7 @@ import (
"github.com/caos/zitadel/internal/api/http/middleware" "github.com/caos/zitadel/internal/api/http/middleware"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
proj_model "github.com/caos/zitadel/internal/project/model" proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
grant_model "github.com/caos/zitadel/internal/usergrant/model" grant_model "github.com/caos/zitadel/internal/usergrant/model"
) )

View File

@ -18,6 +18,7 @@ const (
amrPassword = "password" amrPassword = "password"
amrMFA = "mfa" amrMFA = "mfa"
amrOTP = "otp" amrOTP = "otp"
amrUserPresence = "user"
) )
type AuthRequest struct { type AuthRequest struct {
@ -38,11 +39,11 @@ func (a *AuthRequest) GetAMR() []string {
if a.PasswordVerified { if a.PasswordVerified {
amr = append(amr, amrPassword) amr = append(amr, amrPassword)
} }
if len(a.MfasVerified) > 0 { if len(a.MFAsVerified) > 0 {
amr = append(amr, amrMFA)
for _, mfa := range a.MFAsVerified {
if amrMFA := AMRFromMFAType(mfa); amrMFA != "" {
amr = append(amr, amrMFA) amr = append(amr, amrMFA)
for _, mfa := range a.MfasVerified {
if amrMfa := AMRFromMFAType(mfa); amrMfa != "" {
amr = append(amr, amrMfa)
} }
} }
} }
@ -247,6 +248,9 @@ func AMRFromMFAType(mfaType model.MFAType) string {
switch mfaType { switch mfaType {
case model.MFATypeOTP: case model.MFATypeOTP:
return amrOTP return amrOTP
case model.MFATypeU2F,
model.MFATypeU2FUserVerification:
return amrUserPresence
default: default:
return "" return ""
} }

View File

@ -16,7 +16,7 @@ import (
"github.com/caos/zitadel/internal/crypto" "github.com/caos/zitadel/internal/crypto"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
proj_model "github.com/caos/zitadel/internal/project/model" proj_model "github.com/caos/zitadel/internal/project/model"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
user_model "github.com/caos/zitadel/internal/user/model" user_model "github.com/caos/zitadel/internal/user/model"
grant_model "github.com/caos/zitadel/internal/usergrant/model" grant_model "github.com/caos/zitadel/internal/usergrant/model"
) )

View File

@ -2,6 +2,7 @@ package oidc
import ( import (
"context" "context"
"github.com/caos/zitadel/internal/telemetry/metrics"
"time" "time"
"github.com/caos/logging" "github.com/caos/logging"
@ -12,7 +13,7 @@ import (
"github.com/caos/zitadel/internal/auth/repository" "github.com/caos/zitadel/internal/auth/repository"
"github.com/caos/zitadel/internal/config/types" "github.com/caos/zitadel/internal/config/types"
"github.com/caos/zitadel/internal/id" "github.com/caos/zitadel/internal/id"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
) )
type OPHandlerConfig struct { type OPHandlerConfig struct {
@ -55,12 +56,14 @@ func NewProvider(ctx context.Context, config OPHandlerConfig, repo repository.Re
cookieHandler, err := middleware.NewUserAgentHandler(config.UserAgentCookieConfig, id.SonyFlakeGenerator, localDevMode) cookieHandler, err := middleware.NewUserAgentHandler(config.UserAgentCookieConfig, id.SonyFlakeGenerator, localDevMode)
logging.Log("OIDC-sd4fd").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Panic("cannot user agent handler") logging.Log("OIDC-sd4fd").OnError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Panic("cannot user agent handler")
config.OPConfig.CodeMethodS256 = true config.OPConfig.CodeMethodS256 = true
metricTypes := []metrics.MetricType{metrics.MetricTypeRequestCount, metrics.MetricTypeStatusCode, metrics.MetricTypeTotalCount}
provider, err := op.NewOpenIDProvider( provider, err := op.NewOpenIDProvider(
ctx, ctx,
config.OPConfig, config.OPConfig,
newStorage(config.StorageConfig, repo), newStorage(config.StorageConfig, repo),
op.WithHttpInterceptors( op.WithHttpInterceptors(
middleware.TraceHandler(), middleware.MetricsHandler(metricTypes),
middleware.TelemetryHandler(),
middleware.NoCacheInterceptor, middleware.NoCacheInterceptor,
cookieHandler, cookieHandler,
http_utils.CopyHeadersToContext, http_utils.CopyHeadersToContext,

View File

@ -2,10 +2,9 @@ package repository
import ( import (
"context" "context"
"github.com/caos/zitadel/internal/auth_request/model"
org_model "github.com/caos/zitadel/internal/org/model" org_model "github.com/caos/zitadel/internal/org/model"
user_model "github.com/caos/zitadel/internal/user/model" user_model "github.com/caos/zitadel/internal/user/model"
"github.com/caos/zitadel/internal/auth_request/model"
) )
type AuthRequestRepository interface { type AuthRequestRepository interface {
@ -15,14 +14,22 @@ type AuthRequestRepository interface {
AuthRequestByCode(ctx context.Context, code string) (*model.AuthRequest, error) AuthRequestByCode(ctx context.Context, code string) (*model.AuthRequest, error)
SaveAuthCode(ctx context.Context, id, code, userAgentID string) error SaveAuthCode(ctx context.Context, id, code, userAgentID string) error
DeleteAuthRequest(ctx context.Context, id string) error DeleteAuthRequest(ctx context.Context, id string) error
CheckLoginName(ctx context.Context, id, loginName, userAgentID string) error CheckLoginName(ctx context.Context, id, loginName, userAgentID string) error
CheckExternalUserLogin(ctx context.Context, authReqID, userAgentID string, user *model.ExternalUser, info *model.BrowserInfo) error CheckExternalUserLogin(ctx context.Context, authReqID, userAgentID string, user *model.ExternalUser, info *model.BrowserInfo) error
SelectUser(ctx context.Context, id, userID, userAgentID string) error SelectUser(ctx context.Context, id, userID, userAgentID string) error
SelectExternalIDP(ctx context.Context, authReqID, idpConfigID, userAgentID string) error SelectExternalIDP(ctx context.Context, authReqID, idpConfigID, userAgentID string) error
VerifyPassword(ctx context.Context, id, userID, password, userAgentID string, info *model.BrowserInfo) error VerifyPassword(ctx context.Context, id, userID, password, userAgentID string, info *model.BrowserInfo) error
VerifyMfaOTP(ctx context.Context, agentID, authRequestID, code, userAgentID string, info *model.BrowserInfo) error
VerifyMFAOTP(ctx context.Context, agentID, authRequestID, code, userAgentID string, info *model.BrowserInfo) error
BeginMFAU2FLogin(ctx context.Context, userID, authRequestID, userAgentID string) (*user_model.WebAuthNLogin, error)
VerifyMFAU2F(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) error
BeginPasswordlessLogin(ctx context.Context, userID, authRequestID, userAgentID string) (*user_model.WebAuthNLogin, error)
VerifyPasswordless(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) error
LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) error LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) error
AutoRegisterExternalUser(ctx context.Context, user *user_model.User, externalIDP *user_model.ExternalIDP, member *org_model.OrgMember, authReqID, userAgentID, resourceOwner string, info *model.BrowserInfo) error AutoRegisterExternalUser(ctx context.Context, user *user_model.User, externalIDP *user_model.ExternalIDP, member *org_model.OrgMember, authReqID, userAgentID, resourceOwner string, info *model.BrowserInfo) error
ResetLinkingUsers(ctx context.Context, authReqID, userAgentID string) error ResetLinkingUsers(ctx context.Context, authReqID, userAgentID string) error
GetOrgByPrimaryDomain(primaryDomain string) (*org_model.OrgView, error) GetOrgByPrimaryDomain(primaryDomain string) (*org_model.OrgView, error)
} }

View File

@ -7,6 +7,7 @@ import (
"github.com/caos/zitadel/internal/project/model" "github.com/caos/zitadel/internal/project/model"
proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing" proj_event "github.com/caos/zitadel/internal/project/repository/eventsourcing"
proj_view_model "github.com/caos/zitadel/internal/project/repository/view/model" proj_view_model "github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/telemetry/tracing"
) )
type ApplicationRepo struct { type ApplicationRepo struct {
@ -22,7 +23,10 @@ func (a *ApplicationRepo) ApplicationByClientID(ctx context.Context, clientID st
return proj_view_model.ApplicationViewToModel(app), nil return proj_view_model.ApplicationViewToModel(app), nil
} }
func (a *ApplicationRepo) AuthorizeOIDCApplication(ctx context.Context, clientID, secret string) error { func (a *ApplicationRepo) AuthorizeOIDCApplication(ctx context.Context, clientID, secret string) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
app, err := a.View.ApplicationByClientID(ctx, clientID) app, err := a.View.ApplicationByClientID(ctx, clientID)
if err != nil { if err != nil {
return err return err

View File

@ -21,7 +21,7 @@ import (
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model" org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
project_view_model "github.com/caos/zitadel/internal/project/repository/view/model" project_view_model "github.com/caos/zitadel/internal/project/repository/view/model"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
user_model "github.com/caos/zitadel/internal/user/model" user_model "github.com/caos/zitadel/internal/user/model"
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" es_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
@ -47,7 +47,7 @@ type AuthRequestRepo struct {
PasswordCheckLifeTime time.Duration PasswordCheckLifeTime time.Duration
ExternalLoginCheckLifeTime time.Duration ExternalLoginCheckLifeTime time.Duration
MfaInitSkippedLifeTime time.Duration MFAInitSkippedLifeTime time.Duration
SecondFactorCheckLifeTime time.Duration SecondFactorCheckLifeTime time.Duration
MultiFactorCheckLifeTime time.Duration MultiFactorCheckLifeTime time.Duration
@ -245,27 +245,62 @@ func (repo *AuthRequestRepo) SelectUser(ctx context.Context, id, userID, userAge
func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, id, userID, password, userAgentID string, info *model.BrowserInfo) (err error) { func (repo *AuthRequestRepo) VerifyPassword(ctx context.Context, id, userID, password, userAgentID string, info *model.BrowserInfo) (err error) {
ctx, span := tracing.NewSpan(ctx) ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }() defer func() { span.EndWithError(err) }()
request, err := repo.getAuthRequest(ctx, id, userAgentID) request, err := repo.getAuthRequestEnsureUser(ctx, id, userAgentID, userID)
if err != nil { if err != nil {
return err return err
} }
if request.UserID != userID {
return errors.ThrowPreconditionFailed(nil, "EVENT-ds35D", "Errors.User.NotMatchingUserID")
}
return repo.UserEvents.CheckPassword(ctx, userID, password, request.WithCurrentInfo(info)) return repo.UserEvents.CheckPassword(ctx, userID, password, request.WithCurrentInfo(info))
} }
func (repo *AuthRequestRepo) VerifyMfaOTP(ctx context.Context, authRequestID, userID, code, userAgentID string, info *model.BrowserInfo) (err error) { func (repo *AuthRequestRepo) VerifyMFAOTP(ctx context.Context, authRequestID, userID, code, userAgentID string, info *model.BrowserInfo) (err error) {
ctx, span := tracing.NewSpan(ctx) ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }() defer func() { span.EndWithError(err) }()
request, err := repo.getAuthRequest(ctx, authRequestID, userAgentID) request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID)
if err != nil { if err != nil {
return err return err
} }
if request.UserID != userID { return repo.UserEvents.CheckMFAOTP(ctx, userID, code, request.WithCurrentInfo(info))
return errors.ThrowPreconditionFailed(nil, "EVENT-ADJ26", "Errors.User.NotMatchingUserID")
} }
return repo.UserEvents.CheckMfaOTP(ctx, userID, code, request.WithCurrentInfo(info))
func (repo *AuthRequestRepo) BeginMFAU2FLogin(ctx context.Context, userID, authRequestID, userAgentID string) (login *user_model.WebAuthNLogin, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID)
if err != nil {
return nil, err
}
return repo.UserEvents.BeginU2FLogin(ctx, userID, request)
}
func (repo *AuthRequestRepo) VerifyMFAU2F(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID)
if err != nil {
return err
}
return repo.UserEvents.VerifyMFAU2F(ctx, userID, credentialData, request)
}
func (repo *AuthRequestRepo) BeginPasswordlessLogin(ctx context.Context, userID, authRequestID, userAgentID string) (login *user_model.WebAuthNLogin, err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID)
if err != nil {
return nil, err
}
return repo.UserEvents.BeginPasswordlessLogin(ctx, userID, request)
}
func (repo *AuthRequestRepo) VerifyPasswordless(ctx context.Context, userID, authRequestID, userAgentID string, credentialData []byte, info *model.BrowserInfo) (err error) {
ctx, span := tracing.NewSpan(ctx)
defer func() { span.EndWithError(err) }()
request, err := repo.getAuthRequestEnsureUser(ctx, authRequestID, userAgentID, userID)
if err != nil {
return err
}
return repo.UserEvents.VerifyPasswordless(ctx, userID, credentialData, request)
} }
func (repo *AuthRequestRepo) LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) (err error) { func (repo *AuthRequestRepo) LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *model.BrowserInfo) (err error) {
@ -365,6 +400,17 @@ func (repo *AuthRequestRepo) getAuthRequestNextSteps(ctx context.Context, id, us
return request, nil return request, nil
} }
func (repo *AuthRequestRepo) getAuthRequestEnsureUser(ctx context.Context, authRequestID, userAgentID, userID string) (*model.AuthRequest, error) {
request, err := repo.getAuthRequest(ctx, authRequestID, userAgentID)
if err != nil {
return nil, err
}
if request.UserID != userID {
return nil, errors.ThrowPreconditionFailed(nil, "EVENT-GBH32", "Errors.User.NotMatchingUserID")
}
return request, nil
}
func (repo *AuthRequestRepo) getAuthRequest(ctx context.Context, id, userAgentID string) (*model.AuthRequest, error) { func (repo *AuthRequestRepo) getAuthRequest(ctx context.Context, id, userAgentID string) (*model.AuthRequest, error) {
request, err := repo.AuthRequests.GetAuthRequestByID(ctx, id) request, err := repo.AuthRequests.GetAuthRequestByID(ctx, id)
if err != nil { if err != nil {
@ -545,27 +591,19 @@ func (repo *AuthRequestRepo) nextSteps(ctx context.Context, request *model.AuthR
return nil, err return nil, err
} }
if (request.SelectedIDPConfigID != "" || userSession.SelectedIDPConfigID != "") && (request.LinkingUsers == nil || len(request.LinkingUsers) == 0) { isInternalLogin := request.SelectedIDPConfigID == "" && userSession.SelectedIDPConfigID == ""
if !checkVerificationTime(userSession.ExternalLoginVerification, repo.ExternalLoginCheckLifeTime) { if !isInternalLogin && len(request.LinkingUsers) == 0 && !checkVerificationTime(userSession.ExternalLoginVerification, repo.ExternalLoginCheckLifeTime) {
selectedIDPConfigID := request.SelectedIDPConfigID selectedIDPConfigID := request.SelectedIDPConfigID
if selectedIDPConfigID == "" { if selectedIDPConfigID == "" {
selectedIDPConfigID = userSession.SelectedIDPConfigID selectedIDPConfigID = userSession.SelectedIDPConfigID
} }
return append(steps, &model.ExternalLoginStep{SelectedIDPConfigID: selectedIDPConfigID}), nil return append(steps, &model.ExternalLoginStep{SelectedIDPConfigID: selectedIDPConfigID}), nil
} }
} else if (request.SelectedIDPConfigID == "" && userSession.SelectedIDPConfigID == "") || (request.SelectedIDPConfigID != "" && request.LinkingUsers != nil && len(request.LinkingUsers) > 0) { if isInternalLogin || (!isInternalLogin && len(request.LinkingUsers) > 0) {
if user.InitRequired { step := repo.firstFactorChecked(request, user, userSession)
return append(steps, &model.InitUserStep{PasswordSet: user.PasswordSet}), nil if step != nil {
return append(steps, step), nil
} }
if !user.PasswordSet {
return append(steps, &model.InitPasswordStep{}), nil
}
if !checkVerificationTime(userSession.PasswordVerification, repo.PasswordCheckLifeTime) {
return append(steps, &model.PasswordStep{}), nil
}
request.PasswordVerified = true
request.AuthTime = userSession.PasswordVerification
} }
step, ok, err := repo.mfaChecked(userSession, request, user) step, ok, err := repo.mfaChecked(userSession, request, user)
@ -624,21 +662,46 @@ func (repo *AuthRequestRepo) usersForUserSelection(request *model.AuthRequest) (
return users, nil return users, nil
} }
func (repo *AuthRequestRepo) firstFactorChecked(request *model.AuthRequest, user *user_model.UserView, userSession *user_model.UserSessionView) model.NextStep {
if user.InitRequired {
return &model.InitUserStep{PasswordSet: user.PasswordSet}
}
if user.IsPasswordlessReady() {
if !checkVerificationTime(userSession.PasswordlessVerification, repo.MultiFactorCheckLifeTime) {
return &model.PasswordlessStep{}
}
request.AuthTime = userSession.PasswordlessVerification
return nil
}
if !user.PasswordSet {
return &model.InitPasswordStep{}
}
if !checkVerificationTime(userSession.PasswordVerification, repo.PasswordCheckLifeTime) {
return &model.PasswordStep{}
}
request.PasswordVerified = true
request.AuthTime = userSession.PasswordVerification
return nil
}
func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *model.AuthRequest, user *user_model.UserView) (model.NextStep, bool, error) { func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView, request *model.AuthRequest, user *user_model.UserView) (model.NextStep, bool, error) {
mfaLevel := request.MfaLevel() mfaLevel := request.MFALevel()
allowedProviders, required := user.MfaTypesAllowed(mfaLevel, request.LoginPolicy) allowedProviders, required := user.MFATypesAllowed(mfaLevel, request.LoginPolicy)
promptRequired := (user.MfaMaxSetUp < mfaLevel) || (len(allowedProviders) == 0 && required) promptRequired := (user.MFAMaxSetUp < mfaLevel) || (len(allowedProviders) == 0 && required)
if promptRequired || !repo.mfaSkippedOrSetUp(user) { if promptRequired || !repo.mfaSkippedOrSetUp(user) {
types := user.MfaTypesSetupPossible(mfaLevel, request.LoginPolicy) types := user.MFATypesSetupPossible(mfaLevel, request.LoginPolicy)
if promptRequired && len(types) == 0 { if promptRequired && len(types) == 0 {
return nil, false, errors.ThrowPreconditionFailed(nil, "LOGIN-5Hm8s", "Errors.Login.LoginPolicy.MFA.ForceAndNotConfigured") return nil, false, errors.ThrowPreconditionFailed(nil, "LOGIN-5Hm8s", "Errors.Login.LoginPolicy.MFA.ForceAndNotConfigured")
} }
if len(types) == 0 { if len(types) == 0 {
return nil, true, nil return nil, true, nil
} }
return &model.MfaPromptStep{ return &model.MFAPromptStep{
Required: promptRequired, Required: promptRequired,
MfaProviders: types, MFAProviders: types,
}, false, nil }, false, nil
} }
switch mfaLevel { switch mfaLevel {
@ -651,28 +714,28 @@ func (repo *AuthRequestRepo) mfaChecked(userSession *user_model.UserSessionView,
fallthrough fallthrough
case model.MFALevelSecondFactor: case model.MFALevelSecondFactor:
if checkVerificationTime(userSession.SecondFactorVerification, repo.SecondFactorCheckLifeTime) { if checkVerificationTime(userSession.SecondFactorVerification, repo.SecondFactorCheckLifeTime) {
request.MfasVerified = append(request.MfasVerified, userSession.SecondFactorVerificationType) request.MFAsVerified = append(request.MFAsVerified, userSession.SecondFactorVerificationType)
request.AuthTime = userSession.SecondFactorVerification request.AuthTime = userSession.SecondFactorVerification
return nil, true, nil return nil, true, nil
} }
fallthrough fallthrough
case model.MFALevelMultiFactor: case model.MFALevelMultiFactor:
if checkVerificationTime(userSession.MultiFactorVerification, repo.MultiFactorCheckLifeTime) { if checkVerificationTime(userSession.MultiFactorVerification, repo.MultiFactorCheckLifeTime) {
request.MfasVerified = append(request.MfasVerified, userSession.MultiFactorVerificationType) request.MFAsVerified = append(request.MFAsVerified, userSession.MultiFactorVerificationType)
request.AuthTime = userSession.MultiFactorVerification request.AuthTime = userSession.MultiFactorVerification
return nil, true, nil return nil, true, nil
} }
} }
return &model.MfaVerificationStep{ return &model.MFAVerificationStep{
MfaProviders: allowedProviders, MFAProviders: allowedProviders,
}, false, nil }, false, nil
} }
func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView) bool { func (repo *AuthRequestRepo) mfaSkippedOrSetUp(user *user_model.UserView) bool {
if user.MfaMaxSetUp > model.MFALevelNotSetUp { if user.MFAMaxSetUp > model.MFALevelNotSetUp {
return true return true
} }
return checkVerificationTime(user.MfaInitSkipped, repo.MfaInitSkippedLifeTime) return checkVerificationTime(user.MFAInitSkipped, repo.MFAInitSkippedLifeTime)
} }
func (repo *AuthRequestRepo) getLoginPolicy(ctx context.Context, orgID string) (*iam_model.LoginPolicyView, error) { func (repo *AuthRequestRepo) getLoginPolicy(ctx context.Context, orgID string) (*iam_model.LoginPolicyView, error) {
@ -745,7 +808,11 @@ func userSessionByIDs(ctx context.Context, provider userSessionViewProvider, eve
es_model.HumanExternalLoginCheckSucceeded, es_model.HumanExternalLoginCheckSucceeded,
es_model.HumanMFAOTPCheckSucceeded, es_model.HumanMFAOTPCheckSucceeded,
es_model.HumanMFAOTPCheckFailed, es_model.HumanMFAOTPCheckFailed,
es_model.HumanSignedOut: es_model.HumanSignedOut,
es_model.HumanPasswordlessTokenCheckSucceeded,
es_model.HumanPasswordlessTokenCheckFailed,
es_model.HumanMFAU2FTokenCheckSucceeded,
es_model.HumanMFAU2FTokenCheckFailed:
eventData, err := user_view_model.UserSessionFromEvent(event) eventData, err := user_view_model.UserSessionFromEvent(event)
if err != nil { if err != nil {
logging.Log("EVENT-sdgT3").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("error getting event data") logging.Log("EVENT-sdgT3").WithError(err).WithField("traceID", tracing.TraceIDFromCtx(ctx)).Debug("error getting event data")

View File

@ -48,8 +48,10 @@ func (m *mockViewErrUserSession) UserSessionsByAgentID(string) ([]*user_view_mod
type mockViewUserSession struct { type mockViewUserSession struct {
ExternalLoginVerification time.Time ExternalLoginVerification time.Time
PasswordlessVerification time.Time
PasswordVerification time.Time PasswordVerification time.Time
SecondFactorVerification time.Time SecondFactorVerification time.Time
MultiFactorVerification time.Time
Users []mockUser Users []mockUser
} }
@ -61,8 +63,10 @@ type mockUser struct {
func (m *mockViewUserSession) UserSessionByIDs(string, string) (*user_view_model.UserSessionView, error) { func (m *mockViewUserSession) UserSessionByIDs(string, string) (*user_view_model.UserSessionView, error) {
return &user_view_model.UserSessionView{ return &user_view_model.UserSessionView{
ExternalLoginVerification: m.ExternalLoginVerification, ExternalLoginVerification: m.ExternalLoginVerification,
PasswordlessVerification: m.PasswordlessVerification,
PasswordVerification: m.PasswordVerification, PasswordVerification: m.PasswordVerification,
SecondFactorVerification: m.SecondFactorVerification, SecondFactorVerification: m.SecondFactorVerification,
MultiFactorVerification: m.MultiFactorVerification,
}, nil }, nil
} }
@ -115,8 +119,9 @@ type mockViewUser struct {
PasswordChangeRequired bool PasswordChangeRequired bool
IsEmailVerified bool IsEmailVerified bool
OTPState int32 OTPState int32
MfaMaxSetUp int32 MFAMaxSetUp int32
MfaInitSkipped time.Time MFAInitSkipped time.Time
PasswordlessTokens user_view_model.WebAuthNTokens
} }
type mockLoginPolicy struct { type mockLoginPolicy struct {
@ -138,8 +143,9 @@ func (m *mockViewUser) UserByID(string) (*user_view_model.UserView, error) {
PasswordChangeRequired: m.PasswordChangeRequired, PasswordChangeRequired: m.PasswordChangeRequired,
IsEmailVerified: m.IsEmailVerified, IsEmailVerified: m.IsEmailVerified,
OTPState: m.OTPState, OTPState: m.OTPState,
MfaMaxSetUp: m.MfaMaxSetUp, MFAMaxSetUp: m.MFAMaxSetUp,
MfaInitSkipped: m.MfaInitSkipped, MFAInitSkipped: m.MFAInitSkipped,
PasswordlessTokens: m.PasswordlessTokens,
}, },
}, nil }, nil
} }
@ -200,7 +206,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
loginPolicyProvider loginPolicyViewProvider loginPolicyProvider loginPolicyViewProvider
PasswordCheckLifeTime time.Duration PasswordCheckLifeTime time.Duration
ExternalLoginCheckLifeTime time.Duration ExternalLoginCheckLifeTime time.Duration
MfaInitSkippedLifeTime time.Duration MFAInitSkippedLifeTime time.Duration
SecondFactorCheckLifeTime time.Duration SecondFactorCheckLifeTime time.Duration
MultiFactorCheckLifeTime time.Duration MultiFactorCheckLifeTime time.Duration
} }
@ -413,6 +419,49 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
}}, }},
nil, nil,
}, },
{
"passwordless not verified, passwordless check step",
fields{
userSessionViewProvider: &mockViewUserSession{},
userViewProvider: &mockViewUser{
PasswordSet: true,
PasswordlessTokens: user_view_model.WebAuthNTokens{&user_view_model.WebAuthNView{ID: "id", State: int32(user_model.MFAStateReady)}},
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
MultiFactorCheckLifeTime: 10 * time.Hour,
},
args{&model.AuthRequest{UserID: "UserID"}, false},
[]model.NextStep{&model.PasswordlessStep{}},
nil,
},
{
"passwordless verified, email not verified, email verification step",
fields{
userSessionViewProvider: &mockViewUserSession{
PasswordlessVerification: time.Now().Add(-5 * time.Minute),
MultiFactorVerification: time.Now().Add(-5 * time.Minute),
},
userViewProvider: &mockViewUser{
PasswordSet: true,
PasswordlessTokens: user_view_model.WebAuthNTokens{&user_view_model.WebAuthNView{ID: "id", State: int32(user_model.MFAStateReady)}},
PasswordChangeRequired: false,
IsEmailVerified: false,
MFAMaxSetUp: int32(model.MFALevelMultiFactor),
},
userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
MultiFactorCheckLifeTime: 10 * time.Hour,
},
args{&model.AuthRequest{
UserID: "UserID",
LoginPolicy: &iam_model.LoginPolicyView{
MultiFactors: []iam_model.MultiFactorType{iam_model.MultiFactorTypeU2FWithPIN},
},
}, false},
[]model.NextStep{&model.VerifyEMailStep{}},
nil,
},
{ {
"password not set, init password step", "password not set, init password step",
fields{ fields{
@ -433,7 +482,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
}, },
userViewProvider: &mockViewUser{ userViewProvider: &mockViewUser{
IsEmailVerified: true, IsEmailVerified: true,
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -452,7 +501,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
}, },
userViewProvider: &mockViewUser{ userViewProvider: &mockViewUser{
IsEmailVerified: true, IsEmailVerified: true,
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -499,7 +548,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{ userViewProvider: &mockViewUser{
PasswordSet: true, PasswordSet: true,
IsEmailVerified: true, IsEmailVerified: true,
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -525,8 +574,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
}, },
userViewProvider: &mockViewUser{ userViewProvider: &mockViewUser{
PasswordSet: true, PasswordSet: true,
OTPState: int32(user_model.MfaStateReady), OTPState: int32(user_model.MFAStateReady),
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -540,8 +589,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP}, SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
}, },
}, false}, }, false},
[]model.NextStep{&model.MfaVerificationStep{ []model.NextStep{&model.MFAVerificationStep{
MfaProviders: []model.MFAType{model.MFATypeOTP}, MFAProviders: []model.MFAType{model.MFATypeOTP},
}}, }},
nil, nil,
}, },
@ -554,8 +603,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
}, },
userViewProvider: &mockViewUser{ userViewProvider: &mockViewUser{
PasswordSet: true, PasswordSet: true,
OTPState: int32(user_model.MfaStateReady), OTPState: int32(user_model.MFAStateReady),
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -571,8 +620,8 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP}, SecondFactors: []iam_model.SecondFactorType{iam_model.SecondFactorTypeOTP},
}, },
}, false}, }, false},
[]model.NextStep{&model.MfaVerificationStep{ []model.NextStep{&model.MFAVerificationStep{
MfaProviders: []model.MFAType{model.MFATypeOTP}, MFAProviders: []model.MFAType{model.MFATypeOTP},
}}, }},
nil, nil,
}, },
@ -587,7 +636,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
PasswordSet: true, PasswordSet: true,
PasswordChangeRequired: true, PasswordChangeRequired: true,
IsEmailVerified: true, IsEmailVerified: true,
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -613,7 +662,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
}, },
userViewProvider: &mockViewUser{ userViewProvider: &mockViewUser{
PasswordSet: true, PasswordSet: true,
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -639,7 +688,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{ userViewProvider: &mockViewUser{
PasswordSet: true, PasswordSet: true,
PasswordChangeRequired: true, PasswordChangeRequired: true,
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -665,7 +714,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{ userViewProvider: &mockViewUser{
PasswordSet: true, PasswordSet: true,
IsEmailVerified: true, IsEmailVerified: true,
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -693,7 +742,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{ userViewProvider: &mockViewUser{
PasswordSet: true, PasswordSet: true,
IsEmailVerified: true, IsEmailVerified: true,
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -722,7 +771,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{ userViewProvider: &mockViewUser{
PasswordSet: true, PasswordSet: true,
IsEmailVerified: true, IsEmailVerified: true,
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -754,7 +803,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{ userViewProvider: &mockViewUser{
PasswordSet: true, PasswordSet: true,
IsEmailVerified: true, IsEmailVerified: true,
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -785,7 +834,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{ userViewProvider: &mockViewUser{
PasswordSet: true, PasswordSet: true,
IsEmailVerified: true, IsEmailVerified: true,
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -810,7 +859,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
userViewProvider: &mockViewUser{ userViewProvider: &mockViewUser{
PasswordSet: true, PasswordSet: true,
IsEmailVerified: true, IsEmailVerified: true,
MfaMaxSetUp: int32(model.MFALevelSecondFactor), MFAMaxSetUp: int32(model.MFALevelSecondFactor),
}, },
userEventProvider: &mockEventUser{}, userEventProvider: &mockEventUser{},
orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive}, orgViewProvider: &mockViewOrg{State: org_model.OrgStateActive},
@ -844,7 +893,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
LoginPolicyViewProvider: tt.fields.loginPolicyProvider, LoginPolicyViewProvider: tt.fields.loginPolicyProvider,
PasswordCheckLifeTime: tt.fields.PasswordCheckLifeTime, PasswordCheckLifeTime: tt.fields.PasswordCheckLifeTime,
ExternalLoginCheckLifeTime: tt.fields.ExternalLoginCheckLifeTime, ExternalLoginCheckLifeTime: tt.fields.ExternalLoginCheckLifeTime,
MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime, MFAInitSkippedLifeTime: tt.fields.MFAInitSkippedLifeTime,
SecondFactorCheckLifeTime: tt.fields.SecondFactorCheckLifeTime, SecondFactorCheckLifeTime: tt.fields.SecondFactorCheckLifeTime,
MultiFactorCheckLifeTime: tt.fields.MultiFactorCheckLifeTime, MultiFactorCheckLifeTime: tt.fields.MultiFactorCheckLifeTime,
} }
@ -860,7 +909,7 @@ func TestAuthRequestRepo_nextSteps(t *testing.T) {
func TestAuthRequestRepo_mfaChecked(t *testing.T) { func TestAuthRequestRepo_mfaChecked(t *testing.T) {
type fields struct { type fields struct {
MfaInitSkippedLifeTime time.Duration MFAInitSkippedLifeTime time.Duration
SecondFactorCheckLifeTime time.Duration SecondFactorCheckLifeTime time.Duration
MultiFactorCheckLifeTime time.Duration MultiFactorCheckLifeTime time.Duration
} }
@ -884,7 +933,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
// args{ // args{
// request: &model.AuthRequest{PossibleLOAs: []model.LevelOfAssurance{}}, // request: &model.AuthRequest{PossibleLOAs: []model.LevelOfAssurance{}},
// user: &user_model.UserView{ // user: &user_model.UserView{
// OTPState: user_model.MfaStateReady, // OTPState: user_model.MFAStateReady,
// }, // },
// }, // },
// false, // false,
@ -892,7 +941,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
{ {
"not set up, forced by policy, no mfas configured, error", "not set up, forced by policy, no mfas configured, error",
fields{ fields{
MfaInitSkippedLifeTime: 30 * 24 * time.Hour, MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
}, },
args{ args{
request: &model.AuthRequest{ request: &model.AuthRequest{
@ -902,7 +951,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
}, },
user: &user_model.UserView{ user: &user_model.UserView{
HumanView: &user_model.HumanView{ HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MFALevelNotSetUp, MFAMaxSetUp: model.MFALevelNotSetUp,
}, },
}, },
}, },
@ -913,7 +962,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
{ {
"not set up, no mfas configured, no prompt and true", "not set up, no mfas configured, no prompt and true",
fields{ fields{
MfaInitSkippedLifeTime: 30 * 24 * time.Hour, MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
}, },
args{ args{
request: &model.AuthRequest{ request: &model.AuthRequest{
@ -921,7 +970,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
}, },
user: &user_model.UserView{ user: &user_model.UserView{
HumanView: &user_model.HumanView{ HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MFALevelNotSetUp, MFAMaxSetUp: model.MFALevelNotSetUp,
}, },
}, },
}, },
@ -932,7 +981,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
{ {
"not set up, prompt and false", "not set up, prompt and false",
fields{ fields{
MfaInitSkippedLifeTime: 30 * 24 * time.Hour, MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
}, },
args{ args{
request: &model.AuthRequest{ request: &model.AuthRequest{
@ -942,12 +991,12 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
}, },
user: &user_model.UserView{ user: &user_model.UserView{
HumanView: &user_model.HumanView{ HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MFALevelNotSetUp, MFAMaxSetUp: model.MFALevelNotSetUp,
}, },
}, },
}, },
&model.MfaPromptStep{ &model.MFAPromptStep{
MfaProviders: []model.MFAType{ MFAProviders: []model.MFAType{
model.MFATypeOTP, model.MFATypeOTP,
}, },
}, },
@ -957,7 +1006,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
{ {
"not set up, forced by org, true", "not set up, forced by org, true",
fields{ fields{
MfaInitSkippedLifeTime: 30 * 24 * time.Hour, MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
}, },
args{ args{
request: &model.AuthRequest{ request: &model.AuthRequest{
@ -968,13 +1017,13 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
}, },
user: &user_model.UserView{ user: &user_model.UserView{
HumanView: &user_model.HumanView{ HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MFALevelNotSetUp, MFAMaxSetUp: model.MFALevelNotSetUp,
}, },
}, },
}, },
&model.MfaPromptStep{ &model.MFAPromptStep{
Required: true, Required: true,
MfaProviders: []model.MFAType{ MFAProviders: []model.MFAType{
model.MFATypeOTP, model.MFATypeOTP,
}, },
}, },
@ -984,7 +1033,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
{ {
"not set up and skipped, true", "not set up and skipped, true",
fields{ fields{
MfaInitSkippedLifeTime: 30 * 24 * time.Hour, MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
}, },
args{ args{
request: &model.AuthRequest{ request: &model.AuthRequest{
@ -992,8 +1041,8 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
}, },
user: &user_model.UserView{ user: &user_model.UserView{
HumanView: &user_model.HumanView{ HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MFALevelNotSetUp, MFAMaxSetUp: model.MFALevelNotSetUp,
MfaInitSkipped: time.Now().UTC(), MFAInitSkipped: time.Now().UTC(),
}, },
}, },
}, },
@ -1014,8 +1063,8 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
}, },
user: &user_model.UserView{ user: &user_model.UserView{
HumanView: &user_model.HumanView{ HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MFALevelSecondFactor, MFAMaxSetUp: model.MFALevelSecondFactor,
OTPState: user_model.MfaStateReady, OTPState: user_model.MFAStateReady,
}, },
}, },
userSession: &user_model.UserSessionView{SecondFactorVerification: time.Now().UTC().Add(-5 * time.Hour)}, userSession: &user_model.UserSessionView{SecondFactorVerification: time.Now().UTC().Add(-5 * time.Hour)},
@ -1037,15 +1086,15 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
}, },
user: &user_model.UserView{ user: &user_model.UserView{
HumanView: &user_model.HumanView{ HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MFALevelSecondFactor, MFAMaxSetUp: model.MFALevelSecondFactor,
OTPState: user_model.MfaStateReady, OTPState: user_model.MFAStateReady,
}, },
}, },
userSession: &user_model.UserSessionView{}, userSession: &user_model.UserSessionView{},
}, },
&model.MfaVerificationStep{ &model.MFAVerificationStep{
MfaProviders: []model.MFAType{model.MFATypeOTP}, MFAProviders: []model.MFAType{model.MFATypeOTP},
}, },
false, false,
nil, nil,
@ -1054,7 +1103,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
repo := &AuthRequestRepo{ repo := &AuthRequestRepo{
MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime, MFAInitSkippedLifeTime: tt.fields.MFAInitSkippedLifeTime,
SecondFactorCheckLifeTime: tt.fields.SecondFactorCheckLifeTime, SecondFactorCheckLifeTime: tt.fields.SecondFactorCheckLifeTime,
MultiFactorCheckLifeTime: tt.fields.MultiFactorCheckLifeTime, MultiFactorCheckLifeTime: tt.fields.MultiFactorCheckLifeTime,
} }
@ -1073,7 +1122,7 @@ func TestAuthRequestRepo_mfaChecked(t *testing.T) {
func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) { func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
type fields struct { type fields struct {
MfaInitSkippedLifeTime time.Duration MFAInitSkippedLifeTime time.Duration
} }
type args struct { type args struct {
user *user_model.UserView user *user_model.UserView
@ -1090,7 +1139,7 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
args{ args{
&user_model.UserView{ &user_model.UserView{
HumanView: &user_model.HumanView{ HumanView: &user_model.HumanView{
MfaMaxSetUp: model.MFALevelSecondFactor, MFAMaxSetUp: model.MFALevelSecondFactor,
}, },
}, },
}, },
@ -1099,13 +1148,13 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
{ {
"mfa skipped active, true", "mfa skipped active, true",
fields{ fields{
MfaInitSkippedLifeTime: 30 * 24 * time.Hour, MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
}, },
args{ args{
&user_model.UserView{ &user_model.UserView{
HumanView: &user_model.HumanView{ HumanView: &user_model.HumanView{
MfaMaxSetUp: -1, MFAMaxSetUp: -1,
MfaInitSkipped: time.Now().UTC().Add(-10 * time.Hour), MFAInitSkipped: time.Now().UTC().Add(-10 * time.Hour),
}, },
}, },
}, },
@ -1114,13 +1163,13 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
{ {
"mfa skipped inactive, false", "mfa skipped inactive, false",
fields{ fields{
MfaInitSkippedLifeTime: 30 * 24 * time.Hour, MFAInitSkippedLifeTime: 30 * 24 * time.Hour,
}, },
args{ args{
&user_model.UserView{ &user_model.UserView{
HumanView: &user_model.HumanView{ HumanView: &user_model.HumanView{
MfaMaxSetUp: -1, MFAMaxSetUp: -1,
MfaInitSkipped: time.Now().UTC().Add(-40 * 24 * time.Hour), MFAInitSkipped: time.Now().UTC().Add(-40 * 24 * time.Hour),
}, },
}, },
}, },
@ -1130,7 +1179,7 @@ func TestAuthRequestRepo_mfaSkippedOrSetUp(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
repo := &AuthRequestRepo{ repo := &AuthRequestRepo{
MfaInitSkippedLifeTime: tt.fields.MfaInitSkippedLifeTime, MFAInitSkippedLifeTime: tt.fields.MFAInitSkippedLifeTime,
} }
if got := repo.mfaSkippedOrSetUp(tt.args.user); got != tt.want { if got := repo.mfaSkippedOrSetUp(tt.args.user); got != tt.want {
t.Errorf("mfaSkippedOrSetUp() = %v, want %v", got, tt.want) t.Errorf("mfaSkippedOrSetUp() = %v, want %v", got, tt.want)

View File

@ -9,7 +9,7 @@ import (
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
iam_model "github.com/caos/zitadel/internal/iam/model" iam_model "github.com/caos/zitadel/internal/iam/model"
iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model" iam_view_model "github.com/caos/zitadel/internal/iam/repository/view/model"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
auth_model "github.com/caos/zitadel/internal/auth/model" auth_model "github.com/caos/zitadel/internal/auth/model"
auth_view "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view" auth_view "github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
@ -50,7 +50,7 @@ func (repo *OrgRepository) SearchOrgs(ctx context.Context, request *org_model.Or
} }
if err == nil { if err == nil {
result.Sequence = sequence.CurrentSequence result.Sequence = sequence.CurrentSequence
result.Timestamp = sequence.CurrentTimestamp result.Timestamp = sequence.LastSuccessfulSpoolerRun
} }
return result, nil return result, nil
} }

View File

@ -3,17 +3,18 @@ package eventstore
import ( import (
"context" "context"
"strings" "strings"
"time"
"github.com/caos/logging" "github.com/caos/logging"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
auth_req_model "github.com/caos/zitadel/internal/auth_request/model" auth_req_model "github.com/caos/zitadel/internal/auth_request/model"
"github.com/caos/zitadel/internal/errors" "github.com/caos/zitadel/internal/errors"
"github.com/caos/zitadel/internal/eventstore/models" "github.com/caos/zitadel/internal/eventstore/models"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
usr_model "github.com/caos/zitadel/internal/user/model" usr_model "github.com/caos/zitadel/internal/user/model"
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
"github.com/caos/zitadel/internal/user/repository/view/model" "github.com/caos/zitadel/internal/user/repository/view/model"
"time"
"github.com/caos/zitadel/internal/auth/repository/eventsourcing/view"
) )
type TokenRepo struct { type TokenRepo struct {

View File

@ -16,7 +16,7 @@ import (
"github.com/caos/zitadel/internal/eventstore/sdk" "github.com/caos/zitadel/internal/eventstore/sdk"
org_model "github.com/caos/zitadel/internal/org/model" org_model "github.com/caos/zitadel/internal/org/model"
org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing" org_event "github.com/caos/zitadel/internal/org/repository/eventsourcing"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
"github.com/caos/zitadel/internal/user/model" "github.com/caos/zitadel/internal/user/model"
user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing" user_event "github.com/caos/zitadel/internal/user/repository/eventsourcing"
usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model" usr_model "github.com/caos/zitadel/internal/user/repository/eventsourcing/model"
@ -124,7 +124,7 @@ func (repo *UserRepo) SearchMyExternalIDPs(ctx context.Context, request *model.E
} }
if seqErr == nil { if seqErr == nil {
result.Sequence = sequence.CurrentSequence result.Sequence = sequence.CurrentSequence
result.Timestamp = sequence.CurrentTimestamp result.Timestamp = sequence.LastSuccessfulSpoolerRun
} }
return result, nil return result, nil
} }
@ -253,18 +253,22 @@ func (repo *UserRepo) ChangePassword(ctx context.Context, userID, old, new strin
return err return err
} }
func (repo *UserRepo) MyUserMfas(ctx context.Context) ([]*model.MultiFactor, error) { func (repo *UserRepo) MyUserMFAs(ctx context.Context) ([]*model.MultiFactor, error) {
user, err := repo.UserByID(ctx, authz.GetCtxData(ctx).UserID) user, err := repo.UserByID(ctx, authz.GetCtxData(ctx).UserID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
if user.OTPState == model.MfaStateUnspecified { mfas := make([]*model.MultiFactor, 0)
return []*model.MultiFactor{}, nil if user.OTPState != model.MFAStateUnspecified {
mfas = append(mfas, &model.MultiFactor{Type: model.MFATypeOTP, State: user.OTPState})
} }
return []*model.MultiFactor{{Type: model.MfaTypeOTP, State: user.OTPState}}, nil for _, u2f := range user.U2FTokens {
mfas = append(mfas, &model.MultiFactor{Type: model.MFATypeU2F, State: u2f.State, Attribute: u2f.Name})
}
return mfas, nil
} }
func (repo *UserRepo) AddMfaOTP(ctx context.Context, userID string) (*model.OTP, error) { func (repo *UserRepo) AddMFAOTP(ctx context.Context, userID string) (*model.OTP, error) {
accountName := "" accountName := ""
user, err := repo.UserByID(ctx, userID) user, err := repo.UserByID(ctx, userID)
if err != nil { if err != nil {
@ -275,7 +279,7 @@ func (repo *UserRepo) AddMfaOTP(ctx context.Context, userID string) (*model.OTP,
return repo.UserEvents.AddOTP(ctx, userID, accountName) return repo.UserEvents.AddOTP(ctx, userID, accountName)
} }
func (repo *UserRepo) AddMyMfaOTP(ctx context.Context) (*model.OTP, error) { func (repo *UserRepo) AddMyMFAOTP(ctx context.Context) (*model.OTP, error) {
accountName := "" accountName := ""
user, err := repo.UserByID(ctx, authz.GetCtxData(ctx).UserID) user, err := repo.UserByID(ctx, authz.GetCtxData(ctx).UserID)
if err != nil { if err != nil {
@ -286,18 +290,66 @@ func (repo *UserRepo) AddMyMfaOTP(ctx context.Context) (*model.OTP, error) {
return repo.UserEvents.AddOTP(ctx, authz.GetCtxData(ctx).UserID, accountName) return repo.UserEvents.AddOTP(ctx, authz.GetCtxData(ctx).UserID, accountName)
} }
func (repo *UserRepo) VerifyMfaOTPSetup(ctx context.Context, userID, code string) error { func (repo *UserRepo) VerifyMFAOTPSetup(ctx context.Context, userID, code string) error {
return repo.UserEvents.CheckMfaOTPSetup(ctx, userID, code) return repo.UserEvents.CheckMFAOTPSetup(ctx, userID, code)
} }
func (repo *UserRepo) VerifyMyMfaOTPSetup(ctx context.Context, code string) error { func (repo *UserRepo) VerifyMyMFAOTPSetup(ctx context.Context, code string) error {
return repo.UserEvents.CheckMfaOTPSetup(ctx, authz.GetCtxData(ctx).UserID, code) return repo.UserEvents.CheckMFAOTPSetup(ctx, authz.GetCtxData(ctx).UserID, code)
} }
func (repo *UserRepo) RemoveMyMfaOTP(ctx context.Context) error { func (repo *UserRepo) RemoveMyMFAOTP(ctx context.Context) error {
return repo.UserEvents.RemoveOTP(ctx, authz.GetCtxData(ctx).UserID) return repo.UserEvents.RemoveOTP(ctx, authz.GetCtxData(ctx).UserID)
} }
func (repo *UserRepo) AddMFAU2F(ctx context.Context, userID string) (*model.WebAuthNToken, error) {
return repo.UserEvents.AddU2F(ctx, userID)
}
func (repo *UserRepo) AddMyMFAU2F(ctx context.Context) (*model.WebAuthNToken, error) {
return repo.UserEvents.AddU2F(ctx, authz.GetCtxData(ctx).UserID)
}
func (repo *UserRepo) VerifyMFAU2FSetup(ctx context.Context, userID, tokenName string, credentialData []byte) error {
return repo.UserEvents.VerifyU2FSetup(ctx, userID, tokenName, credentialData)
}
func (repo *UserRepo) VerifyMyMFAU2FSetup(ctx context.Context, tokenName string, credentialData []byte) error {
return repo.UserEvents.VerifyU2FSetup(ctx, authz.GetCtxData(ctx).UserID, tokenName, credentialData)
}
func (repo *UserRepo) RemoveMFAU2F(ctx context.Context, userID, webAuthNTokenID string) error {
return repo.UserEvents.RemoveU2FToken(ctx, userID, webAuthNTokenID)
}
func (repo *UserRepo) RemoveMyMFAU2F(ctx context.Context, webAuthNTokenID string) error {
return repo.UserEvents.RemoveU2FToken(ctx, authz.GetCtxData(ctx).UserID, webAuthNTokenID)
}
func (repo *UserRepo) AddPasswordless(ctx context.Context, userID string) (*model.WebAuthNToken, error) {
return repo.UserEvents.AddPasswordless(ctx, userID)
}
func (repo *UserRepo) AddMyPasswordless(ctx context.Context) (*model.WebAuthNToken, error) {
return repo.UserEvents.AddPasswordless(ctx, authz.GetCtxData(ctx).UserID)
}
func (repo *UserRepo) VerifyPasswordlessSetup(ctx context.Context, userID, tokenName string, credentialData []byte) error {
return repo.UserEvents.VerifyPasswordlessSetup(ctx, userID, tokenName, credentialData)
}
func (repo *UserRepo) VerifyMyPasswordlessSetup(ctx context.Context, tokenName string, credentialData []byte) error {
return repo.UserEvents.VerifyPasswordlessSetup(ctx, authz.GetCtxData(ctx).UserID, tokenName, credentialData)
}
func (repo *UserRepo) RemovePasswordless(ctx context.Context, userID, webAuthNTokenID string) error {
return repo.UserEvents.RemovePasswordlessToken(ctx, userID, webAuthNTokenID)
}
func (repo *UserRepo) RemoveMyPasswordless(ctx context.Context, webAuthNTokenID string) error {
return repo.UserEvents.RemovePasswordlessToken(ctx, authz.GetCtxData(ctx).UserID, webAuthNTokenID)
}
func (repo *UserRepo) ChangeMyUsername(ctx context.Context, username string) error { func (repo *UserRepo) ChangeMyUsername(ctx context.Context, username string) error {
ctxData := authz.GetCtxData(ctx) ctxData := authz.GetCtxData(ctx)
orgPolicy, err := repo.View.OrgIAMPolicyByAggregateID(ctxData.OrgID) orgPolicy, err := repo.View.OrgIAMPolicyByAggregateID(ctxData.OrgID)
@ -327,8 +379,8 @@ func (repo *UserRepo) VerifyInitCode(ctx context.Context, userID, code, password
return repo.UserEvents.VerifyInitCode(ctx, pwPolicyView, userID, code, password) return repo.UserEvents.VerifyInitCode(ctx, pwPolicyView, userID, code, password)
} }
func (repo *UserRepo) SkipMfaInit(ctx context.Context, userID string) error { func (repo *UserRepo) SkipMFAInit(ctx context.Context, userID string) error {
return repo.UserEvents.SkipMfaInit(ctx, userID) return repo.UserEvents.SkipMFAInit(ctx, userID)
} }
func (repo *UserRepo) RequestPasswordReset(ctx context.Context, loginname string) error { func (repo *UserRepo) RequestPasswordReset(ctx context.Context, loginname string) error {

View File

@ -12,7 +12,7 @@ import (
global_model "github.com/caos/zitadel/internal/model" global_model "github.com/caos/zitadel/internal/model"
org_model "github.com/caos/zitadel/internal/org/model" org_model "github.com/caos/zitadel/internal/org/model"
org_view_model "github.com/caos/zitadel/internal/org/repository/view/model" org_view_model "github.com/caos/zitadel/internal/org/repository/view/model"
"github.com/caos/zitadel/internal/tracing" "github.com/caos/zitadel/internal/telemetry/tracing"
user_model "github.com/caos/zitadel/internal/user/model" user_model "github.com/caos/zitadel/internal/user/model"
user_view_model "github.com/caos/zitadel/internal/user/repository/view/model" user_view_model "github.com/caos/zitadel/internal/user/repository/view/model"
grant_model "github.com/caos/zitadel/internal/usergrant/model" grant_model "github.com/caos/zitadel/internal/usergrant/model"
@ -44,7 +44,7 @@ func (repo *UserGrantRepo) SearchMyUserGrants(ctx context.Context, request *gran
} }
if err == nil { if err == nil {
result.Sequence = sequence.CurrentSequence result.Sequence = sequence.CurrentSequence
result.Timestamp = sequence.CurrentTimestamp result.Timestamp = sequence.LastSuccessfulSpoolerRun
} }
return result, nil return result, nil
} }

View File

@ -20,3 +20,8 @@ func (repo *UserSessionRepo) GetMyUserSessions(ctx context.Context) ([]*usr_mode
} }
return model.UserSessionsToModel(userSessions), nil return model.UserSessionsToModel(userSessions), nil
} }
func (repo *UserSessionRepo) ActiveUserSessionCount() int64 {
userSessions, _ := repo.View.ActiveUserSessions()
return int64(len(userSessions))
}

View File

@ -22,12 +22,12 @@ const (
applicationTable = "auth.applications" applicationTable = "auth.applications"
) )
func (p *Application) ViewModel() string { func (a *Application) ViewModel() string {
return applicationTable return applicationTable
} }
func (p *Application) EventQuery() (*models.SearchQuery, error) { func (a *Application) EventQuery() (*models.SearchQuery, error) {
sequence, err := p.view.GetLatestApplicationSequence() sequence, err := a.view.GetLatestApplicationSequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -65,33 +65,37 @@ func (a *Application) Reduce(event *models.Event) (err error) {
if err != nil { if err != nil {
return err return err
} }
return a.view.DeleteApplication(app.ID, event.Sequence) return a.view.DeleteApplication(app.ID, event.Sequence, event.CreationDate)
case es_model.ProjectChanged: case es_model.ProjectChanged:
apps, err := a.view.ApplicationsByProjectID(event.AggregateID) apps, err := a.view.ApplicationsByProjectID(event.AggregateID)
if err != nil { if err != nil {
return err return err
} }
if len(apps) == 0 { if len(apps) == 0 {
return a.view.ProcessedApplicationSequence(event.Sequence) return a.view.ProcessedApplicationSequence(event.Sequence, event.CreationDate)
} }
for _, app := range apps { for _, app := range apps {
if err := app.AppendEvent(event); err != nil { if err := app.AppendEvent(event); err != nil {
return err return err
} }
} }
return a.view.PutApplications(apps, event.Sequence) return a.view.PutApplications(apps, event.Sequence, event.CreationDate)
case es_model.ProjectRemoved: case es_model.ProjectRemoved:
return a.view.DeleteApplicationsByProjectID(event.AggregateID) return a.view.DeleteApplicationsByProjectID(event.AggregateID)
default: default:
return a.view.ProcessedApplicationSequence(event.Sequence) return a.view.ProcessedApplicationSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return a.view.PutApplication(app) return a.view.PutApplication(app, event.CreationDate)
} }
func (p *Application) OnError(event *models.Event, spoolerError error) error { func (a *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") 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) return spooler.HandleError(event, spoolerError, a.view.GetLatestApplicationFailedEvent, a.view.ProcessedApplicationFailedEvent, a.view.ProcessedApplicationSequence, a.errorCountUntilSkip)
}
func (a *Application) OnSuccess() error {
return spooler.HandleSuccess(a.view.UpdateApplicationSpoolerRunTimestamp)
} }

View File

@ -19,12 +19,12 @@ const (
idpConfigTable = "auth.idp_configs" idpConfigTable = "auth.idp_configs"
) )
func (m *IDPConfig) ViewModel() string { func (i *IDPConfig) ViewModel() string {
return idpConfigTable return idpConfigTable
} }
func (m *IDPConfig) EventQuery() (*models.SearchQuery, error) { func (i *IDPConfig) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestIDPConfigSequence() sequence, err := i.view.GetLatestIDPConfigSequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -33,17 +33,17 @@ func (m *IDPConfig) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *IDPConfig) Reduce(event *models.Event) (err error) { func (i *IDPConfig) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.OrgAggregate: case model.OrgAggregate:
err = m.processIdpConfig(iam_model.IDPProviderTypeOrg, event) err = i.processIdpConfig(iam_model.IDPProviderTypeOrg, event)
case iam_es_model.IAMAggregate: case iam_es_model.IAMAggregate:
err = m.processIdpConfig(iam_model.IDPProviderTypeSystem, event) err = i.processIdpConfig(iam_model.IDPProviderTypeSystem, event)
} }
return err return err
} }
func (m *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, event *models.Event) (err error) { func (i *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, event *models.Event) (err error) {
idp := new(iam_view_model.IDPConfigView) idp := new(iam_view_model.IDPConfigView)
switch event.Type { switch event.Type {
case model.IDPConfigAdded, case model.IDPConfigAdded,
@ -56,7 +56,7 @@ func (m *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve
if err != nil { if err != nil {
return err return err
} }
idp, err = m.view.IDPConfigByID(idp.IDPConfigID) idp, err = i.view.IDPConfigByID(idp.IDPConfigID)
if err != nil { if err != nil {
return err return err
} }
@ -66,17 +66,21 @@ func (m *IDPConfig) processIdpConfig(providerType iam_model.IDPProviderType, eve
if err != nil { if err != nil {
return err return err
} }
return m.view.DeleteIDPConfig(idp.IDPConfigID, event.Sequence) return i.view.DeleteIDPConfig(idp.IDPConfigID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedIDPConfigSequence(event.Sequence) return i.view.ProcessedIDPConfigSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutIDPConfig(idp, idp.Sequence) return i.view.PutIDPConfig(idp, idp.Sequence, event.CreationDate)
} }
func (m *IDPConfig) OnError(event *models.Event, err error) error { func (i *IDPConfig) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Ejf8s", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp config handler") logging.LogWithFields("SPOOL-Ejf8s", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp config handler")
return spooler.HandleError(event, err, m.view.GetLatestIDPConfigFailedEvent, m.view.ProcessedIDPConfigFailedEvent, m.view.ProcessedIDPConfigSequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, i.view.GetLatestIDPConfigFailedEvent, i.view.ProcessedIDPConfigFailedEvent, i.view.ProcessedIDPConfigSequence, i.errorCountUntilSkip)
}
func (i *IDPConfig) OnSuccess() error {
return spooler.HandleSuccess(i.view.UpdateIDPConfigSpoolerRunTimestamp)
} }

View File

@ -27,12 +27,12 @@ const (
idpProviderTable = "auth.idp_providers" idpProviderTable = "auth.idp_providers"
) )
func (m *IDPProvider) ViewModel() string { func (i *IDPProvider) ViewModel() string {
return idpProviderTable return idpProviderTable
} }
func (m *IDPProvider) EventQuery() (*models.SearchQuery, error) { func (i *IDPProvider) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestIDPProviderSequence() sequence, err := i.view.GetLatestIDPProviderSequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -41,15 +41,15 @@ func (m *IDPProvider) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *IDPProvider) Reduce(event *models.Event) (err error) { func (i *IDPProvider) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.IAMAggregate, org_es_model.OrgAggregate: case model.IAMAggregate, org_es_model.OrgAggregate:
err = m.processIdpProvider(event) err = i.processIdpProvider(event)
} }
return err return err
} }
func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) { func (i *IDPProvider) processIdpProvider(event *models.Event) (err error) {
provider := new(iam_view_model.IDPProviderView) provider := new(iam_view_model.IDPProviderView)
switch event.Type { switch event.Type {
case model.LoginPolicyIDPProviderAdded, org_es_model.LoginPolicyIDPProviderAdded: case model.LoginPolicyIDPProviderAdded, org_es_model.LoginPolicyIDPProviderAdded:
@ -57,71 +57,75 @@ func (m *IDPProvider) processIdpProvider(event *models.Event) (err error) {
if err != nil { if err != nil {
return err return err
} }
err = m.fillData(provider) err = i.fillData(provider)
case model.LoginPolicyIDPProviderRemoved, model.LoginPolicyIDPProviderCascadeRemoved, case model.LoginPolicyIDPProviderRemoved, model.LoginPolicyIDPProviderCascadeRemoved,
org_es_model.LoginPolicyIDPProviderRemoved, org_es_model.LoginPolicyIDPProviderCascadeRemoved: org_es_model.LoginPolicyIDPProviderRemoved, org_es_model.LoginPolicyIDPProviderCascadeRemoved:
err = provider.SetData(event) err = provider.SetData(event)
if err != nil { if err != nil {
return err return err
} }
return m.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event.Sequence) return i.view.DeleteIDPProvider(event.AggregateID, provider.IDPConfigID, event.Sequence, event.CreationDate)
case model.IDPConfigChanged, org_es_model.IDPConfigChanged: case model.IDPConfigChanged, org_es_model.IDPConfigChanged:
esConfig := new(iam_view_model.IDPConfigView) esConfig := new(iam_view_model.IDPConfigView)
providerType := iam_model.IDPProviderTypeSystem providerType := iam_model.IDPProviderTypeSystem
if event.AggregateID != m.systemDefaults.IamID { if event.AggregateID != i.systemDefaults.IamID {
providerType = iam_model.IDPProviderTypeOrg providerType = iam_model.IDPProviderTypeOrg
} }
esConfig.AppendEvent(providerType, event) esConfig.AppendEvent(providerType, event)
providers, err := m.view.IDPProvidersByIDPConfigID(esConfig.IDPConfigID) providers, err := i.view.IDPProvidersByIDPConfigID(esConfig.IDPConfigID)
if err != nil { if err != nil {
return err return err
} }
config := new(iam_model.IDPConfig) config := new(iam_model.IDPConfig)
if event.AggregateID == m.systemDefaults.IamID { if event.AggregateID == i.systemDefaults.IamID {
config, err = m.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID) config, err = i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID)
} else { } else {
config, err = m.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID) config, err = i.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, esConfig.IDPConfigID)
} }
if err != nil { if err != nil {
return err return err
} }
for _, provider := range providers { for _, provider := range providers {
m.fillConfigData(provider, config) i.fillConfigData(provider, config)
} }
return m.view.PutIDPProviders(event.Sequence, providers...) return i.view.PutIDPProviders(event.Sequence, event.CreationDate, providers...)
case org_es_model.LoginPolicyRemoved: case org_es_model.LoginPolicyRemoved:
return m.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event.Sequence) return i.view.DeleteIDPProvidersByAggregateID(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedIDPProviderSequence(event.Sequence) return i.view.ProcessedIDPProviderSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutIDPProvider(provider, provider.Sequence) return i.view.PutIDPProvider(provider, provider.Sequence, event.CreationDate)
} }
func (m *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) { func (i *IDPProvider) fillData(provider *iam_view_model.IDPProviderView) (err error) {
var config *iam_model.IDPConfig var config *iam_model.IDPConfig
if provider.IDPProviderType == int32(iam_model.IDPProviderTypeSystem) { if provider.IDPProviderType == int32(iam_model.IDPProviderTypeSystem) {
config, err = m.iamEvents.GetIDPConfig(context.Background(), m.systemDefaults.IamID, provider.IDPConfigID) config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, provider.IDPConfigID)
} else { } else {
config, err = m.orgEvents.GetIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID) config, err = i.orgEvents.GetIDPConfig(context.Background(), provider.AggregateID, provider.IDPConfigID)
} }
if err != nil { if err != nil {
return err return err
} }
m.fillConfigData(provider, config) i.fillConfigData(provider, config)
return nil return nil
} }
func (m *IDPProvider) fillConfigData(provider *iam_view_model.IDPProviderView, config *iam_model.IDPConfig) { func (i *IDPProvider) fillConfigData(provider *iam_view_model.IDPProviderView, config *iam_model.IDPConfig) {
provider.Name = config.Name provider.Name = config.Name
provider.StylingType = int32(config.StylingType) provider.StylingType = int32(config.StylingType)
provider.IDPConfigType = int32(config.Type) provider.IDPConfigType = int32(config.Type)
provider.IDPState = int32(config.State) provider.IDPState = int32(config.State)
} }
func (m *IDPProvider) OnError(event *models.Event, err error) error { func (i *IDPProvider) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Fjd89", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler") logging.LogWithFields("SPOOL-Fjd89", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler")
return spooler.HandleError(event, err, m.view.GetLatestIDPProviderFailedEvent, m.view.ProcessedIDPProviderFailedEvent, m.view.ProcessedIDPProviderSequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, i.view.GetLatestIDPProviderFailedEvent, i.view.ProcessedIDPProviderFailedEvent, i.view.ProcessedIDPProviderSequence, i.errorCountUntilSkip)
}
func (i *IDPProvider) OnSuccess() error {
return spooler.HandleSuccess(i.view.UpdateIDPProviderSpoolerRunTimestamp)
} }

View File

@ -41,11 +41,11 @@ func (k *Key) Reduce(event *models.Event) error {
return err return err
} }
if privateKey.Expiry.Before(time.Now()) && publicKey.Expiry.Before(time.Now()) { if privateKey.Expiry.Before(time.Now()) && publicKey.Expiry.Before(time.Now()) {
return k.view.ProcessedKeySequence(event.Sequence) return k.view.ProcessedKeySequence(event.Sequence, event.CreationDate)
} }
return k.view.PutKeys(privateKey, publicKey, event.Sequence) return k.view.PutKeys(privateKey, publicKey, event.Sequence, event.CreationDate)
default: default:
return k.view.ProcessedKeySequence(event.Sequence) return k.view.ProcessedKeySequence(event.Sequence, event.CreationDate)
} }
} }
@ -53,3 +53,9 @@ 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") 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) return spooler.HandleError(event, err, k.view.GetLatestKeyFailedEvent, k.view.ProcessedKeyFailedEvent, k.view.ProcessedKeySequence, k.errorCountUntilSkip)
} }
func (k *Key) OnSuccess() error {
err := spooler.HandleSuccess(k.view.UpdateKeySpoolerRunTimestamp)
logging.LogWithFields("SPOOL-vM9sd", "table", keyTable).OnError(err).Warn("could not process on success func")
return err
}

View File

@ -19,12 +19,12 @@ const (
loginPolicyTable = "auth.login_policies" loginPolicyTable = "auth.login_policies"
) )
func (m *LoginPolicy) ViewModel() string { func (p *LoginPolicy) ViewModel() string {
return loginPolicyTable return loginPolicyTable
} }
func (m *LoginPolicy) EventQuery() (*models.SearchQuery, error) { func (p *LoginPolicy) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestLoginPolicySequence() sequence, err := p.view.GetLatestLoginPolicySequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -33,15 +33,15 @@ func (m *LoginPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *LoginPolicy) Reduce(event *models.Event) (err error) { func (p *LoginPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate: case model.OrgAggregate, iam_es_model.IAMAggregate:
err = m.processLoginPolicy(event) err = p.processLoginPolicy(event)
} }
return err return err
} }
func (m *LoginPolicy) processLoginPolicy(event *models.Event) (err error) { func (p *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
policy := new(iam_model.LoginPolicyView) policy := new(iam_model.LoginPolicyView)
switch event.Type { switch event.Type {
case iam_es_model.LoginPolicyAdded, model.LoginPolicyAdded: case iam_es_model.LoginPolicyAdded, model.LoginPolicyAdded:
@ -51,23 +51,27 @@ func (m *LoginPolicy) processLoginPolicy(event *models.Event) (err error) {
iam_es_model.LoginPolicySecondFactorRemoved, model.LoginPolicySecondFactorRemoved, iam_es_model.LoginPolicySecondFactorRemoved, model.LoginPolicySecondFactorRemoved,
iam_es_model.LoginPolicyMultiFactorAdded, model.LoginPolicyMultiFactorAdded, iam_es_model.LoginPolicyMultiFactorAdded, model.LoginPolicyMultiFactorAdded,
iam_es_model.LoginPolicyMultiFactorRemoved, model.LoginPolicyMultiFactorRemoved: iam_es_model.LoginPolicyMultiFactorRemoved, model.LoginPolicyMultiFactorRemoved:
policy, err = m.view.LoginPolicyByAggregateID(event.AggregateID) policy, err = p.view.LoginPolicyByAggregateID(event.AggregateID)
if err != nil { if err != nil {
return err return err
} }
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case model.LoginPolicyRemoved: case model.LoginPolicyRemoved:
return m.view.DeleteLoginPolicy(event.AggregateID, event.Sequence) return p.view.DeleteLoginPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedLoginPolicySequence(event.Sequence) return p.view.ProcessedLoginPolicySequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutLoginPolicy(policy, policy.Sequence) return p.view.PutLoginPolicy(policy, policy.Sequence, event.CreationDate)
} }
func (m *LoginPolicy) OnError(event *models.Event, err error) error { func (p *LoginPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-5id9s", "id", event.AggregateID).WithError(err).Warn("something went wrong in login policy handler") logging.LogWithFields("SPOOL-5id9s", "id", event.AggregateID).WithError(err).Warn("something went wrong in login policy handler")
return spooler.HandleError(event, err, m.view.GetLatestLoginPolicyFailedEvent, m.view.ProcessedLoginPolicyFailedEvent, m.view.ProcessedLoginPolicySequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, p.view.GetLatestLoginPolicyFailedEvent, p.view.ProcessedLoginPolicyFailedEvent, p.view.ProcessedLoginPolicySequence, p.errorCountUntilSkip)
}
func (p *LoginPolicy) OnSuccess() error {
return spooler.HandleSuccess(p.view.UpdateLoginPolicySpoolerRunTimestamp)
} }

View File

@ -48,26 +48,30 @@ func (d *MachineKeys) processMachineKeys(event *models.Event) (err error) {
case model.MachineKeyAdded: case model.MachineKeyAdded:
err = key.AppendEvent(event) err = key.AppendEvent(event)
if key.ExpirationDate.Before(time.Now()) { if key.ExpirationDate.Before(time.Now()) {
return d.view.ProcessedMachineKeySequence(event.Sequence) return d.view.ProcessedMachineKeySequence(event.Sequence, event.CreationDate)
} }
case model.MachineKeyRemoved: case model.MachineKeyRemoved:
err = key.SetData(event) err = key.SetData(event)
if err != nil { if err != nil {
return err return err
} }
return d.view.DeleteMachineKey(key.ID, event.Sequence) return d.view.DeleteMachineKey(key.ID, event.Sequence, event.CreationDate)
case model.UserRemoved: case model.UserRemoved:
return d.view.DeleteMachineKeysByUserID(event.AggregateID, event.Sequence) return d.view.DeleteMachineKeysByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return d.view.ProcessedMachineKeySequence(event.Sequence) return d.view.ProcessedMachineKeySequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return d.view.PutMachineKey(key, key.Sequence) return d.view.PutMachineKey(key, key.Sequence, event.CreationDate)
} }
func (d *MachineKeys) OnError(event *models.Event, err error) error { func (d *MachineKeys) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-S9fe", "id", event.AggregateID).WithError(err).Warn("something went wrong in machine key handler") logging.LogWithFields("SPOOL-S9fe", "id", event.AggregateID).WithError(err).Warn("something went wrong in machine key handler")
return spooler.HandleError(event, err, d.view.GetLatestMachineKeyFailedEvent, d.view.ProcessedMachineKeyFailedEvent, d.view.ProcessedMachineKeySequence, d.errorCountUntilSkip) return spooler.HandleError(event, err, d.view.GetLatestMachineKeyFailedEvent, d.view.ProcessedMachineKeyFailedEvent, d.view.ProcessedMachineKeySequence, d.errorCountUntilSkip)
} }
func (d *MachineKeys) OnSuccess() error {
return spooler.HandleSuccess(d.view.UpdateMachineKeySpoolerRunTimestamp)
}

View File

@ -58,16 +58,20 @@ func (o *Org) Reduce(event *es_models.Event) (err error) {
} }
org.Domain = domain.Domain org.Domain = domain.Domain
default: default:
return o.view.ProcessedOrgSequence(event.Sequence) return o.view.ProcessedOrgSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return o.view.PutOrg(org) return o.view.PutOrg(org, event.CreationDate)
} }
func (o *Org) OnError(event *es_models.Event, spoolerErr error) error { 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") 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) return spooler.HandleError(event, spoolerErr, o.view.GetLatestOrgFailedEvent, o.view.ProcessedOrgFailedEvent, o.view.ProcessedOrgSequence, o.errorCountUntilSkip)
} }
func (o *Org) OnSuccess() error {
return spooler.HandleSuccess(o.view.UpdateOrgSpoolerRunTimestamp)
}

View File

@ -19,12 +19,12 @@ const (
orgIAMPolicyTable = "auth.org_iam_policies" orgIAMPolicyTable = "auth.org_iam_policies"
) )
func (m *OrgIAMPolicy) ViewModel() string { func (p *OrgIAMPolicy) ViewModel() string {
return orgIAMPolicyTable return orgIAMPolicyTable
} }
func (m *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) { func (p *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestOrgIAMPolicySequence() sequence, err := p.view.GetLatestOrgIAMPolicySequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -33,37 +33,41 @@ func (m *OrgIAMPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *OrgIAMPolicy) Reduce(event *models.Event) (err error) { func (p *OrgIAMPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate: case model.OrgAggregate, iam_es_model.IAMAggregate:
err = m.processOrgIAMPolicy(event) err = p.processOrgIAMPolicy(event)
} }
return err return err
} }
func (m *OrgIAMPolicy) processOrgIAMPolicy(event *models.Event) (err error) { func (p *OrgIAMPolicy) processOrgIAMPolicy(event *models.Event) (err error) {
policy := new(iam_model.OrgIAMPolicyView) policy := new(iam_model.OrgIAMPolicyView)
switch event.Type { switch event.Type {
case iam_es_model.OrgIAMPolicyAdded, model.OrgIAMPolicyAdded: case iam_es_model.OrgIAMPolicyAdded, model.OrgIAMPolicyAdded:
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case iam_es_model.OrgIAMPolicyChanged, model.OrgIAMPolicyChanged: case iam_es_model.OrgIAMPolicyChanged, model.OrgIAMPolicyChanged:
policy, err = m.view.OrgIAMPolicyByAggregateID(event.AggregateID) policy, err = p.view.OrgIAMPolicyByAggregateID(event.AggregateID)
if err != nil { if err != nil {
return err return err
} }
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case model.OrgIAMPolicyRemoved: case model.OrgIAMPolicyRemoved:
return m.view.DeleteOrgIAMPolicy(event.AggregateID, event.Sequence) return p.view.DeleteOrgIAMPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedOrgIAMPolicySequence(event.Sequence) return p.view.ProcessedOrgIAMPolicySequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutOrgIAMPolicy(policy, policy.Sequence) return p.view.PutOrgIAMPolicy(policy, policy.Sequence, event.CreationDate)
} }
func (m *OrgIAMPolicy) OnError(event *models.Event, err error) error { func (p *OrgIAMPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-3Gj8s", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgIAM policy handler") logging.LogWithFields("SPOOL-3Gj8s", "id", event.AggregateID).WithError(err).Warn("something went wrong in orgIAM policy handler")
return spooler.HandleError(event, err, m.view.GetLatestOrgIAMPolicyFailedEvent, m.view.ProcessedOrgIAMPolicyFailedEvent, m.view.ProcessedOrgIAMPolicySequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, p.view.GetLatestOrgIAMPolicyFailedEvent, p.view.ProcessedOrgIAMPolicyFailedEvent, p.view.ProcessedOrgIAMPolicySequence, p.errorCountUntilSkip)
}
func (p *OrgIAMPolicy) OnSuccess() error {
return spooler.HandleSuccess(p.view.UpdateOrgIAMPolicySpoolerRunTimestamp)
} }

View File

@ -19,12 +19,12 @@ const (
passwordComplexityPolicyTable = "auth.password_complexity_policies" passwordComplexityPolicyTable = "auth.password_complexity_policies"
) )
func (m *PasswordComplexityPolicy) ViewModel() string { func (p *PasswordComplexityPolicy) ViewModel() string {
return passwordComplexityPolicyTable return passwordComplexityPolicyTable
} }
func (m *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) { func (p *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestPasswordComplexityPolicySequence() sequence, err := p.view.GetLatestPasswordComplexityPolicySequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -33,37 +33,41 @@ func (m *PasswordComplexityPolicy) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *PasswordComplexityPolicy) Reduce(event *models.Event) (err error) { func (p *PasswordComplexityPolicy) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.OrgAggregate, iam_es_model.IAMAggregate: case model.OrgAggregate, iam_es_model.IAMAggregate:
err = m.processPasswordComplexityPolicy(event) err = p.processPasswordComplexityPolicy(event)
} }
return err return err
} }
func (m *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *models.Event) (err error) { func (p *PasswordComplexityPolicy) processPasswordComplexityPolicy(event *models.Event) (err error) {
policy := new(iam_model.PasswordComplexityPolicyView) policy := new(iam_model.PasswordComplexityPolicyView)
switch event.Type { switch event.Type {
case iam_es_model.PasswordComplexityPolicyAdded, model.PasswordComplexityPolicyAdded: case iam_es_model.PasswordComplexityPolicyAdded, model.PasswordComplexityPolicyAdded:
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case iam_es_model.PasswordComplexityPolicyChanged, model.PasswordComplexityPolicyChanged: case iam_es_model.PasswordComplexityPolicyChanged, model.PasswordComplexityPolicyChanged:
policy, err = m.view.PasswordComplexityPolicyByAggregateID(event.AggregateID) policy, err = p.view.PasswordComplexityPolicyByAggregateID(event.AggregateID)
if err != nil { if err != nil {
return err return err
} }
err = policy.AppendEvent(event) err = policy.AppendEvent(event)
case model.PasswordComplexityPolicyRemoved: case model.PasswordComplexityPolicyRemoved:
return m.view.DeletePasswordComplexityPolicy(event.AggregateID, event.Sequence) return p.view.DeletePasswordComplexityPolicy(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedPasswordComplexityPolicySequence(event.Sequence) return p.view.ProcessedPasswordComplexityPolicySequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutPasswordComplexityPolicy(policy, policy.Sequence) return p.view.PutPasswordComplexityPolicy(policy, policy.Sequence, event.CreationDate)
} }
func (m *PasswordComplexityPolicy) OnError(event *models.Event, err error) error { func (p *PasswordComplexityPolicy) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordComplexity policy handler") logging.LogWithFields("SPOOL-4Djo9", "id", event.AggregateID).WithError(err).Warn("something went wrong in passwordComplexity policy handler")
return spooler.HandleError(event, err, m.view.GetLatestPasswordComplexityPolicyFailedEvent, m.view.ProcessedPasswordComplexityPolicyFailedEvent, m.view.ProcessedPasswordComplexityPolicySequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, p.view.GetLatestPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicyFailedEvent, p.view.ProcessedPasswordComplexityPolicySequence, p.errorCountUntilSkip)
}
func (p *PasswordComplexityPolicy) OnSuccess() error {
return spooler.HandleSuccess(p.view.UpdatePasswordComplexityPolicySpoolerRunTimestamp)
} }

View File

@ -52,19 +52,23 @@ func (p *ProjectRole) Reduce(event *models.Event) (err error) {
if err != nil { if err != nil {
return err return err
} }
return p.view.DeleteProjectRole(event.AggregateID, event.ResourceOwner, role.Key, event.Sequence) return p.view.DeleteProjectRole(event.AggregateID, event.ResourceOwner, role.Key, event.Sequence, event.CreationDate)
case es_model.ProjectRemoved: case es_model.ProjectRemoved:
return p.view.DeleteProjectRolesByProjectID(event.AggregateID) return p.view.DeleteProjectRolesByProjectID(event.AggregateID)
default: default:
return p.view.ProcessedProjectRoleSequence(event.Sequence) return p.view.ProcessedProjectRoleSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return p.view.PutProjectRole(role) return p.view.PutProjectRole(role, event.CreationDate)
} }
func (p *ProjectRole) OnError(event *models.Event, err error) error { func (p *ProjectRole) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-lso9w", "id", event.AggregateID).WithError(err).Warn("something went wrong in project role handler") logging.LogWithFields("SPOOL-lso9w", "id", event.AggregateID).WithError(err).Warn("something went wrong in project role handler")
return spooler.HandleError(event, err, p.view.GetLatestProjectRoleFailedEvent, p.view.ProcessedProjectRoleFailedEvent, p.view.ProcessedProjectRoleSequence, p.errorCountUntilSkip) return spooler.HandleError(event, err, p.view.GetLatestProjectRoleFailedEvent, p.view.ProcessedProjectRoleFailedEvent, p.view.ProcessedProjectRoleSequence, p.errorCountUntilSkip)
} }
func (p *ProjectRole) OnSuccess() error {
return spooler.HandleSuccess(p.view.UpdateProjectRoleSpoolerRunTimestamp)
}

View File

@ -49,7 +49,7 @@ func (t *Token) Reduce(event *models.Event) (err error) {
if err != nil { if err != nil {
return err return err
} }
return t.view.PutToken(token) return t.view.PutToken(token, event.CreationDate)
case user_es_model.UserProfileChanged, case user_es_model.UserProfileChanged,
user_es_model.HumanProfileChanged: user_es_model.HumanProfileChanged:
user := new(view_model.UserView) user := new(view_model.UserView)
@ -61,25 +61,25 @@ func (t *Token) Reduce(event *models.Event) (err error) {
for _, token := range tokens { for _, token := range tokens {
token.PreferredLanguage = user.PreferredLanguage token.PreferredLanguage = user.PreferredLanguage
} }
return t.view.PutTokens(tokens, event.Sequence) return t.view.PutTokens(tokens, event.Sequence, event.CreationDate)
case user_es_model.SignedOut, case user_es_model.SignedOut,
user_es_model.HumanSignedOut: user_es_model.HumanSignedOut:
id, err := agentIDFromSession(event) id, err := agentIDFromSession(event)
if err != nil { if err != nil {
return err return err
} }
return t.view.DeleteSessionTokens(id, event.AggregateID, event.Sequence) return t.view.DeleteSessionTokens(id, event.AggregateID, event.Sequence, event.CreationDate)
case user_es_model.UserLocked, case user_es_model.UserLocked,
user_es_model.UserDeactivated, user_es_model.UserDeactivated,
user_es_model.UserRemoved: user_es_model.UserRemoved:
return t.view.DeleteUserTokens(event.AggregateID, event.Sequence) return t.view.DeleteUserTokens(event.AggregateID, event.Sequence, event.CreationDate)
case project_es_model.ApplicationDeactivated, case project_es_model.ApplicationDeactivated,
project_es_model.ApplicationRemoved: project_es_model.ApplicationRemoved:
application, err := applicationFromSession(event) application, err := applicationFromSession(event)
if err != nil { if err != nil {
return err return err
} }
return t.view.DeleteApplicationTokens(event.Sequence, application.AppID) return t.view.DeleteApplicationTokens(event.Sequence, event.CreationDate, application.AppID)
case project_es_model.ProjectDeactivated, case project_es_model.ProjectDeactivated,
project_es_model.ProjectRemoved: project_es_model.ProjectRemoved:
project, err := t.ProjectEvents.ProjectByID(context.Background(), event.AggregateID) project, err := t.ProjectEvents.ProjectByID(context.Background(), event.AggregateID)
@ -90,9 +90,9 @@ func (t *Token) Reduce(event *models.Event) (err error) {
for _, app := range project.Applications { for _, app := range project.Applications {
applicationsIDs = append(applicationsIDs, app.AppID) applicationsIDs = append(applicationsIDs, app.AppID)
} }
return t.view.DeleteApplicationTokens(event.Sequence, applicationsIDs...) return t.view.DeleteApplicationTokens(event.Sequence, event.CreationDate, applicationsIDs...)
default: default:
return t.view.ProcessedTokenSequence(event.Sequence) return t.view.ProcessedTokenSequence(event.Sequence, event.CreationDate)
} }
} }
@ -118,3 +118,7 @@ func applicationFromSession(event *models.Event) (*project_es_model.Application,
} }
return application, nil return application, nil
} }
func (t *Token) OnSuccess() error {
return spooler.HandleSuccess(t.view.UpdateTokenSpoolerRunTimestamp)
}

View File

@ -67,7 +67,7 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
if err != nil { if err != nil {
return err return err
} }
u.fillLoginNames(user) err = u.fillLoginNames(user)
case es_model.UserProfileChanged, case es_model.UserProfileChanged,
es_model.UserEmailChanged, es_model.UserEmailChanged,
es_model.UserEmailVerified, es_model.UserEmailVerified,
@ -94,6 +94,12 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
es_model.HumanMFAOTPAdded, es_model.HumanMFAOTPAdded,
es_model.HumanMFAOTPVerified, es_model.HumanMFAOTPVerified,
es_model.HumanMFAOTPRemoved, es_model.HumanMFAOTPRemoved,
es_model.HumanMFAU2FTokenAdded,
es_model.HumanMFAU2FTokenVerified,
es_model.HumanMFAU2FTokenRemoved,
es_model.HumanPasswordlessTokenAdded,
es_model.HumanPasswordlessTokenVerified,
es_model.HumanPasswordlessTokenRemoved,
es_model.HumanMFAInitSkipped, es_model.HumanMFAInitSkipped,
es_model.MachineChanged, es_model.MachineChanged,
es_model.HumanPasswordChanged: es_model.HumanPasswordChanged:
@ -114,14 +120,14 @@ func (u *User) ProcessUser(event *models.Event) (err error) {
} }
err = u.fillLoginNames(user) err = u.fillLoginNames(user)
case es_model.UserRemoved: case es_model.UserRemoved:
return u.view.DeleteUser(event.AggregateID, event.Sequence) return u.view.DeleteUser(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return u.view.ProcessedUserSequence(event.Sequence) return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return u.view.PutUser(user, user.Sequence) return u.view.PutUser(user, user.Sequence, event.CreationDate)
} }
func (u *User) fillLoginNames(user *view_model.UserView) (err error) { func (u *User) fillLoginNames(user *view_model.UserView) (err error) {
@ -152,7 +158,7 @@ func (u *User) ProcessOrg(event *models.Event) (err error) {
case org_es_model.OrgDomainPrimarySet: case org_es_model.OrgDomainPrimarySet:
return u.fillPreferredLoginNamesOnOrgUsers(event) return u.fillPreferredLoginNamesOnOrgUsers(event)
default: default:
return u.view.ProcessedUserSequence(event.Sequence) return u.view.ProcessedUserSequence(event.Sequence, event.CreationDate)
} }
} }
@ -175,7 +181,7 @@ func (u *User) fillLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users { for _, user := range users {
user.SetLoginNames(policy, org.Domains) user.SetLoginNames(policy, org.Domains)
} }
return u.view.PutUsers(users, event.Sequence) return u.view.PutUsers(users, event.Sequence, event.CreationDate)
} }
func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error { func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
@ -200,10 +206,14 @@ func (u *User) fillPreferredLoginNamesOnOrgUsers(event *models.Event) error {
for _, user := range users { for _, user := range users {
user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain) user.PreferredLoginName = user.GenerateLoginName(org.GetPrimaryDomain().Domain, policy.UserLoginMustBeDomain)
} }
return u.view.PutUsers(users, 0) return u.view.PutUsers(users, 0, event.CreationDate)
} }
func (u *User) OnError(event *models.Event, err error) error { func (u *User) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-is8aAWima", "id", event.AggregateID).WithError(err).Warn("something went wrong in user handler") logging.LogWithFields("SPOOL-is8aAWima", "id", event.AggregateID).WithError(err).Warn("something went wrong in user handler")
return spooler.HandleError(event, err, u.view.GetLatestUserFailedEvent, u.view.ProcessedUserFailedEvent, u.view.ProcessedUserSequence, u.errorCountUntilSkip) return spooler.HandleError(event, err, u.view.GetLatestUserFailedEvent, u.view.ProcessedUserFailedEvent, u.view.ProcessedUserSequence, u.errorCountUntilSkip)
} }
func (u *User) OnSuccess() error {
return spooler.HandleSuccess(u.view.UpdateUserSpoolerRunTimestamp)
}

View File

@ -29,12 +29,12 @@ const (
externalIDPTable = "auth.user_external_idps" externalIDPTable = "auth.user_external_idps"
) )
func (m *ExternalIDP) ViewModel() string { func (i *ExternalIDP) ViewModel() string {
return externalIDPTable return externalIDPTable
} }
func (m *ExternalIDP) EventQuery() (*models.SearchQuery, error) { func (i *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
sequence, err := m.view.GetLatestExternalIDPSequence() sequence, err := i.view.GetLatestExternalIDPSequence()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -43,17 +43,17 @@ func (m *ExternalIDP) EventQuery() (*models.SearchQuery, error) {
LatestSequenceFilter(sequence.CurrentSequence), nil LatestSequenceFilter(sequence.CurrentSequence), nil
} }
func (m *ExternalIDP) Reduce(event *models.Event) (err error) { func (i *ExternalIDP) Reduce(event *models.Event) (err error) {
switch event.AggregateType { switch event.AggregateType {
case model.UserAggregate: case model.UserAggregate:
err = m.processUser(event) err = i.processUser(event)
case iam_es_model.IAMAggregate, org_es_model.OrgAggregate: case iam_es_model.IAMAggregate, org_es_model.OrgAggregate:
err = m.processIdpConfig(event) err = i.processIdpConfig(event)
} }
return err return err
} }
func (m *ExternalIDP) processUser(event *models.Event) (err error) { func (i *ExternalIDP) processUser(event *models.Event) (err error) {
externalIDP := new(usr_view_model.ExternalIDPView) externalIDP := new(usr_view_model.ExternalIDPView)
switch event.Type { switch event.Type {
case model.HumanExternalIDPAdded: case model.HumanExternalIDPAdded:
@ -61,25 +61,25 @@ func (m *ExternalIDP) processUser(event *models.Event) (err error) {
if err != nil { if err != nil {
return err return err
} }
err = m.fillData(externalIDP) err = i.fillData(externalIDP)
case model.HumanExternalIDPRemoved, model.HumanExternalIDPCascadeRemoved: case model.HumanExternalIDPRemoved, model.HumanExternalIDPCascadeRemoved:
err = externalIDP.SetData(event) err = externalIDP.SetData(event)
if err != nil { if err != nil {
return err return err
} }
return m.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event.Sequence) return i.view.DeleteExternalIDP(externalIDP.ExternalUserID, externalIDP.IDPConfigID, event.Sequence, event.CreationDate)
case model.UserRemoved: case model.UserRemoved:
return m.view.DeleteExternalIDPsByUserID(event.AggregateID, event.Sequence) return i.view.DeleteExternalIDPsByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedExternalIDPSequence(event.Sequence) return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutExternalIDP(externalIDP, externalIDP.Sequence) return i.view.PutExternalIDP(externalIDP, externalIDP.Sequence, event.CreationDate)
} }
func (m *ExternalIDP) processIdpConfig(event *models.Event) (err error) { func (i *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
switch event.Type { switch event.Type {
case iam_es_model.IDPConfigChanged, org_es_model.IDPConfigChanged: case iam_es_model.IDPConfigChanged, org_es_model.IDPConfigChanged:
configView := new(iam_view_model.IDPConfigView) configView := new(iam_view_model.IDPConfigView)
@ -89,45 +89,49 @@ func (m *ExternalIDP) processIdpConfig(event *models.Event) (err error) {
} else { } else {
configView.AppendEvent(iam_model.IDPProviderTypeOrg, event) configView.AppendEvent(iam_model.IDPProviderTypeOrg, event)
} }
exterinalIDPs, err := m.view.ExternalIDPsByIDPConfigID(configView.IDPConfigID) exterinalIDPs, err := i.view.ExternalIDPsByIDPConfigID(configView.IDPConfigID)
if err != nil { if err != nil {
return err return err
} }
if event.AggregateType == iam_es_model.IAMAggregate { if event.AggregateType == iam_es_model.IAMAggregate {
config, err = m.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID) config, err = i.iamEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
} else { } else {
config, err = m.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID) config, err = i.orgEvents.GetIDPConfig(context.Background(), event.AggregateID, configView.IDPConfigID)
} }
if err != nil { if err != nil {
return err return err
} }
for _, provider := range exterinalIDPs { for _, provider := range exterinalIDPs {
m.fillConfigData(provider, config) i.fillConfigData(provider, config)
} }
return m.view.PutExternalIDPs(event.Sequence, exterinalIDPs...) return i.view.PutExternalIDPs(event.Sequence, event.CreationDate, exterinalIDPs...)
default: default:
return m.view.ProcessedExternalIDPSequence(event.Sequence) return i.view.ProcessedExternalIDPSequence(event.Sequence, event.CreationDate)
} }
return nil return nil
} }
func (m *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error { func (i *ExternalIDP) fillData(externalIDP *usr_view_model.ExternalIDPView) error {
config, err := m.orgEvents.GetIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID) config, err := i.orgEvents.GetIDPConfig(context.Background(), externalIDP.ResourceOwner, externalIDP.IDPConfigID)
if caos_errs.IsNotFound(err) { if caos_errs.IsNotFound(err) {
config, err = m.iamEvents.GetIDPConfig(context.Background(), m.systemDefaults.IamID, externalIDP.IDPConfigID) config, err = i.iamEvents.GetIDPConfig(context.Background(), i.systemDefaults.IamID, externalIDP.IDPConfigID)
} }
if err != nil { if err != nil {
return err return err
} }
m.fillConfigData(externalIDP, config) i.fillConfigData(externalIDP, config)
return nil return nil
} }
func (m *ExternalIDP) fillConfigData(externalIDP *usr_view_model.ExternalIDPView, config *iam_model.IDPConfig) { func (i *ExternalIDP) fillConfigData(externalIDP *usr_view_model.ExternalIDPView, config *iam_model.IDPConfig) {
externalIDP.IDPName = config.Name externalIDP.IDPName = config.Name
} }
func (m *ExternalIDP) OnError(event *models.Event, err error) error { func (i *ExternalIDP) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-4Rsu8", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler") logging.LogWithFields("SPOOL-4Rsu8", "id", event.AggregateID).WithError(err).Warn("something went wrong in idp provider handler")
return spooler.HandleError(event, err, m.view.GetLatestExternalIDPFailedEvent, m.view.ProcessedExternalIDPFailedEvent, m.view.ProcessedExternalIDPSequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, i.view.GetLatestExternalIDPFailedEvent, i.view.ProcessedExternalIDPFailedEvent, i.view.ProcessedExternalIDPSequence, i.errorCountUntilSkip)
}
func (i *ExternalIDP) OnSuccess() error {
return spooler.HandleSuccess(i.view.UpdateExternalIDPSpoolerRunTimestamp)
} }

View File

@ -97,14 +97,14 @@ func (u *UserGrant) processUserGrant(event *models.Event) (err error) {
} }
err = grant.AppendEvent(event) err = grant.AppendEvent(event)
case grant_es_model.UserGrantRemoved, grant_es_model.UserGrantCascadeRemoved: case grant_es_model.UserGrantRemoved, grant_es_model.UserGrantCascadeRemoved:
return u.view.DeleteUserGrant(event.AggregateID, event.Sequence) return u.view.DeleteUserGrant(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return u.view.ProcessedUserGrantSequence(event.Sequence) return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return u.view.PutUserGrant(grant, grant.Sequence) return u.view.PutUserGrant(grant, grant.Sequence, event.CreationDate)
} }
func (u *UserGrant) processUser(event *models.Event) (err error) { func (u *UserGrant) processUser(event *models.Event) (err error) {
@ -119,7 +119,7 @@ func (u *UserGrant) processUser(event *models.Event) (err error) {
return err return err
} }
if len(grants) == 0 { if len(grants) == 0 {
return u.view.ProcessedUserGrantSequence(event.Sequence) return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
} }
user, err := u.userEvents.UserByID(context.Background(), event.AggregateID) user, err := u.userEvents.UserByID(context.Background(), event.AggregateID)
if err != nil { if err != nil {
@ -128,9 +128,9 @@ func (u *UserGrant) processUser(event *models.Event) (err error) {
for _, grant := range grants { for _, grant := range grants {
u.fillUserData(grant, user) u.fillUserData(grant, user)
} }
return u.view.PutUserGrants(grants, event.Sequence) return u.view.PutUserGrants(grants, event.Sequence, event.CreationDate)
default: default:
return u.view.ProcessedUserGrantSequence(event.Sequence) return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
} }
} }
@ -148,7 +148,7 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
for _, grant := range grants { for _, grant := range grants {
u.fillProjectData(grant, project) u.fillProjectData(grant, project)
} }
return u.view.PutUserGrants(grants, event.Sequence) return u.view.PutUserGrants(grants, event.Sequence, event.CreationDate)
case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectMemberRemoved: case proj_es_model.ProjectMemberAdded, proj_es_model.ProjectMemberChanged, proj_es_model.ProjectMemberRemoved:
member := new(proj_es_model.ProjectMember) member := new(proj_es_model.ProjectMember)
member.SetData(event) member.SetData(event)
@ -158,7 +158,7 @@ func (u *UserGrant) processProject(event *models.Event) (err error) {
member.SetData(event) member.SetData(event)
return u.processMember(event, "PROJECT_GRANT", member.GrantID, member.UserID, member.Roles) return u.processMember(event, "PROJECT_GRANT", member.GrantID, member.UserID, member.Roles)
default: default:
return u.view.ProcessedUserGrantSequence(event.Sequence) return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
} }
} }
@ -169,7 +169,7 @@ func (u *UserGrant) processOrg(event *models.Event) (err error) {
member.SetData(event) member.SetData(event)
return u.processMember(event, "ORG", "", member.UserID, member.Roles) return u.processMember(event, "ORG", "", member.UserID, member.Roles)
default: default:
return u.view.ProcessedUserGrantSequence(event.Sequence) return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
} }
} }
@ -207,16 +207,16 @@ func (u *UserGrant) processIAMMember(event *models.Event, rolePrefix string, suf
} }
grant.Sequence = event.Sequence grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate grant.ChangeDate = event.CreationDate
return u.view.PutUserGrant(grant, grant.Sequence) return u.view.PutUserGrant(grant, grant.Sequence, event.CreationDate)
case iam_es_model.IAMMemberRemoved: case iam_es_model.IAMMemberRemoved:
member.SetData(event) member.SetData(event)
grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID) grant, err := u.view.UserGrantByIDs(u.iamID, u.iamProjectID, member.UserID)
if err != nil { if err != nil {
return err return err
} }
return u.view.DeleteUserGrant(grant.ID, event.Sequence) return u.view.DeleteUserGrant(grant.ID, event.Sequence, event.CreationDate)
default: default:
return u.view.ProcessedUserGrantSequence(event.Sequence) return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
} }
} }
@ -252,7 +252,7 @@ func (u *UserGrant) processMember(event *models.Event, rolePrefix, roleSuffix st
} }
grant.Sequence = event.Sequence grant.Sequence = event.Sequence
grant.ChangeDate = event.CreationDate grant.ChangeDate = event.CreationDate
return u.view.PutUserGrant(grant, event.Sequence) return u.view.PutUserGrant(grant, event.Sequence, event.CreationDate)
case org_es_model.OrgMemberRemoved, case org_es_model.OrgMemberRemoved,
proj_es_model.ProjectMemberRemoved, proj_es_model.ProjectMemberRemoved,
proj_es_model.ProjectGrantMemberRemoved: proj_es_model.ProjectGrantMemberRemoved:
@ -262,18 +262,18 @@ func (u *UserGrant) processMember(event *models.Event, rolePrefix, roleSuffix st
return err return err
} }
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
return u.view.ProcessedUserGrantSequence(event.Sequence) return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
} }
if roleSuffix != "" { if roleSuffix != "" {
roleKeys = suffixRoles(roleSuffix, roleKeys) roleKeys = suffixRoles(roleSuffix, roleKeys)
} }
if grant.RoleKeys == nil { if grant.RoleKeys == nil {
return u.view.ProcessedUserGrantSequence(event.Sequence) return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
} }
grant.RoleKeys = mergeExistingRoles(rolePrefix, roleSuffix, grant.RoleKeys, nil) grant.RoleKeys = mergeExistingRoles(rolePrefix, roleSuffix, grant.RoleKeys, nil)
return u.view.PutUserGrant(grant, event.Sequence) return u.view.PutUserGrant(grant, event.Sequence, event.CreationDate)
default: default:
return u.view.ProcessedUserGrantSequence(event.Sequence) return u.view.ProcessedUserGrantSequence(event.Sequence, event.CreationDate)
} }
} }
@ -367,3 +367,7 @@ func (u *UserGrant) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-UZmc7", "id", event.AggregateID).WithError(err).Warn("something went wrong in user grant handler") logging.LogWithFields("SPOOL-UZmc7", "id", event.AggregateID).WithError(err).Warn("something went wrong in user grant handler")
return spooler.HandleError(event, err, u.view.GetLatestUserGrantFailedEvent, u.view.ProcessedUserGrantFailedEvent, u.view.ProcessedUserGrantSequence, u.errorCountUntilSkip) return spooler.HandleError(event, err, u.view.GetLatestUserGrantFailedEvent, u.view.ProcessedUserGrantFailedEvent, u.view.ProcessedUserGrantSequence, u.errorCountUntilSkip)
} }
func (u *UserGrant) OnSuccess() error {
return spooler.HandleSuccess(u.view.UpdateUserGrantSpoolerRunTimestamp)
}

View File

@ -74,14 +74,14 @@ func (m *UserMembership) processIam(event *models.Event) (err error) {
} }
err = member.AppendEvent(event) err = member.AppendEvent(event)
case iam_es_model.IAMMemberRemoved: case iam_es_model.IAMMemberRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event.Sequence) return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeIam, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedUserMembershipSequence(event.Sequence) return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutUserMembership(member, event.Sequence) return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
} }
func (m *UserMembership) fillIamDisplayName(member *usr_es_model.UserMembershipView) { func (m *UserMembership) fillIamDisplayName(member *usr_es_model.UserMembershipView) {
@ -105,16 +105,16 @@ func (m *UserMembership) processOrg(event *models.Event) (err error) {
} }
err = member.AppendEvent(event) err = member.AppendEvent(event)
case org_es_model.OrgMemberRemoved: case org_es_model.OrgMemberRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence) return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeOrganisation, event.Sequence, event.CreationDate)
case org_es_model.OrgChanged: case org_es_model.OrgChanged:
return m.updateOrgName(event) return m.updateOrgName(event)
default: default:
return m.view.ProcessedUserMembershipSequence(event.Sequence) return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutUserMembership(member, event.Sequence) return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
} }
func (m *UserMembership) fillOrgName(member *usr_es_model.UserMembershipView) (err error) { func (m *UserMembership) fillOrgName(member *usr_es_model.UserMembershipView) (err error) {
@ -145,7 +145,7 @@ func (m *UserMembership) updateOrgName(event *models.Event) error {
membership.DisplayName = org.Name membership.DisplayName = org.Name
} }
} }
return m.view.BulkPutUserMemberships(memberships, event.Sequence) return m.view.BulkPutUserMemberships(memberships, event.Sequence, event.CreationDate)
} }
func (m *UserMembership) processProject(event *models.Event) (err error) { func (m *UserMembership) processProject(event *models.Event) (err error) {
@ -168,7 +168,7 @@ func (m *UserMembership) processProject(event *models.Event) (err error) {
} }
err = member.AppendEvent(event) err = member.AppendEvent(event)
case proj_es_model.ProjectMemberRemoved: case proj_es_model.ProjectMemberRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event.Sequence) return m.view.DeleteUserMembership(member.UserID, event.AggregateID, event.AggregateID, usr_model.MemberTypeProject, event.Sequence, event.CreationDate)
case proj_es_model.ProjectGrantMemberChanged: case proj_es_model.ProjectGrantMemberChanged:
member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant) member, err = m.view.UserMembershipByIDs(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant)
if err != nil { if err != nil {
@ -176,20 +176,20 @@ func (m *UserMembership) processProject(event *models.Event) (err error) {
} }
err = member.AppendEvent(event) err = member.AppendEvent(event)
case proj_es_model.ProjectGrantMemberRemoved: case proj_es_model.ProjectGrantMemberRemoved:
return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence) return m.view.DeleteUserMembership(member.UserID, event.AggregateID, member.ObjectID, usr_model.MemberTypeProjectGrant, event.Sequence, event.CreationDate)
case proj_es_model.ProjectChanged: case proj_es_model.ProjectChanged:
return m.updateProjectDisplayName(event) return m.updateProjectDisplayName(event)
case proj_es_model.ProjectRemoved: case proj_es_model.ProjectRemoved:
return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.Sequence) return m.view.DeleteUserMembershipsByAggregateID(event.AggregateID, event.Sequence, event.CreationDate)
case proj_es_model.ProjectGrantRemoved: case proj_es_model.ProjectGrantRemoved:
return m.view.DeleteUserMembershipsByAggregateIDAndObjectID(event.AggregateID, member.ObjectID, event.Sequence) return m.view.DeleteUserMembershipsByAggregateIDAndObjectID(event.AggregateID, member.ObjectID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedUserMembershipSequence(event.Sequence) return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
} }
if err != nil { if err != nil {
return err return err
} }
return m.view.PutUserMembership(member, event.Sequence) return m.view.PutUserMembership(member, event.Sequence, event.CreationDate)
} }
func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembershipView) (err error) { func (m *UserMembership) fillProjectDisplayName(member *usr_es_model.UserMembershipView) (err error) {
@ -214,15 +214,15 @@ func (m *UserMembership) updateProjectDisplayName(event *models.Event) error {
for _, membership := range memberships { for _, membership := range memberships {
membership.DisplayName = project.Name membership.DisplayName = project.Name
} }
return m.view.BulkPutUserMemberships(memberships, event.Sequence) return m.view.BulkPutUserMemberships(memberships, event.Sequence, event.CreationDate)
} }
func (m *UserMembership) processUser(event *models.Event) (err error) { func (m *UserMembership) processUser(event *models.Event) (err error) {
switch event.Type { switch event.Type {
case model.UserRemoved: case model.UserRemoved:
return m.view.DeleteUserMembershipsByUserID(event.AggregateID, event.Sequence) return m.view.DeleteUserMembershipsByUserID(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return m.view.ProcessedUserMembershipSequence(event.Sequence) return m.view.ProcessedUserMembershipSequence(event.Sequence, event.CreationDate)
} }
} }
@ -230,3 +230,7 @@ func (m *UserMembership) OnError(event *models.Event, err error) error {
logging.LogWithFields("SPOOL-Ms3fj", "id", event.AggregateID).WithError(err).Warn("something went wrong in user membership handler") logging.LogWithFields("SPOOL-Ms3fj", "id", event.AggregateID).WithError(err).Warn("something went wrong in user membership handler")
return spooler.HandleError(event, err, m.view.GetLatestUserMembershipFailedEvent, m.view.ProcessedUserMembershipFailedEvent, m.view.ProcessedUserMembershipSequence, m.errorCountUntilSkip) return spooler.HandleError(event, err, m.view.GetLatestUserMembershipFailedEvent, m.view.ProcessedUserMembershipFailedEvent, m.view.ProcessedUserMembershipSequence, m.errorCountUntilSkip)
} }
func (m *UserMembership) OnSuccess() error {
return spooler.HandleSuccess(m.view.UpdateUserMembershipSpoolerRunTimestamp)
}

View File

@ -48,6 +48,10 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
es_model.HumanExternalLoginCheckSucceeded, es_model.HumanExternalLoginCheckSucceeded,
es_model.HumanMFAOTPCheckSucceeded, es_model.HumanMFAOTPCheckSucceeded,
es_model.HumanMFAOTPCheckFailed, es_model.HumanMFAOTPCheckFailed,
es_model.HumanMFAU2FTokenCheckSucceeded,
es_model.HumanMFAU2FTokenCheckFailed,
es_model.HumanPasswordlessTokenCheckSucceeded,
es_model.HumanPasswordlessTokenCheckFailed,
es_model.HumanSignedOut: es_model.HumanSignedOut:
eventData, err := view_model.UserSessionFromEvent(event) eventData, err := view_model.UserSessionFromEvent(event)
if err != nil { if err != nil {
@ -78,13 +82,15 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
es_model.DomainClaimed, es_model.DomainClaimed,
es_model.UserUserNameChanged, es_model.UserUserNameChanged,
es_model.HumanExternalIDPRemoved, es_model.HumanExternalIDPRemoved,
es_model.HumanExternalIDPCascadeRemoved: es_model.HumanExternalIDPCascadeRemoved,
es_model.HumanPasswordlessTokenRemoved,
es_model.HumanMFAU2FTokenRemoved:
sessions, err := u.view.UserSessionsByUserID(event.AggregateID) sessions, err := u.view.UserSessionsByUserID(event.AggregateID)
if err != nil { if err != nil {
return err return err
} }
if len(sessions) == 0 { if len(sessions) == 0 {
return u.view.ProcessedUserSessionSequence(event.Sequence) return u.view.ProcessedUserSessionSequence(event.Sequence, event.CreationDate)
} }
for _, session := range sessions { for _, session := range sessions {
session.AppendEvent(event) session.AppendEvent(event)
@ -92,11 +98,11 @@ func (u *UserSession) Reduce(event *models.Event) (err error) {
return err return err
} }
} }
return u.view.PutUserSessions(sessions, event.Sequence) return u.view.PutUserSessions(sessions, event.Sequence, event.CreationDate)
case es_model.UserRemoved: case es_model.UserRemoved:
return u.view.DeleteUserSessions(event.AggregateID, event.Sequence) return u.view.DeleteUserSessions(event.AggregateID, event.Sequence, event.CreationDate)
default: default:
return u.view.ProcessedUserSessionSequence(event.Sequence) return u.view.ProcessedUserSessionSequence(event.Sequence, event.CreationDate)
} }
} }
@ -105,12 +111,16 @@ 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) return spooler.HandleError(event, err, u.view.GetLatestUserSessionFailedEvent, u.view.ProcessedUserSessionFailedEvent, u.view.ProcessedUserSessionSequence, u.errorCountUntilSkip)
} }
func (u *UserSession) OnSuccess() error {
return spooler.HandleSuccess(u.view.UpdateUserSessionSpoolerRunTimestamp)
}
func (u *UserSession) updateSession(session *view_model.UserSessionView, event *models.Event) error { func (u *UserSession) updateSession(session *view_model.UserSessionView, event *models.Event) error {
session.AppendEvent(event) session.AppendEvent(event)
if err := u.fillUserInfo(session, event.AggregateID); err != nil { if err := u.fillUserInfo(session, event.AggregateID); err != nil {
return err return err
} }
return u.view.PutUserSession(session) return u.view.PutUserSession(session, event.CreationDate)
} }
func (u *UserSession) fillUserInfo(session *view_model.UserSessionView, id string) error { func (u *UserSession) fillUserInfo(session *view_model.UserSessionView, id string) error {

Some files were not shown because too many files have changed in this diff Show More