diff --git a/docs/specs/event.md b/docs/specs/event.md index baaffa2be7..34f5e63243 100644 --- a/docs/specs/event.md +++ b/docs/specs/event.md @@ -181,6 +181,7 @@ Use this event to add custom fields to the JWT access token. { "payload": { "user": { /* ... */ }, + "identities": [ ], "jwt": { "payload": { "iss": "issuer", @@ -192,6 +193,8 @@ Use this event to add custom fields to the JWT access token. } ``` +- `identities`: This contain all Login ID identities, OAuth identities, or LDAP identities that the user has. + ### Non-blocking Events - [user.created](#usercreated) diff --git a/pkg/admin/wire_gen.go b/pkg/admin/wire_gen.go index 753c6b56f9..2853fe6861 100644 --- a/pkg/admin/wire_gen.go +++ b/pkg/admin/wire_gen.go @@ -1098,6 +1098,7 @@ func newGraphQLHandler(p *deps.RequestProvider) http.Handler { IDTokenIssuer: idTokenIssuer, BaseURL: endpointsEndpoints, Events: eventService, + Identities: facadeIdentityFacade, } tokenGenerator := _wireTokenGeneratorValue oauthAccessTokenEncoding := oauth2.AccessTokenEncoding{ @@ -1106,6 +1107,7 @@ func newGraphQLHandler(p *deps.RequestProvider) http.Handler { IDTokenIssuer: idTokenIssuer, BaseURL: endpointsEndpoints, Events: eventService, + Identities: facadeIdentityFacade, } accessGrantService := oauth2.AccessGrantService{ AppID: appID, diff --git a/pkg/api/event/blocking/oidc_jwt_pre_create.go b/pkg/api/event/blocking/oidc_jwt_pre_create.go index 377e042596..e7cc5ab843 100644 --- a/pkg/api/event/blocking/oidc_jwt_pre_create.go +++ b/pkg/api/event/blocking/oidc_jwt_pre_create.go @@ -14,9 +14,10 @@ type OIDCJWT struct { } type OIDCJWTPreCreateBlockingEventPayload struct { - UserRef model.UserRef `json:"-" resolve:"user"` - UserModel model.User `json:"user"` - JWT OIDCJWT `json:"jwt"` + UserRef model.UserRef `json:"-" resolve:"user"` + UserModel model.User `json:"user"` + Identities []model.Identity `json:"identities"` + JWT OIDCJWT `json:"jwt"` } func (e *OIDCJWTPreCreateBlockingEventPayload) BlockingEventType() event.Type { diff --git a/pkg/auth/wire_gen.go b/pkg/auth/wire_gen.go index 5dc8341484..791ed131de 100644 --- a/pkg/auth/wire_gen.go +++ b/pkg/auth/wire_gen.go @@ -753,12 +753,155 @@ func newOAuthAuthorizeHandler(p *deps.RequestProvider) http.Handler { Database: handle, } eventService := event.NewService(contextContext, appID, remoteIP, userAgentString, eventLogger, handle, clock, localizationConfig, storeImpl, resolverImpl, sink, auditSink, elasticsearchSink) + storeDeviceTokenRedis := &mfa.StoreDeviceTokenRedis{ + Redis: appredisHandle, + AppID: appID, + Clock: clock, + } + storeRecoveryCodePQ := &mfa.StoreRecoveryCodePQ{ + SQLBuilder: sqlBuilderApp, + SQLExecutor: sqlExecutor, + } + mfaLockout := mfa.Lockout{ + Config: authenticationLockoutConfig, + RemoteIP: remoteIP, + Provider: lockoutService, + } + mfaService := &mfa.Service{ + IP: remoteIP, + DeviceTokens: storeDeviceTokenRedis, + RecoveryCodes: storeRecoveryCodePQ, + Clock: clock, + Config: authenticationConfig, + RateLimiter: limiter, + Lockout: mfaLockout, + } + messagingLogger := messaging.NewLogger(factory) + usageLogger := usage.NewLogger(factory) + usageLimiter := &usage.Limiter{ + Logger: usageLogger, + Clock: clock, + AppID: appID, + Redis: appredisHandle, + } + messagingConfig := appConfig.Messaging + messagingRateLimitsConfig := messagingConfig.RateLimits + messagingFeatureConfig := featureConfig.Messaging + rateLimitsEnvironmentConfig := &environmentConfig.RateLimits + limits := messaging.Limits{ + Logger: messagingLogger, + RateLimiter: limiter, + UsageLimiter: usageLimiter, + RemoteIP: remoteIP, + Config: messagingRateLimitsConfig, + FeatureConfig: messagingFeatureConfig, + EnvConfig: rateLimitsEnvironmentConfig, + } + serviceLogger := whatsapp.NewServiceLogger(factory) + devMode := environmentConfig.DevMode + featureTestModeWhatsappSuppressed := deps.ProvideTestModeWhatsappSuppressed(testModeFeatureConfig) + testModeWhatsappConfig := testModeConfig.Whatsapp + whatsappConfig := messagingConfig.Whatsapp + whatsappOnPremisesCredentials := deps.ProvideWhatsappOnPremisesCredentials(secretConfig) + tokenStore := &whatsapp.TokenStore{ + Redis: appredisHandle, + AppID: appID, + Clock: clock, + } + onPremisesClient := whatsapp.NewWhatsappOnPremisesClient(whatsappConfig, whatsappOnPremisesCredentials, tokenStore) + whatsappService := &whatsapp.Service{ + Context: contextContext, + Logger: serviceLogger, + DevMode: devMode, + FeatureTestModeWhatsappSuppressed: featureTestModeWhatsappSuppressed, + TestModeWhatsappConfig: testModeWhatsappConfig, + WhatsappConfig: whatsappConfig, + LocalizationConfig: localizationConfig, + OnPremisesClient: onPremisesClient, + TokenStore: tokenStore, + } + sender := &messaging.Sender{ + Limits: limits, + TaskQueue: queue, + Events: eventService, + Whatsapp: whatsappService, + MessagingFeatureConfig: messagingFeatureConfig, + } + forgotpasswordSender := &forgotpassword.Sender{ + AppConfg: appConfig, + Identities: serviceService, + Sender: sender, + Translation: translationService, + } + rawCommands := &user.RawCommands{ + Store: store, + Clock: clock, + } + userCommands := &user.Commands{ + RawCommands: rawCommands, + RawQueries: rawQueries, + Events: eventService, + Verification: verificationService, + UserProfileConfig: userProfileConfig, + StandardAttributes: serviceNoEvent, + CustomAttributes: customattrsServiceNoEvent, + Web3: web3Service, + RolesAndGroups: queries, + } + stdattrsService := &stdattrs2.Service{ + UserProfileConfig: userProfileConfig, + ServiceNoEvent: serviceNoEvent, + Identities: serviceService, + UserQueries: rawQueries, + UserStore: store, + Events: eventService, + } + cookieDef := session.NewSessionCookieDef(sessionConfig) + idpsessionManager := &idpsession.Manager{ + Store: idpsessionStoreRedis, + Config: sessionConfig, + Cookies: cookieManager, + CookieDef: cookieDef, + } + accountAnonymizationConfig := appConfig.AccountAnonymization + passwordRand := password.NewRandSource() + generator := &password.Generator{ + Checker: passwordChecker, + Rand: passwordRand, + PasswordConfig: authenticatorPasswordConfig, + } + coordinator := &facade.Coordinator{ + Events: eventService, + Identities: serviceService, + Authenticators: service3, + Verification: verificationService, + MFA: mfaService, + SendPassword: forgotpasswordSender, + UserCommands: userCommands, + UserQueries: userQueries, + RolesGroupsCommands: commands, + StdAttrsService: stdattrsService, + PasswordHistory: historyStore, + OAuth: authorizationStore, + IDPSessions: idpsessionManager, + OAuthSessions: sessionManager, + IdentityConfig: identityConfig, + AccountDeletionConfig: accountDeletionConfig, + AccountAnonymizationConfig: accountAnonymizationConfig, + AuthenticationConfig: authenticationConfig, + Clock: clock, + PasswordGenerator: generator, + } + identityFacade := &facade.IdentityFacade{ + Coordinator: coordinator, + } accessTokenEncoding := oauth2.AccessTokenEncoding{ Secrets: oAuthKeyMaterials, Clock: clock, IDTokenIssuer: idTokenIssuer, BaseURL: endpointsEndpoints, Events: eventService, + Identities: identityFacade, } accessGrantService := &oauth2.AccessGrantService{ AppID: appID, @@ -1433,12 +1576,155 @@ func newOAuthConsentHandler(p *deps.RequestProvider) http.Handler { Database: handle, } eventService := event.NewService(contextContext, appID, remoteIP, userAgentString, eventLogger, handle, clockClock, localizationConfig, storeImpl, resolverImpl, sink, auditSink, elasticsearchSink) + storeDeviceTokenRedis := &mfa.StoreDeviceTokenRedis{ + Redis: appredisHandle, + AppID: appID, + Clock: clockClock, + } + storeRecoveryCodePQ := &mfa.StoreRecoveryCodePQ{ + SQLBuilder: sqlBuilderApp, + SQLExecutor: sqlExecutor, + } + mfaLockout := mfa.Lockout{ + Config: authenticationLockoutConfig, + RemoteIP: remoteIP, + Provider: lockoutService, + } + mfaService := &mfa.Service{ + IP: remoteIP, + DeviceTokens: storeDeviceTokenRedis, + RecoveryCodes: storeRecoveryCodePQ, + Clock: clockClock, + Config: authenticationConfig, + RateLimiter: limiter, + Lockout: mfaLockout, + } + messagingLogger := messaging.NewLogger(factory) + usageLogger := usage.NewLogger(factory) + usageLimiter := &usage.Limiter{ + Logger: usageLogger, + Clock: clockClock, + AppID: appID, + Redis: appredisHandle, + } + messagingConfig := appConfig.Messaging + messagingRateLimitsConfig := messagingConfig.RateLimits + messagingFeatureConfig := featureConfig.Messaging + rateLimitsEnvironmentConfig := &environmentConfig.RateLimits + limits := messaging.Limits{ + Logger: messagingLogger, + RateLimiter: limiter, + UsageLimiter: usageLimiter, + RemoteIP: remoteIP, + Config: messagingRateLimitsConfig, + FeatureConfig: messagingFeatureConfig, + EnvConfig: rateLimitsEnvironmentConfig, + } + serviceLogger := whatsapp.NewServiceLogger(factory) + devMode := environmentConfig.DevMode + featureTestModeWhatsappSuppressed := deps.ProvideTestModeWhatsappSuppressed(testModeFeatureConfig) + testModeWhatsappConfig := testModeConfig.Whatsapp + whatsappConfig := messagingConfig.Whatsapp + whatsappOnPremisesCredentials := deps.ProvideWhatsappOnPremisesCredentials(secretConfig) + tokenStore := &whatsapp.TokenStore{ + Redis: appredisHandle, + AppID: appID, + Clock: clockClock, + } + onPremisesClient := whatsapp.NewWhatsappOnPremisesClient(whatsappConfig, whatsappOnPremisesCredentials, tokenStore) + whatsappService := &whatsapp.Service{ + Context: contextContext, + Logger: serviceLogger, + DevMode: devMode, + FeatureTestModeWhatsappSuppressed: featureTestModeWhatsappSuppressed, + TestModeWhatsappConfig: testModeWhatsappConfig, + WhatsappConfig: whatsappConfig, + LocalizationConfig: localizationConfig, + OnPremisesClient: onPremisesClient, + TokenStore: tokenStore, + } + sender := &messaging.Sender{ + Limits: limits, + TaskQueue: queue, + Events: eventService, + Whatsapp: whatsappService, + MessagingFeatureConfig: messagingFeatureConfig, + } + forgotpasswordSender := &forgotpassword.Sender{ + AppConfg: appConfig, + Identities: serviceService, + Sender: sender, + Translation: translationService, + } + rawCommands := &user.RawCommands{ + Store: store, + Clock: clockClock, + } + userCommands := &user.Commands{ + RawCommands: rawCommands, + RawQueries: rawQueries, + Events: eventService, + Verification: verificationService, + UserProfileConfig: userProfileConfig, + StandardAttributes: serviceNoEvent, + CustomAttributes: customattrsServiceNoEvent, + Web3: web3Service, + RolesAndGroups: queries, + } + stdattrsService := &stdattrs2.Service{ + UserProfileConfig: userProfileConfig, + ServiceNoEvent: serviceNoEvent, + Identities: serviceService, + UserQueries: rawQueries, + UserStore: store, + Events: eventService, + } + cookieDef := session.NewSessionCookieDef(sessionConfig) + idpsessionManager := &idpsession.Manager{ + Store: idpsessionStoreRedis, + Config: sessionConfig, + Cookies: cookieManager, + CookieDef: cookieDef, + } + accountAnonymizationConfig := appConfig.AccountAnonymization + passwordRand := password.NewRandSource() + generator := &password.Generator{ + Checker: passwordChecker, + Rand: passwordRand, + PasswordConfig: authenticatorPasswordConfig, + } + coordinator := &facade.Coordinator{ + Events: eventService, + Identities: serviceService, + Authenticators: service3, + Verification: verificationService, + MFA: mfaService, + SendPassword: forgotpasswordSender, + UserCommands: userCommands, + UserQueries: userQueries, + RolesGroupsCommands: commands, + StdAttrsService: stdattrsService, + PasswordHistory: historyStore, + OAuth: authorizationStore, + IDPSessions: idpsessionManager, + OAuthSessions: sessionManager, + IdentityConfig: identityConfig, + AccountDeletionConfig: accountDeletionConfig, + AccountAnonymizationConfig: accountAnonymizationConfig, + AuthenticationConfig: authenticationConfig, + Clock: clockClock, + PasswordGenerator: generator, + } + identityFacade := &facade.IdentityFacade{ + Coordinator: coordinator, + } accessTokenEncoding := oauth2.AccessTokenEncoding{ Secrets: oAuthKeyMaterials, Clock: clockClock, IDTokenIssuer: idTokenIssuer, BaseURL: endpointsEndpoints, Events: eventService, + Identities: identityFacade, } accessGrantService := &oauth2.AccessGrantService{ AppID: appID, @@ -2094,26 +2380,6 @@ func newOAuthTokenHandler(p *deps.RequestProvider) http.Handler { Database: handle, } eventService := event.NewService(contextContext, appID, remoteIP, userAgentString, eventLogger, handle, clockClock, localizationConfig, storeImpl, resolverImpl, sink, auditSink, elasticsearchSink) - accessTokenEncoding := oauth2.AccessTokenEncoding{ - Secrets: oAuthKeyMaterials, - Clock: clockClock, - IDTokenIssuer: idTokenIssuer, - BaseURL: endpointsEndpoints, - Events: eventService, - } - accessGrantService := &oauth2.AccessGrantService{ - AppID: appID, - AccessGrants: store, - AccessTokenIssuer: accessTokenEncoding, - Clock: clockClock, - } - preAuthenticatedURLTokenServiceImpl := &handler.PreAuthenticatedURLTokenServiceImpl{ - Clock: clockClock, - PreAuthenticatedURLTokens: store, - AccessGrantService: accessGrantService, - OfflineGrantService: oauthOfflineGrantService, - } - interactionLogger := interaction.NewLogger(factory) storeDeviceTokenRedis := &mfa.StoreDeviceTokenRedis{ Redis: appredisHandle, AppID: appID, @@ -2256,7 +2522,31 @@ func newOAuthTokenHandler(p *deps.RequestProvider) http.Handler { Clock: clockClock, PasswordGenerator: generator, } - identityFacade := facade.IdentityFacade{ + identityFacade := &facade.IdentityFacade{ + Coordinator: coordinator, + } + accessTokenEncoding := oauth2.AccessTokenEncoding{ + Secrets: oAuthKeyMaterials, + Clock: clockClock, + IDTokenIssuer: idTokenIssuer, + BaseURL: endpointsEndpoints, + Events: eventService, + Identities: identityFacade, + } + accessGrantService := &oauth2.AccessGrantService{ + AppID: appID, + AccessGrants: store, + AccessTokenIssuer: accessTokenEncoding, + Clock: clockClock, + } + preAuthenticatedURLTokenServiceImpl := &handler.PreAuthenticatedURLTokenServiceImpl{ + Clock: clockClock, + PreAuthenticatedURLTokens: store, + AccessGrantService: accessGrantService, + OfflineGrantService: oauthOfflineGrantService, + } + interactionLogger := interaction.NewLogger(factory) + facadeIdentityFacade := facade.IdentityFacade{ Coordinator: coordinator, } authenticatorFacade := facade.AuthenticatorFacade{ @@ -2355,7 +2645,7 @@ func newOAuthTokenHandler(p *deps.RequestProvider) http.Handler { FeatureConfig: featureConfig, OAuthClientResolver: resolver, OfflineGrants: store, - Identities: identityFacade, + Identities: facadeIdentityFacade, Authenticators: authenticatorFacade, AnonymousIdentities: anonymousProvider, AnonymousUserPromotionCodeStore: anonymousStoreRedis, @@ -2400,6 +2690,7 @@ func newOAuthTokenHandler(p *deps.RequestProvider) http.Handler { IDTokenIssuer: idTokenIssuer, BaseURL: endpointsEndpoints, Events: eventService, + Identities: identityFacade, } tokenGenerator := _wireTokenGeneratorValue oauthAccessGrantService := oauth2.AccessGrantService{ @@ -5060,26 +5351,6 @@ func newOAuthAppSessionTokenHandler(p *deps.RequestProvider) http.Handler { Database: handle, } eventService := event.NewService(contextContext, appID, remoteIP, userAgentString, eventLogger, handle, clockClock, localizationConfig, storeImpl, resolverImpl, sink, auditSink, elasticsearchSink) - accessTokenEncoding := oauth2.AccessTokenEncoding{ - Secrets: oAuthKeyMaterials, - Clock: clockClock, - IDTokenIssuer: idTokenIssuer, - BaseURL: endpointsEndpoints, - Events: eventService, - } - accessGrantService := &oauth2.AccessGrantService{ - AppID: appID, - AccessGrants: store, - AccessTokenIssuer: accessTokenEncoding, - Clock: clockClock, - } - preAuthenticatedURLTokenServiceImpl := &handler.PreAuthenticatedURLTokenServiceImpl{ - Clock: clockClock, - PreAuthenticatedURLTokens: store, - AccessGrantService: accessGrantService, - OfflineGrantService: oauthOfflineGrantService, - } - interactionLogger := interaction.NewLogger(factory) storeDeviceTokenRedis := &mfa.StoreDeviceTokenRedis{ Redis: appredisHandle, AppID: appID, @@ -5222,7 +5493,31 @@ func newOAuthAppSessionTokenHandler(p *deps.RequestProvider) http.Handler { Clock: clockClock, PasswordGenerator: generator, } - identityFacade := facade.IdentityFacade{ + identityFacade := &facade.IdentityFacade{ + Coordinator: coordinator, + } + accessTokenEncoding := oauth2.AccessTokenEncoding{ + Secrets: oAuthKeyMaterials, + Clock: clockClock, + IDTokenIssuer: idTokenIssuer, + BaseURL: endpointsEndpoints, + Events: eventService, + Identities: identityFacade, + } + accessGrantService := &oauth2.AccessGrantService{ + AppID: appID, + AccessGrants: store, + AccessTokenIssuer: accessTokenEncoding, + Clock: clockClock, + } + preAuthenticatedURLTokenServiceImpl := &handler.PreAuthenticatedURLTokenServiceImpl{ + Clock: clockClock, + PreAuthenticatedURLTokens: store, + AccessGrantService: accessGrantService, + OfflineGrantService: oauthOfflineGrantService, + } + interactionLogger := interaction.NewLogger(factory) + facadeIdentityFacade := facade.IdentityFacade{ Coordinator: coordinator, } authenticatorFacade := facade.AuthenticatorFacade{ @@ -5321,7 +5616,7 @@ func newOAuthAppSessionTokenHandler(p *deps.RequestProvider) http.Handler { FeatureConfig: featureConfig, OAuthClientResolver: resolver, OfflineGrants: store, - Identities: identityFacade, + Identities: facadeIdentityFacade, Authenticators: authenticatorFacade, AnonymousIdentities: anonymousProvider, AnonymousUserPromotionCodeStore: anonymousStoreRedis, @@ -5366,6 +5661,7 @@ func newOAuthAppSessionTokenHandler(p *deps.RequestProvider) http.Handler { IDTokenIssuer: idTokenIssuer, BaseURL: endpointsEndpoints, Events: eventService, + Identities: identityFacade, } tokenGenerator := _wireTokenGeneratorValue oauthAccessGrantService := oauth2.AccessGrantService{ @@ -6393,12 +6689,16 @@ func newAPIAnonymousUserSignupHandler(p *deps.RequestProvider) http.Handler { RolesAndGroups: queries, Clock: clockClock, } + facadeIdentityFacade := &facade.IdentityFacade{ + Coordinator: coordinator, + } accessTokenEncoding := &oauth2.AccessTokenEncoding{ Secrets: oAuthKeyMaterials, Clock: clockClock, IDTokenIssuer: idTokenIssuer, BaseURL: endpointsEndpoints, Events: eventService, + Identities: facadeIdentityFacade, } tokenGenerator := _wireTokenGeneratorValue oauthAccessTokenEncoding := oauth2.AccessTokenEncoding{ @@ -6407,6 +6707,7 @@ func newAPIAnonymousUserSignupHandler(p *deps.RequestProvider) http.Handler { IDTokenIssuer: idTokenIssuer, BaseURL: endpointsEndpoints, Events: eventService, + Identities: facadeIdentityFacade, } accessGrantService := oauth2.AccessGrantService{ AppID: appID, @@ -7299,12 +7600,16 @@ func newAPIAnonymousUserPromotionCodeHandler(p *deps.RequestProvider) http.Handl RolesAndGroups: queries, Clock: clockClock, } + facadeIdentityFacade := &facade.IdentityFacade{ + Coordinator: coordinator, + } accessTokenEncoding := &oauth2.AccessTokenEncoding{ Secrets: oAuthKeyMaterials, Clock: clockClock, IDTokenIssuer: idTokenIssuer, BaseURL: endpointsEndpoints, Events: eventService, + Identities: facadeIdentityFacade, } tokenGenerator := _wireTokenGeneratorValue oauthAccessTokenEncoding := oauth2.AccessTokenEncoding{ @@ -7313,6 +7618,7 @@ func newAPIAnonymousUserPromotionCodeHandler(p *deps.RequestProvider) http.Handl IDTokenIssuer: idTokenIssuer, BaseURL: endpointsEndpoints, Events: eventService, + Identities: facadeIdentityFacade, } accessGrantService := oauth2.AccessGrantService{ AppID: appID, @@ -69687,12 +69993,16 @@ func newWebAppTesterHandler(p *deps.RequestProvider) http.Handler { RolesAndGroups: queries, Clock: clockClock, } + facadeIdentityFacade := &facade.IdentityFacade{ + Coordinator: coordinator, + } accessTokenEncoding := oauth2.AccessTokenEncoding{ Secrets: oAuthKeyMaterials, Clock: clockClock, IDTokenIssuer: idTokenIssuer, BaseURL: endpointsEndpoints, Events: eventService, + Identities: facadeIdentityFacade, } accessGrantService := &oauth2.AccessGrantService{ AppID: appID, @@ -69712,6 +70022,7 @@ func newWebAppTesterHandler(p *deps.RequestProvider) http.Handler { IDTokenIssuer: idTokenIssuer, BaseURL: endpointsEndpoints, Events: eventService, + Identities: facadeIdentityFacade, } tokenGenerator := _wireTokenGeneratorValue oauthAccessGrantService := oauth2.AccessGrantService{ @@ -133888,12 +134199,114 @@ func newSessionMiddleware(p *deps.RequestProvider) httproute.Middleware { Database: appdbHandle, } eventService := event.NewService(contextContext, appID, remoteIP, userAgentString, eventLogger, appdbHandle, clockClock, localizationConfig, storeImpl, resolverImpl, sink, auditSink, elasticsearchSink) - accessTokenEncoding := &oauth2.AccessTokenEncoding{ - Secrets: oAuthKeyMaterials, + storeDeviceTokenRedis := &mfa.StoreDeviceTokenRedis{ + Redis: handle, + AppID: appID, + Clock: clockClock, + } + storeRecoveryCodePQ := &mfa.StoreRecoveryCodePQ{ + SQLBuilder: sqlBuilderApp, + SQLExecutor: sqlExecutor, + } + mfaLockout := mfa.Lockout{ + Config: authenticationLockoutConfig, + RemoteIP: remoteIP, + Provider: lockoutService, + } + mfaService := &mfa.Service{ + IP: remoteIP, + DeviceTokens: storeDeviceTokenRedis, + RecoveryCodes: storeRecoveryCodePQ, Clock: clockClock, - IDTokenIssuer: idTokenIssuer, - BaseURL: endpointsEndpoints, - Events: eventService, + Config: authenticationConfig, + RateLimiter: limiter, + Lockout: mfaLockout, + } + messagingLogger := messaging.NewLogger(factory) + usageLogger := usage.NewLogger(factory) + usageLimiter := &usage.Limiter{ + Logger: usageLogger, + Clock: clockClock, + AppID: appID, + Redis: handle, + } + messagingConfig := appConfig.Messaging + messagingRateLimitsConfig := messagingConfig.RateLimits + messagingFeatureConfig := featureConfig.Messaging + rateLimitsEnvironmentConfig := &environmentConfig.RateLimits + limits := messaging.Limits{ + Logger: messagingLogger, + RateLimiter: limiter, + UsageLimiter: usageLimiter, + RemoteIP: remoteIP, + Config: messagingRateLimitsConfig, + FeatureConfig: messagingFeatureConfig, + EnvConfig: rateLimitsEnvironmentConfig, + } + serviceLogger := whatsapp.NewServiceLogger(factory) + devMode := environmentConfig.DevMode + featureTestModeWhatsappSuppressed := deps.ProvideTestModeWhatsappSuppressed(testModeFeatureConfig) + testModeWhatsappConfig := testModeConfig.Whatsapp + whatsappConfig := messagingConfig.Whatsapp + whatsappOnPremisesCredentials := deps.ProvideWhatsappOnPremisesCredentials(secretConfig) + tokenStore := &whatsapp.TokenStore{ + Redis: handle, + AppID: appID, + Clock: clockClock, + } + onPremisesClient := whatsapp.NewWhatsappOnPremisesClient(whatsappConfig, whatsappOnPremisesCredentials, tokenStore) + whatsappService := &whatsapp.Service{ + Context: contextContext, + Logger: serviceLogger, + DevMode: devMode, + FeatureTestModeWhatsappSuppressed: featureTestModeWhatsappSuppressed, + TestModeWhatsappConfig: testModeWhatsappConfig, + WhatsappConfig: whatsappConfig, + LocalizationConfig: localizationConfig, + OnPremisesClient: onPremisesClient, + TokenStore: tokenStore, + } + sender := &messaging.Sender{ + Limits: limits, + TaskQueue: queue, + Events: eventService, + Whatsapp: whatsappService, + MessagingFeatureConfig: messagingFeatureConfig, + } + forgotpasswordSender := &forgotpassword.Sender{ + AppConfg: appConfig, + Identities: serviceService, + Sender: sender, + Translation: translationService, + } + rawCommands := &user.RawCommands{ + Store: userStore, + Clock: clockClock, + } + userCommands := &user.Commands{ + RawCommands: rawCommands, + RawQueries: rawQueries, + Events: eventService, + Verification: verificationService, + UserProfileConfig: userProfileConfig, + StandardAttributes: serviceNoEvent, + CustomAttributes: customattrsServiceNoEvent, + Web3: web3Service, + RolesAndGroups: queries, + } + stdattrsService := &stdattrs2.Service{ + UserProfileConfig: userProfileConfig, + ServiceNoEvent: serviceNoEvent, + Identities: serviceService, + UserQueries: rawQueries, + UserStore: userStore, + Events: eventService, + } + idpsessionManager := &idpsession.Manager{ + Store: storeRedis, + Config: sessionConfig, + Cookies: cookieManager, + CookieDef: cookieDef, } oauthclientResolver := &oauthclient.Resolver{ OAuthConfig: oAuthConfig, @@ -133906,6 +134319,52 @@ func newSessionMiddleware(p *deps.RequestProvider) httproute.Middleware { ClientResolver: oauthclientResolver, OfflineGrants: store, } + sessionManager := &oauth2.SessionManager{ + Store: store, + Config: oAuthConfig, + Service: offlineGrantService, + } + accountDeletionConfig := appConfig.AccountDeletion + accountAnonymizationConfig := appConfig.AccountAnonymization + passwordRand := password.NewRandSource() + generator := &password.Generator{ + Checker: passwordChecker, + Rand: passwordRand, + PasswordConfig: authenticatorPasswordConfig, + } + coordinator := &facade.Coordinator{ + Events: eventService, + Identities: serviceService, + Authenticators: service3, + Verification: verificationService, + MFA: mfaService, + SendPassword: forgotpasswordSender, + UserCommands: userCommands, + UserQueries: userQueries, + RolesGroupsCommands: commands, + StdAttrsService: stdattrsService, + PasswordHistory: historyStore, + OAuth: authorizationStore, + IDPSessions: idpsessionManager, + OAuthSessions: sessionManager, + IdentityConfig: identityConfig, + AccountDeletionConfig: accountDeletionConfig, + AccountAnonymizationConfig: accountAnonymizationConfig, + AuthenticationConfig: authenticationConfig, + Clock: clockClock, + PasswordGenerator: generator, + } + identityFacade := &facade.IdentityFacade{ + Coordinator: coordinator, + } + accessTokenEncoding := &oauth2.AccessTokenEncoding{ + Secrets: oAuthKeyMaterials, + Clock: clockClock, + IDTokenIssuer: idTokenIssuer, + BaseURL: endpointsEndpoints, + Events: eventService, + Identities: identityFacade, + } oauthResolver := &oauth2.Resolver{ RemoteIP: remoteIP, UserAgentString: userAgentString, diff --git a/pkg/lib/authn/identity/service/service.go b/pkg/lib/authn/identity/service/service.go index e7d46eb815..317930e7b9 100644 --- a/pkg/lib/authn/identity/service/service.go +++ b/pkg/lib/authn/identity/service/service.go @@ -550,6 +550,76 @@ func (s *Service) ListByUser(userID string) ([]*identity.Info, error) { } +func (s *Service) ListIdentitiesThatHaveStandardAttributes(userID string) ([]*identity.Info, error) { + userIDs := []string{userID} + + extractIDs := func(idRefs []*model.IdentityRef) []string { + ids := []string{} + for _, idRef := range idRefs { + ids = append(ids, idRef.ID) + } + return ids + } + + infos := []*identity.Info{} + + { + typeLoginID := model.IdentityTypeLoginID + loginIDRefs, err := s.Store.ListRefsByUsers(userIDs, &typeLoginID) + if err != nil { + return nil, err + } + + if len(loginIDRefs) > 0 { + loginIDs, err := s.LoginID.GetMany(extractIDs(loginIDRefs)) + if err != nil { + return nil, err + } + for _, i := range loginIDs { + infos = append(infos, i.ToInfo()) + } + } + } + + { + typeOAuth := model.IdentityTypeOAuth + oauthRefs, err := s.Store.ListRefsByUsers(userIDs, &typeOAuth) + if err != nil { + return nil, err + } + + if len(oauthRefs) > 0 { + oauths, err := s.OAuth.GetMany(extractIDs(oauthRefs)) + if err != nil { + return nil, err + } + for _, i := range oauths { + infos = append(infos, i.ToInfo()) + } + } + } + + { + typeLDAP := model.IdentityTypeLDAP + ldapRefs, err := s.Store.ListRefsByUsers(userIDs, &typeLDAP) + if err != nil { + return nil, err + } + + if len(ldapRefs) > 0 { + ldaps, err := s.LDAP.GetMany(extractIDs(ldapRefs)) + if err != nil { + return nil, err + } + for _, i := range ldaps { + infos = append(infos, i.ToInfo()) + } + } + } + + return infos, nil +} + func (s *Service) Count(userID string) (uint64, error) { return s.Store.Count(userID) } diff --git a/pkg/lib/deps/deps_common.go b/pkg/lib/deps/deps_common.go index 270eb616d6..d93b166789 100644 --- a/pkg/lib/deps/deps_common.go +++ b/pkg/lib/deps/deps_common.go @@ -300,6 +300,7 @@ var CommonDependencySet = wire.NewSet( wire.Bind(new(userimport.IdentityService), new(*facade.IdentityFacade)), wire.Bind(new(userimport.AuthenticatorService), new(*facade.AuthenticatorFacade)), wire.Bind(new(accountmanagement.IdentityService), new(*facade.IdentityFacade)), + wire.Bind(new(oauth.AccessTokenEncodingIdentityService), new(*facade.IdentityFacade)), ), wire.NewSet( diff --git a/pkg/lib/facade/coordinator.go b/pkg/lib/facade/coordinator.go index 7be7547db5..6577ac0f67 100644 --- a/pkg/lib/facade/coordinator.go +++ b/pkg/lib/facade/coordinator.go @@ -39,6 +39,7 @@ type IdentityService interface { Get(id string) (*identity.Info, error) SearchBySpec(spec *identity.Spec) (exactMatch *identity.Info, otherMatches []*identity.Info, err error) ListByUser(userID string) ([]*identity.Info, error) + ListIdentitiesThatHaveStandardAttributes(userID string) ([]*identity.Info, error) ListByClaim(name string, value string) ([]*identity.Info, error) ListRefsByUsers(userIDs []string, identityType *model.IdentityType) ([]*model.IdentityRef, error) New(userID string, spec *identity.Spec, options identity.NewIdentityOptions) (*identity.Info, error) @@ -187,6 +188,10 @@ func (c *Coordinator) IdentityListByUser(userID string) ([]*identity.Info, error return c.Identities.ListByUser(userID) } +func (c *Coordinator) IdentityListIdentitiesThatHaveStandardAttributes(userID string) ([]*identity.Info, error) { + return c.Identities.ListIdentitiesThatHaveStandardAttributes(userID) +} + func (c *Coordinator) IdentityListByClaim(name string, value string) ([]*identity.Info, error) { return c.Identities.ListByClaim(name, value) } diff --git a/pkg/lib/facade/identity.go b/pkg/lib/facade/identity.go index 5c1c9e4935..6996be1f5d 100644 --- a/pkg/lib/facade/identity.go +++ b/pkg/lib/facade/identity.go @@ -22,6 +22,10 @@ func (i IdentityFacade) ListByUser(userID string) ([]*identity.Info, error) { return i.Coordinator.IdentityListByUser(userID) } +func (i IdentityFacade) ListIdentitiesThatHaveStandardAttributes(userID string) ([]*identity.Info, error) { + return i.Coordinator.IdentityListIdentitiesThatHaveStandardAttributes(userID) +} + func (i IdentityFacade) ListByClaim(name string, value string) ([]*identity.Info, error) { return i.Coordinator.IdentityListByClaim(name, value) } diff --git a/pkg/lib/oauth/token_encoding.go b/pkg/lib/oauth/token_encoding.go index d5b03cbc66..5bd46c5c31 100644 --- a/pkg/lib/oauth/token_encoding.go +++ b/pkg/lib/oauth/token_encoding.go @@ -15,6 +15,7 @@ import ( "github.com/authgear/authgear-server/pkg/api/event" "github.com/authgear/authgear-server/pkg/api/event/blocking" "github.com/authgear/authgear-server/pkg/api/model" + "github.com/authgear/authgear-server/pkg/lib/authn/identity" "github.com/authgear/authgear-server/pkg/lib/config" "github.com/authgear/authgear-server/pkg/util/clock" "github.com/authgear/authgear-server/pkg/util/jwtutil" @@ -35,12 +36,17 @@ type EventService interface { DispatchEventOnCommit(payload event.Payload) error } +type AccessTokenEncodingIdentityService interface { + ListIdentitiesThatHaveStandardAttributes(userID string) ([]*identity.Info, error) +} + type AccessTokenEncoding struct { Secrets *config.OAuthKeyMaterials Clock clock.Clock IDTokenIssuer IDTokenIssuer BaseURL BaseURLProvider Events EventService + Identities AccessTokenEncodingIdentityService } func (e *AccessTokenEncoding) EncodeAccessToken(client *config.OAuthClientConfig, clientLike *ClientLike, grant *AccessGrant, userID string, token string) (string, error) { @@ -70,12 +76,23 @@ func (e *AccessTokenEncoding) EncodeAccessToken(client *config.OAuthClientConfig return "", err } + identities, err := e.Identities.ListIdentitiesThatHaveStandardAttributes(userID) + if err != nil { + return "", err + } + + var identityModels []model.Identity + for _, i := range identities { + identityModels = append(identityModels, i.ToModel()) + } + eventPayload := &blocking.OIDCJWTPreCreateBlockingEventPayload{ UserRef: model.UserRef{ Meta: model.Meta{ ID: userID, }, }, + Identities: identityModels, JWT: blocking.OIDCJWT{ Payload: forMutation, }, diff --git a/pkg/lib/oauth/token_encoding_mock_test.go b/pkg/lib/oauth/token_encoding_mock_test.go index fdb71edd9d..0f9c0192f2 100644 --- a/pkg/lib/oauth/token_encoding_mock_test.go +++ b/pkg/lib/oauth/token_encoding_mock_test.go @@ -9,6 +9,7 @@ import ( reflect "reflect" event "github.com/authgear/authgear-server/pkg/api/event" + identity "github.com/authgear/authgear-server/pkg/lib/authn/identity" gomock "github.com/golang/mock/gomock" jwt "github.com/lestrrat-go/jwx/v2/jwt" ) @@ -137,3 +138,41 @@ func (mr *MockEventServiceMockRecorder) DispatchEventOnCommit(payload interface{ mr.mock.ctrl.T.Helper() return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DispatchEventOnCommit", reflect.TypeOf((*MockEventService)(nil).DispatchEventOnCommit), payload) } + +// MockAccessTokenEncodingIdentityService is a mock of AccessTokenEncodingIdentityService interface. +type MockAccessTokenEncodingIdentityService struct { + ctrl *gomock.Controller + recorder *MockAccessTokenEncodingIdentityServiceMockRecorder +} + +// MockAccessTokenEncodingIdentityServiceMockRecorder is the mock recorder for MockAccessTokenEncodingIdentityService. +type MockAccessTokenEncodingIdentityServiceMockRecorder struct { + mock *MockAccessTokenEncodingIdentityService +} + +// NewMockAccessTokenEncodingIdentityService creates a new mock instance. +func NewMockAccessTokenEncodingIdentityService(ctrl *gomock.Controller) *MockAccessTokenEncodingIdentityService { + mock := &MockAccessTokenEncodingIdentityService{ctrl: ctrl} + mock.recorder = &MockAccessTokenEncodingIdentityServiceMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAccessTokenEncodingIdentityService) EXPECT() *MockAccessTokenEncodingIdentityServiceMockRecorder { + return m.recorder +} + +// ListIdentitiesThatHaveStandardAttributes mocks base method. +func (m *MockAccessTokenEncodingIdentityService) ListIdentitiesThatHaveStandardAttributes(userID string) ([]*identity.Info, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListIdentitiesThatHaveStandardAttributes", userID) + ret0, _ := ret[0].([]*identity.Info) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListIdentitiesThatHaveStandardAttributes indicates an expected call of ListIdentitiesThatHaveStandardAttributes. +func (mr *MockAccessTokenEncodingIdentityServiceMockRecorder) ListIdentitiesThatHaveStandardAttributes(userID interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListIdentitiesThatHaveStandardAttributes", reflect.TypeOf((*MockAccessTokenEncodingIdentityService)(nil).ListIdentitiesThatHaveStandardAttributes), userID) +} diff --git a/pkg/lib/oauth/token_encoding_test.go b/pkg/lib/oauth/token_encoding_test.go index 113936234d..cb977d8ddf 100644 --- a/pkg/lib/oauth/token_encoding_test.go +++ b/pkg/lib/oauth/token_encoding_test.go @@ -63,6 +63,7 @@ func TestAccessToken(t *testing.T) { mockIDTokenIssuer := NewMockIDTokenIssuer(ctrl) mockEventService := NewMockEventService(ctrl) + mockIdentityService := NewMockAccessTokenEncodingIdentityService(ctrl) encoding := &AccessTokenEncoding{ Secrets: secrets, @@ -72,7 +73,8 @@ func TestAccessToken(t *testing.T) { HTTPHost: "test1.authgear.com", HTTPProto: "http", }, - Events: mockEventService, + Events: mockEventService, + Identities: mockIdentityService, } client := &config.OAuthClientConfig{ @@ -92,6 +94,7 @@ func TestAccessToken(t *testing.T) { mockEventService.EXPECT().DispatchEventOnCommit(gomock.Any()).Return(nil) mockIDTokenIssuer.EXPECT().Iss().Return("http://test1.authgear.com") mockIDTokenIssuer.EXPECT().PopulateUserClaimsInIDToken(gomock.Any(), "user-id", clientLike).Return(nil) + mockIdentityService.EXPECT().ListIdentitiesThatHaveStandardAttributes("user-id").Return(nil, nil) accessToken, err := encoding.EncodeAccessToken(client, clientLike, accessGrant, "user-id", "token") So(err, ShouldBeNil) diff --git a/pkg/resolver/wire_gen.go b/pkg/resolver/wire_gen.go index ac25af2072..03f6e50363 100644 --- a/pkg/resolver/wire_gen.go +++ b/pkg/resolver/wire_gen.go @@ -22,6 +22,7 @@ import ( "github.com/authgear/authgear-server/pkg/lib/authn/identity/passkey" "github.com/authgear/authgear-server/pkg/lib/authn/identity/service" "github.com/authgear/authgear-server/pkg/lib/authn/identity/siwe" + "github.com/authgear/authgear-server/pkg/lib/authn/mfa" "github.com/authgear/authgear-server/pkg/lib/authn/otp" "github.com/authgear/authgear-server/pkg/lib/authn/stdattrs" "github.com/authgear/authgear-server/pkg/lib/authn/user" @@ -29,7 +30,9 @@ import ( "github.com/authgear/authgear-server/pkg/lib/elasticsearch" "github.com/authgear/authgear-server/pkg/lib/endpoints" "github.com/authgear/authgear-server/pkg/lib/event" + "github.com/authgear/authgear-server/pkg/lib/facade" "github.com/authgear/authgear-server/pkg/lib/feature/customattrs" + "github.com/authgear/authgear-server/pkg/lib/feature/forgotpassword" passkey2 "github.com/authgear/authgear-server/pkg/lib/feature/passkey" siwe2 "github.com/authgear/authgear-server/pkg/lib/feature/siwe" stdattrs2 "github.com/authgear/authgear-server/pkg/lib/feature/stdattrs" @@ -42,7 +45,9 @@ import ( "github.com/authgear/authgear-server/pkg/lib/infra/db/globaldb" "github.com/authgear/authgear-server/pkg/lib/infra/middleware" "github.com/authgear/authgear-server/pkg/lib/infra/redisqueue" + "github.com/authgear/authgear-server/pkg/lib/infra/whatsapp" "github.com/authgear/authgear-server/pkg/lib/lockout" + "github.com/authgear/authgear-server/pkg/lib/messaging" "github.com/authgear/authgear-server/pkg/lib/meter" oauth2 "github.com/authgear/authgear-server/pkg/lib/oauth" "github.com/authgear/authgear-server/pkg/lib/oauth/oidc" @@ -55,6 +60,7 @@ import ( "github.com/authgear/authgear-server/pkg/lib/session/access" "github.com/authgear/authgear-server/pkg/lib/session/idpsession" "github.com/authgear/authgear-server/pkg/lib/translation" + "github.com/authgear/authgear-server/pkg/lib/usage" "github.com/authgear/authgear-server/pkg/lib/web" "github.com/authgear/authgear-server/pkg/resolver/handler" "github.com/authgear/authgear-server/pkg/util/clock" @@ -651,12 +657,114 @@ func newSessionMiddleware(p *deps.RequestProvider) httproute.Middleware { Database: appdbHandle, } eventService := event.NewService(contextContext, appID, remoteIP, userAgentString, eventLogger, appdbHandle, clock, localizationConfig, storeImpl, resolverImpl, sink, auditSink, elasticsearchSink) - accessTokenEncoding := &oauth2.AccessTokenEncoding{ - Secrets: oAuthKeyMaterials, + storeDeviceTokenRedis := &mfa.StoreDeviceTokenRedis{ + Redis: handle, + AppID: appID, + Clock: clock, + } + storeRecoveryCodePQ := &mfa.StoreRecoveryCodePQ{ + SQLBuilder: sqlBuilderApp, + SQLExecutor: sqlExecutor, + } + mfaLockout := mfa.Lockout{ + Config: authenticationLockoutConfig, + RemoteIP: remoteIP, + Provider: lockoutService, + } + mfaService := &mfa.Service{ + IP: remoteIP, + DeviceTokens: storeDeviceTokenRedis, + RecoveryCodes: storeRecoveryCodePQ, Clock: clock, - IDTokenIssuer: idTokenIssuer, - BaseURL: endpointsEndpoints, - Events: eventService, + Config: authenticationConfig, + RateLimiter: limiter, + Lockout: mfaLockout, + } + messagingLogger := messaging.NewLogger(factory) + usageLogger := usage.NewLogger(factory) + usageLimiter := &usage.Limiter{ + Logger: usageLogger, + Clock: clock, + AppID: appID, + Redis: handle, + } + messagingConfig := appConfig.Messaging + messagingRateLimitsConfig := messagingConfig.RateLimits + messagingFeatureConfig := featureConfig.Messaging + rateLimitsEnvironmentConfig := &environmentConfig.RateLimits + limits := messaging.Limits{ + Logger: messagingLogger, + RateLimiter: limiter, + UsageLimiter: usageLimiter, + RemoteIP: remoteIP, + Config: messagingRateLimitsConfig, + FeatureConfig: messagingFeatureConfig, + EnvConfig: rateLimitsEnvironmentConfig, + } + serviceLogger := whatsapp.NewServiceLogger(factory) + devMode := environmentConfig.DevMode + featureTestModeWhatsappSuppressed := deps.ProvideTestModeWhatsappSuppressed(testModeFeatureConfig) + testModeWhatsappConfig := testModeConfig.Whatsapp + whatsappConfig := messagingConfig.Whatsapp + whatsappOnPremisesCredentials := deps.ProvideWhatsappOnPremisesCredentials(secretConfig) + tokenStore := &whatsapp.TokenStore{ + Redis: handle, + AppID: appID, + Clock: clock, + } + onPremisesClient := whatsapp.NewWhatsappOnPremisesClient(whatsappConfig, whatsappOnPremisesCredentials, tokenStore) + whatsappService := &whatsapp.Service{ + Context: contextContext, + Logger: serviceLogger, + DevMode: devMode, + FeatureTestModeWhatsappSuppressed: featureTestModeWhatsappSuppressed, + TestModeWhatsappConfig: testModeWhatsappConfig, + WhatsappConfig: whatsappConfig, + LocalizationConfig: localizationConfig, + OnPremisesClient: onPremisesClient, + TokenStore: tokenStore, + } + sender := &messaging.Sender{ + Limits: limits, + TaskQueue: queue, + Events: eventService, + Whatsapp: whatsappService, + MessagingFeatureConfig: messagingFeatureConfig, + } + forgotpasswordSender := &forgotpassword.Sender{ + AppConfg: appConfig, + Identities: serviceService, + Sender: sender, + Translation: translationService, + } + rawCommands := &user.RawCommands{ + Store: userStore, + Clock: clock, + } + userCommands := &user.Commands{ + RawCommands: rawCommands, + RawQueries: rawQueries, + Events: eventService, + Verification: verificationService, + UserProfileConfig: userProfileConfig, + StandardAttributes: serviceNoEvent, + CustomAttributes: customattrsServiceNoEvent, + Web3: web3Service, + RolesAndGroups: queries, + } + stdattrsService := &stdattrs2.Service{ + UserProfileConfig: userProfileConfig, + ServiceNoEvent: serviceNoEvent, + Identities: serviceService, + UserQueries: rawQueries, + UserStore: userStore, + Events: eventService, + } + idpsessionManager := &idpsession.Manager{ + Store: storeRedis, + Config: sessionConfig, + Cookies: cookieManager, + CookieDef: cookieDef, } oauthclientResolver := &oauthclient.Resolver{ OAuthConfig: oAuthConfig, @@ -669,6 +777,52 @@ func newSessionMiddleware(p *deps.RequestProvider) httproute.Middleware { ClientResolver: oauthclientResolver, OfflineGrants: store, } + sessionManager := &oauth2.SessionManager{ + Store: store, + Config: oAuthConfig, + Service: offlineGrantService, + } + accountDeletionConfig := appConfig.AccountDeletion + accountAnonymizationConfig := appConfig.AccountAnonymization + passwordRand := password.NewRandSource() + generator := &password.Generator{ + Checker: passwordChecker, + Rand: passwordRand, + PasswordConfig: authenticatorPasswordConfig, + } + coordinator := &facade.Coordinator{ + Events: eventService, + Identities: serviceService, + Authenticators: service3, + Verification: verificationService, + MFA: mfaService, + SendPassword: forgotpasswordSender, + UserCommands: userCommands, + UserQueries: userQueries, + RolesGroupsCommands: commands, + StdAttrsService: stdattrsService, + PasswordHistory: historyStore, + OAuth: authorizationStore, + IDPSessions: idpsessionManager, + OAuthSessions: sessionManager, + IdentityConfig: identityConfig, + AccountDeletionConfig: accountDeletionConfig, + AccountAnonymizationConfig: accountAnonymizationConfig, + AuthenticationConfig: authenticationConfig, + Clock: clock, + PasswordGenerator: generator, + } + identityFacade := &facade.IdentityFacade{ + Coordinator: coordinator, + } + accessTokenEncoding := &oauth2.AccessTokenEncoding{ + Secrets: oAuthKeyMaterials, + Clock: clock, + IDTokenIssuer: idTokenIssuer, + BaseURL: endpointsEndpoints, + Events: eventService, + Identities: identityFacade, + } oauthResolver := &oauth2.Resolver{ RemoteIP: remoteIP, UserAgentString: userAgentString,