mirror of
https://github.com/zitadel/zitadel.git
synced 2025-01-06 13:27:45 +00:00
feat: ldap provider login (#5448)
Add the logic to configure and use LDAP provider as an external IDP with a dedicated login GUI.
This commit is contained in:
parent
a8bfcc166e
commit
41ff0bbc63
2
go.mod
2
go.mod
@ -53,7 +53,7 @@ require (
|
||||
github.com/sony/sonyflake v1.1.0
|
||||
github.com/spf13/cobra v1.6.1
|
||||
github.com/spf13/viper v1.15.0
|
||||
github.com/stretchr/testify v1.8.1
|
||||
github.com/stretchr/testify v1.8.2
|
||||
github.com/superseriousbusiness/exifremove v0.0.0-20210330092427-6acd27eac203
|
||||
github.com/ttacon/libphonenumber v1.2.1
|
||||
github.com/zitadel/logging v0.3.4
|
||||
|
3
go.sum
3
go.sum
@ -1087,8 +1087,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
|
||||
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
|
@ -407,32 +407,34 @@ func updateGoogleProviderToCommand(req *admin_pb.UpdateGoogleProviderRequest) co
|
||||
|
||||
func addLDAPProviderToCommand(req *admin_pb.AddLDAPProviderRequest) command.LDAPProvider {
|
||||
return command.LDAPProvider{
|
||||
Name: req.Name,
|
||||
Host: req.Host,
|
||||
Port: req.Port,
|
||||
TLS: req.Tls,
|
||||
BaseDN: req.BaseDn,
|
||||
UserObjectClass: req.UserObjectClass,
|
||||
UserUniqueAttribute: req.UserUniqueAttribute,
|
||||
Admin: req.Admin,
|
||||
Password: req.Password,
|
||||
LDAPAttributes: idp_grpc.LDAPAttributesToCommand(req.Attributes),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
Name: req.Name,
|
||||
Servers: req.Servers,
|
||||
StartTLS: req.StartTls,
|
||||
BaseDN: req.BaseDn,
|
||||
BindDN: req.BindDn,
|
||||
BindPassword: req.BindPassword,
|
||||
UserBase: req.UserBase,
|
||||
UserObjectClasses: req.UserObjectClasses,
|
||||
UserFilters: req.UserFilters,
|
||||
Timeout: req.Timeout.AsDuration(),
|
||||
LDAPAttributes: idp_grpc.LDAPAttributesToCommand(req.Attributes),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func updateLDAPProviderToCommand(req *admin_pb.UpdateLDAPProviderRequest) command.LDAPProvider {
|
||||
return command.LDAPProvider{
|
||||
Name: req.Name,
|
||||
Host: req.Host,
|
||||
Port: req.Port,
|
||||
TLS: req.Tls,
|
||||
BaseDN: req.BaseDn,
|
||||
UserObjectClass: req.UserObjectClass,
|
||||
UserUniqueAttribute: req.UserUniqueAttribute,
|
||||
Admin: req.Admin,
|
||||
Password: req.Password,
|
||||
LDAPAttributes: idp_grpc.LDAPAttributesToCommand(req.Attributes),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
Name: req.Name,
|
||||
Servers: req.Servers,
|
||||
StartTLS: req.StartTls,
|
||||
BaseDN: req.BaseDn,
|
||||
BindDN: req.BindDn,
|
||||
BindPassword: req.BindPassword,
|
||||
UserBase: req.UserBase,
|
||||
UserObjectClasses: req.UserObjectClasses,
|
||||
UserFilters: req.UserFilters,
|
||||
Timeout: req.Timeout.AsDuration(),
|
||||
LDAPAttributes: idp_grpc.LDAPAttributesToCommand(req.Attributes),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package idp
|
||||
|
||||
import (
|
||||
"google.golang.org/protobuf/types/known/durationpb"
|
||||
|
||||
obj_grpc "github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
iam_model "github.com/zitadel/zitadel/internal/iam/model"
|
||||
@ -582,16 +584,21 @@ func googleConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.Goo
|
||||
}
|
||||
|
||||
func ldapConfigToPb(providerConfig *idp_pb.ProviderConfig, template *query.LDAPIDPTemplate) {
|
||||
var timeout *durationpb.Duration
|
||||
if template.Timeout != 0 {
|
||||
timeout = durationpb.New(template.Timeout)
|
||||
}
|
||||
providerConfig.Config = &idp_pb.ProviderConfig_Ldap{
|
||||
Ldap: &idp_pb.LDAPConfig{
|
||||
Host: template.Host,
|
||||
Port: template.Port,
|
||||
Tls: template.TLS,
|
||||
BaseDn: template.BaseDN,
|
||||
UserObjectClass: template.UserObjectClass,
|
||||
UserUniqueAttribute: template.UserUniqueAttribute,
|
||||
Admin: template.Admin,
|
||||
Attributes: ldapAttributesToPb(template.LDAPAttributes),
|
||||
Servers: template.Servers,
|
||||
StartTls: template.StartTLS,
|
||||
BaseDn: template.BaseDN,
|
||||
BindDn: template.BindDN,
|
||||
UserBase: template.UserBase,
|
||||
UserObjectClasses: template.UserObjectClasses,
|
||||
UserFilters: template.UserFilters,
|
||||
Timeout: timeout,
|
||||
Attributes: ldapAttributesToPb(template.LDAPAttributes),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -422,32 +422,34 @@ func updateGoogleProviderToCommand(req *mgmt_pb.UpdateGoogleProviderRequest) com
|
||||
|
||||
func addLDAPProviderToCommand(req *mgmt_pb.AddLDAPProviderRequest) command.LDAPProvider {
|
||||
return command.LDAPProvider{
|
||||
Name: req.Name,
|
||||
Host: req.Host,
|
||||
Port: req.Port,
|
||||
TLS: req.Tls,
|
||||
BaseDN: req.BaseDn,
|
||||
UserObjectClass: req.UserObjectClass,
|
||||
UserUniqueAttribute: req.UserUniqueAttribute,
|
||||
Admin: req.Admin,
|
||||
Password: req.Password,
|
||||
LDAPAttributes: idp_grpc.LDAPAttributesToCommand(req.Attributes),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
Name: req.Name,
|
||||
Servers: req.Servers,
|
||||
StartTLS: req.StartTls,
|
||||
BaseDN: req.BaseDn,
|
||||
BindDN: req.BindDn,
|
||||
BindPassword: req.BindPassword,
|
||||
UserBase: req.UserBase,
|
||||
UserObjectClasses: req.UserObjectClasses,
|
||||
UserFilters: req.UserFilters,
|
||||
Timeout: req.Timeout.AsDuration(),
|
||||
LDAPAttributes: idp_grpc.LDAPAttributesToCommand(req.Attributes),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
||||
func updateLDAPProviderToCommand(req *mgmt_pb.UpdateLDAPProviderRequest) command.LDAPProvider {
|
||||
return command.LDAPProvider{
|
||||
Name: req.Name,
|
||||
Host: req.Host,
|
||||
Port: req.Port,
|
||||
TLS: req.Tls,
|
||||
BaseDN: req.BaseDn,
|
||||
UserObjectClass: req.UserObjectClass,
|
||||
UserUniqueAttribute: req.UserUniqueAttribute,
|
||||
Admin: req.Admin,
|
||||
Password: req.Password,
|
||||
LDAPAttributes: idp_grpc.LDAPAttributesToCommand(req.Attributes),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
Name: req.Name,
|
||||
Servers: req.Servers,
|
||||
StartTLS: req.StartTls,
|
||||
BaseDN: req.BaseDn,
|
||||
BindDN: req.BindDn,
|
||||
BindPassword: req.BindPassword,
|
||||
UserBase: req.UserBase,
|
||||
UserObjectClasses: req.UserObjectClasses,
|
||||
UserFilters: req.UserFilters,
|
||||
Timeout: req.Timeout.AsDuration(),
|
||||
LDAPAttributes: idp_grpc.LDAPAttributesToCommand(req.Attributes),
|
||||
IDPOptions: idp_grpc.OptionsToCommand(req.ProviderOptions),
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/gitlab"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/google"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/jwt"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/ldap"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/oauth"
|
||||
openid "github.com/zitadel/zitadel/internal/idp/providers/oidc"
|
||||
"github.com/zitadel/zitadel/internal/query"
|
||||
@ -157,8 +158,9 @@ func (l *Login) handleIDP(w http.ResponseWriter, r *http.Request, authReq *domai
|
||||
provider, err = l.gitlabSelfHostedProvider(r.Context(), identityProvider)
|
||||
case domain.IDPTypeGoogle:
|
||||
provider, err = l.googleProvider(r.Context(), identityProvider)
|
||||
case domain.IDPTypeLDAP,
|
||||
domain.IDPTypeUnspecified:
|
||||
case domain.IDPTypeLDAP:
|
||||
provider, err = l.ldapProvider(r.Context(), identityProvider)
|
||||
case domain.IDPTypeUnspecified:
|
||||
fallthrough
|
||||
default:
|
||||
l.renderLogin(w, r, authReq, errors.ThrowInvalidArgument(nil, "LOGIN-AShek", "Errors.ExternalIDP.IDPTypeNotImplemented"))
|
||||
@ -604,6 +606,69 @@ func (l *Login) updateExternalUser(ctx context.Context, authReq *domain.AuthRequ
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Login) ldapProvider(ctx context.Context, identityProvider *query.IDPTemplate) (*ldap.Provider, error) {
|
||||
password, err := crypto.DecryptString(identityProvider.LDAPIDPTemplate.BindPassword, l.idpConfigAlg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var opts []ldap.ProviderOpts
|
||||
if !identityProvider.LDAPIDPTemplate.StartTLS {
|
||||
opts = append(opts, ldap.WithoutStartTLS())
|
||||
}
|
||||
if identityProvider.LDAPIDPTemplate.LDAPAttributes.IDAttribute != "" {
|
||||
opts = append(opts, ldap.WithCustomIDAttribute(identityProvider.LDAPIDPTemplate.LDAPAttributes.IDAttribute))
|
||||
}
|
||||
if identityProvider.LDAPIDPTemplate.LDAPAttributes.FirstNameAttribute != "" {
|
||||
opts = append(opts, ldap.WithFirstNameAttribute(identityProvider.LDAPIDPTemplate.LDAPAttributes.FirstNameAttribute))
|
||||
}
|
||||
if identityProvider.LDAPIDPTemplate.LDAPAttributes.LastNameAttribute != "" {
|
||||
opts = append(opts, ldap.WithLastNameAttribute(identityProvider.LDAPIDPTemplate.LDAPAttributes.LastNameAttribute))
|
||||
}
|
||||
if identityProvider.LDAPIDPTemplate.LDAPAttributes.DisplayNameAttribute != "" {
|
||||
opts = append(opts, ldap.WithDisplayNameAttribute(identityProvider.LDAPIDPTemplate.LDAPAttributes.DisplayNameAttribute))
|
||||
}
|
||||
if identityProvider.LDAPIDPTemplate.LDAPAttributes.NickNameAttribute != "" {
|
||||
opts = append(opts, ldap.WithNickNameAttribute(identityProvider.LDAPIDPTemplate.LDAPAttributes.NickNameAttribute))
|
||||
}
|
||||
if identityProvider.LDAPIDPTemplate.LDAPAttributes.PreferredUsernameAttribute != "" {
|
||||
opts = append(opts, ldap.WithPreferredUsernameAttribute(identityProvider.LDAPIDPTemplate.LDAPAttributes.PreferredUsernameAttribute))
|
||||
}
|
||||
if identityProvider.LDAPIDPTemplate.LDAPAttributes.EmailAttribute != "" {
|
||||
opts = append(opts, ldap.WithEmailAttribute(identityProvider.LDAPIDPTemplate.LDAPAttributes.EmailAttribute))
|
||||
}
|
||||
if identityProvider.LDAPIDPTemplate.LDAPAttributes.EmailVerifiedAttribute != "" {
|
||||
opts = append(opts, ldap.WithEmailVerifiedAttribute(identityProvider.LDAPIDPTemplate.LDAPAttributes.EmailVerifiedAttribute))
|
||||
}
|
||||
if identityProvider.LDAPIDPTemplate.LDAPAttributes.PhoneAttribute != "" {
|
||||
opts = append(opts, ldap.WithPhoneAttribute(identityProvider.LDAPIDPTemplate.LDAPAttributes.PhoneAttribute))
|
||||
}
|
||||
if identityProvider.LDAPIDPTemplate.LDAPAttributes.PhoneVerifiedAttribute != "" {
|
||||
opts = append(opts, ldap.WithPhoneVerifiedAttribute(identityProvider.LDAPIDPTemplate.LDAPAttributes.PhoneVerifiedAttribute))
|
||||
}
|
||||
if identityProvider.LDAPIDPTemplate.LDAPAttributes.PreferredLanguageAttribute != "" {
|
||||
opts = append(opts, ldap.WithPreferredLanguageAttribute(identityProvider.LDAPIDPTemplate.LDAPAttributes.PreferredLanguageAttribute))
|
||||
}
|
||||
if identityProvider.LDAPIDPTemplate.LDAPAttributes.AvatarURLAttribute != "" {
|
||||
opts = append(opts, ldap.WithAvatarURLAttribute(identityProvider.LDAPIDPTemplate.LDAPAttributes.AvatarURLAttribute))
|
||||
}
|
||||
if identityProvider.LDAPIDPTemplate.LDAPAttributes.ProfileAttribute != "" {
|
||||
opts = append(opts, ldap.WithProfileAttribute(identityProvider.LDAPIDPTemplate.LDAPAttributes.ProfileAttribute))
|
||||
}
|
||||
return ldap.New(
|
||||
identityProvider.Name,
|
||||
identityProvider.Servers,
|
||||
identityProvider.BaseDN,
|
||||
identityProvider.BindDN,
|
||||
password,
|
||||
identityProvider.UserBase,
|
||||
identityProvider.UserObjectClasses,
|
||||
identityProvider.UserFilters,
|
||||
identityProvider.Timeout,
|
||||
l.baseURL(ctx)+EndpointLDAPLogin+"?"+QueryAuthRequestID+"=",
|
||||
opts...,
|
||||
), nil
|
||||
}
|
||||
|
||||
func (l *Login) googleProvider(ctx context.Context, identityProvider *query.IDPTemplate) (*google.Provider, error) {
|
||||
errorHandler := func(w http.ResponseWriter, r *http.Request, errorType string, errorDesc string, state string) {
|
||||
logging.Errorf("token exchanged failed: %s - %s (state: %s)", errorType, errorType, state)
|
||||
|
83
internal/api/ui/login/ldap_handler.go
Normal file
83
internal/api/ui/login/ldap_handler.go
Normal file
@ -0,0 +1,83 @@
|
||||
package login
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/zitadel/logging"
|
||||
|
||||
http_mw "github.com/zitadel/zitadel/internal/api/http/middleware"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/ldap"
|
||||
)
|
||||
|
||||
const (
|
||||
tmplLDAPLogin = "ldap_login"
|
||||
)
|
||||
|
||||
type ldapFormData struct {
|
||||
Username string `schema:"ldapusername"`
|
||||
Password string `schema:"ldappassword"`
|
||||
ResetExternalIDP bool `schema:"resetexternalidp"`
|
||||
}
|
||||
|
||||
func (l *Login) handleLDAP(w http.ResponseWriter, r *http.Request) {
|
||||
authReq, err := l.getAuthRequest(r)
|
||||
if err != nil {
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
l.renderLDAPLogin(w, r, authReq, nil)
|
||||
}
|
||||
|
||||
func (l *Login) renderLDAPLogin(w http.ResponseWriter, r *http.Request, authReq *domain.AuthRequest, err error) {
|
||||
var errID, errMessage string
|
||||
if err != nil {
|
||||
errID, errMessage = l.getErrorMessage(r, err)
|
||||
}
|
||||
temp := l.renderer.Templates[tmplLDAPLogin]
|
||||
data := l.getUserData(r, authReq, "Login.Title", "Login.Description", errID, errMessage)
|
||||
l.renderer.RenderTemplate(w, r, l.getTranslator(r.Context(), authReq), temp, data, nil)
|
||||
}
|
||||
|
||||
func (l *Login) handleLDAPCallback(w http.ResponseWriter, r *http.Request) {
|
||||
data := new(ldapFormData)
|
||||
authReq, err := l.getAuthRequestAndParseData(r, data)
|
||||
if err != nil {
|
||||
l.renderError(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
if data.ResetExternalIDP {
|
||||
userAgentID, _ := http_mw.UserAgentIDFromCtx(r.Context())
|
||||
err := l.authRepo.ResetSelectedIDP(r.Context(), authReq.ID, userAgentID)
|
||||
if err != nil {
|
||||
l.renderLDAPLogin(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
|
||||
l.handleLoginName(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
identityProvider, err := l.getIDPByID(r, authReq.SelectedIDPConfigID)
|
||||
if err != nil {
|
||||
l.renderLDAPLogin(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
|
||||
provider, err := l.ldapProvider(r.Context(), identityProvider)
|
||||
if err != nil {
|
||||
l.renderLDAPLogin(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
session := &ldap.Session{Provider: provider, User: data.Username, Password: data.Password}
|
||||
|
||||
user, err := session.FetchUser(r.Context())
|
||||
if err != nil {
|
||||
if _, actionErr := l.runPostExternalAuthenticationActions(new(domain.ExternalUser), nil, authReq, r, nil, err); actionErr != nil {
|
||||
logging.WithError(err).Error("both external user authentication and action post authentication failed")
|
||||
}
|
||||
l.renderLDAPLogin(w, r, authReq, err)
|
||||
return
|
||||
}
|
||||
l.handleExternalUserAuthenticated(w, r, authReq, identityProvider, session, user, l.renderNextStep)
|
||||
}
|
@ -76,6 +76,7 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage
|
||||
tmplLinkUsersDone: "link_users_done.html",
|
||||
tmplExternalNotFoundOption: "external_not_found_option.html",
|
||||
tmplLoginSuccess: "login_success.html",
|
||||
tmplLDAPLogin: "ldap_login.html",
|
||||
}
|
||||
funcs := map[string]interface{}{
|
||||
"resourceUrl": func(file string) string {
|
||||
@ -219,6 +220,9 @@ func CreateRenderer(pathPrefix string, staticDir http.FileSystem, staticStorage
|
||||
"idpProviderClass": func(idpType domain.IDPType) string {
|
||||
return idpType.GetCSSClass()
|
||||
},
|
||||
"ldapUrl": func() string {
|
||||
return path.Join(r.pathPrefix, EndpointLDAPCallback)
|
||||
},
|
||||
}
|
||||
var err error
|
||||
r.Renderer, err = renderer.NewRenderer(
|
||||
|
@ -15,6 +15,8 @@ const (
|
||||
EndpointExternalLoginCallback = "/login/externalidp/callback"
|
||||
EndpointJWTAuthorize = "/login/jwt/authorize"
|
||||
EndpointJWTCallback = "/login/jwt/callback"
|
||||
EndpointLDAPLogin = "/login/ldap"
|
||||
EndpointLDAPCallback = "/login/ldap/callback"
|
||||
EndpointPasswordlessLogin = "/login/passwordless"
|
||||
EndpointPasswordlessRegistration = "/login/passwordless/init"
|
||||
EndpointPasswordlessPrompt = "/login/passwordless/prompt"
|
||||
@ -102,6 +104,8 @@ func CreateRouter(login *Login, staticDir http.FileSystem, interceptors ...mux.M
|
||||
router.HandleFunc(EndpointRegisterOrg, login.handleRegisterOrg).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointRegisterOrg, login.handleRegisterOrgCheck).Methods(http.MethodPost)
|
||||
router.HandleFunc(EndpointLoginSuccess, login.handleLoginSuccess).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointLDAPLogin, login.handleLDAP).Methods(http.MethodGet)
|
||||
router.HandleFunc(EndpointLDAPCallback, login.handleLDAPCallback).Methods(http.MethodPost)
|
||||
router.SkipClean(true).Handle("", http.RedirectHandler(HandlerPrefix+"/", http.StatusMovedPermanently))
|
||||
return router
|
||||
}
|
||||
|
@ -11,6 +11,13 @@ Login:
|
||||
RegisterButtonText: registrieren
|
||||
NextButtonText: weiter
|
||||
|
||||
LDAP:
|
||||
Title: Anmeldung
|
||||
Description: Mit Konto anmelden.
|
||||
LoginNameLabel: Loginname
|
||||
PasswordLabel: Passwort
|
||||
NextButtonText: weiter
|
||||
|
||||
SelectAccount:
|
||||
Title: Account auswählen
|
||||
Description: Wähle deinen Account aus.
|
||||
|
@ -11,6 +11,13 @@ Login:
|
||||
RegisterButtonText: register
|
||||
NextButtonText: next
|
||||
|
||||
LDAP:
|
||||
Title: Login
|
||||
Description: Enter your login data.
|
||||
LoginNameLabel: Loginname
|
||||
PasswordLabel: Password
|
||||
NextButtonText: next
|
||||
|
||||
SelectAccount:
|
||||
Title: Select account
|
||||
Description: Use your ZITADEL-Account
|
||||
|
@ -11,6 +11,13 @@ Login:
|
||||
RegisterButtonText: s'inscrire
|
||||
NextButtonText: suivant
|
||||
|
||||
LDAP:
|
||||
Title: Connexion
|
||||
Description: Entrez vos données de connexion.
|
||||
LoginNameLabel: Identifiant
|
||||
PasswordLabel: Mot de passe
|
||||
NextButtonText: suivant
|
||||
|
||||
SelectAccount:
|
||||
Title: Sélectionner un compte
|
||||
Description: Utilisez votre compte ZITADEL
|
||||
|
@ -11,6 +11,13 @@ Login:
|
||||
RegisterButtonText: registrare
|
||||
NextButtonText: Avanti
|
||||
|
||||
LDAP:
|
||||
Title: Accesso
|
||||
Description: Inserisci i tuoi dati di accesso.
|
||||
LoginNameLabel: Nome di accesso
|
||||
PasswordLabel: Password
|
||||
NextButtonText: Avanti
|
||||
|
||||
SelectAccount:
|
||||
Title: Seleziona l'account
|
||||
Description: Usa il tuo account ZITADEL
|
||||
|
@ -11,6 +11,13 @@ Login:
|
||||
RegisterButtonText: zarejestruj
|
||||
NextButtonText: dalej
|
||||
|
||||
LDAP:
|
||||
Title: Rejestracja
|
||||
Description: Wprowadź swoje dane logowania.
|
||||
LoginNameLabel: Nazwa użytkownika
|
||||
PasswordLabel: Hasło
|
||||
NextButtonText: dalej
|
||||
|
||||
SelectAccount:
|
||||
Title: Wybierz konto
|
||||
Description: Użyj swojego konta ZITADEL
|
||||
|
@ -11,6 +11,13 @@ Login:
|
||||
RegisterButtonText: 注册
|
||||
NextButtonText: 继续
|
||||
|
||||
LDAP:
|
||||
Title: 注册
|
||||
Description: 输入您的登录数据。
|
||||
LoginNameLabel: 登录名
|
||||
PasswordLabel: 密码
|
||||
NextButtonText: 继续
|
||||
|
||||
SelectAccount:
|
||||
Title: 选择账户
|
||||
Description: 使用您的 ZITADEL 帐户
|
||||
|
40
internal/api/ui/login/static/templates/ldap_login.html
Normal file
40
internal/api/ui/login/static/templates/ldap_login.html
Normal file
@ -0,0 +1,40 @@
|
||||
{{template "main-top" .}}
|
||||
|
||||
<div class="lgn-head">
|
||||
<h1>{{t "LDAP.Title"}}</h1>
|
||||
<p>{{t "LDAP.Description"}}</p>
|
||||
</div>
|
||||
|
||||
|
||||
<form action="{{ ldapUrl }}" method="POST">
|
||||
|
||||
{{ .CSRF }}
|
||||
|
||||
<input type="hidden" name="authRequestID" value="{{ .AuthReqID }}"/>
|
||||
|
||||
<div class="fields">
|
||||
<label class="lgn-label" for="ldapusername">{{t "LDAP.LoginNameLabel"}}</label>
|
||||
<input class="lgn-input" type="text" id="ldapusername" name="ldapusername" autocomplete="username" autofocus required>
|
||||
</div>
|
||||
<div class="fields">
|
||||
<label class="lgn-label" for="ldappassword">{{t "LDAP.PasswordLabel"}}</label>
|
||||
<input class="lgn-input" type="password" id="ldappassword" name="ldappassword" autocomplete="current-password" required>
|
||||
</div>
|
||||
|
||||
{{template "error-message" .}}
|
||||
|
||||
<div class="lgn-actions lgn-reverse-order">
|
||||
<button class="lgn-raised-button lgn-primary lgn-initial-focus" id="submit-button" type="submit">
|
||||
{{t "LDAP.NextButtonText"}}
|
||||
</button>
|
||||
<span class="fill-space"></span>
|
||||
<button class="lgn-icon-button lgn-left-action" name="resetexternalidp" value="true" formnovalidate>
|
||||
<i class="lgn-icon-arrow-left-solid"></i>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<script src="{{ resourceUrl " scripts/form_submit.js" }}"></script>
|
||||
<script src="{{ resourceUrl " scripts/default_form_validation.js" }}"></script>
|
||||
|
||||
{{template "main-bottom" .}}
|
@ -34,4 +34,5 @@ type AuthRequestRepository interface {
|
||||
LinkExternalUsers(ctx context.Context, authReqID, userAgentID string, info *domain.BrowserInfo) error
|
||||
AutoRegisterExternalUser(ctx context.Context, user *domain.Human, externalIDP *domain.UserIDPLink, orgMemberRoles []string, authReqID, userAgentID, resourceOwner string, metadatas []*domain.Metadata, info *domain.BrowserInfo) error
|
||||
ResetLinkingUsers(ctx context.Context, authReqID, userAgentID string) error
|
||||
ResetSelectedIDP(ctx context.Context, authReqID, userAgentID string) error
|
||||
}
|
||||
|
@ -461,6 +461,15 @@ func (repo *AuthRequestRepo) ResetLinkingUsers(ctx context.Context, authReqID, u
|
||||
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
|
||||
}
|
||||
|
||||
func (repo *AuthRequestRepo) ResetSelectedIDP(ctx context.Context, authReqID, userAgentID string) error {
|
||||
request, err := repo.getAuthRequest(ctx, authReqID, userAgentID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
request.SelectedIDPConfigID = ""
|
||||
return repo.AuthRequests.UpdateAuthRequest(ctx, request)
|
||||
}
|
||||
|
||||
func (repo *AuthRequestRepo) AutoRegisterExternalUser(ctx context.Context, registerUser *domain.Human, externalIDP *domain.UserIDPLink, orgMemberRoles []string, authReqID, userAgentID, resourceOwner string, metadatas []*domain.Metadata, info *domain.BrowserInfo) (err error) {
|
||||
ctx, span := tracing.NewSpan(ctx)
|
||||
defer func() { span.EndWithError(err) }()
|
||||
|
@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/api/authz"
|
||||
"github.com/zitadel/zitadel/internal/command/preparation"
|
||||
@ -94,17 +95,18 @@ type GoogleProvider struct {
|
||||
}
|
||||
|
||||
type LDAPProvider struct {
|
||||
Name string
|
||||
Host string
|
||||
Port string
|
||||
TLS bool
|
||||
BaseDN string
|
||||
UserObjectClass string
|
||||
UserUniqueAttribute string
|
||||
Admin string
|
||||
Password string
|
||||
LDAPAttributes idp.LDAPAttributes
|
||||
IDPOptions idp.Options
|
||||
Name string
|
||||
Servers []string
|
||||
StartTLS bool
|
||||
BaseDN string
|
||||
BindDN string
|
||||
BindPassword string
|
||||
UserBase string
|
||||
UserObjectClasses []string
|
||||
UserFilters []string
|
||||
Timeout time.Duration
|
||||
LDAPAttributes idp.LDAPAttributes
|
||||
IDPOptions idp.Options
|
||||
}
|
||||
|
||||
func ExistsIDP(ctx context.Context, filter preparation.FilterToQueryReducer, id, orgID string) (exists bool, err error) {
|
||||
|
@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@ -999,16 +1000,17 @@ func (wm *GoogleIDPWriteModel) NewChanges(
|
||||
type LDAPIDPWriteModel struct {
|
||||
eventstore.WriteModel
|
||||
|
||||
ID string
|
||||
Name string
|
||||
Host string
|
||||
Port string
|
||||
TLS bool
|
||||
BaseDN string
|
||||
UserObjectClass string
|
||||
UserUniqueAttribute string
|
||||
Admin string
|
||||
Password *crypto.CryptoValue
|
||||
ID string
|
||||
Name string
|
||||
Servers []string
|
||||
StartTLS bool
|
||||
BaseDN string
|
||||
BindDN string
|
||||
BindPassword *crypto.CryptoValue
|
||||
UserBase string
|
||||
UserObjectClasses []string
|
||||
UserFilters []string
|
||||
Timeout time.Duration
|
||||
idp.LDAPAttributes
|
||||
idp.Options
|
||||
|
||||
@ -1040,14 +1042,15 @@ func (wm *LDAPIDPWriteModel) Reduce() error {
|
||||
|
||||
func (wm *LDAPIDPWriteModel) reduceAddedEvent(e *idp.LDAPIDPAddedEvent) {
|
||||
wm.Name = e.Name
|
||||
wm.Host = e.Host
|
||||
wm.Port = e.Port
|
||||
wm.TLS = e.TLS
|
||||
wm.Servers = e.Servers
|
||||
wm.StartTLS = e.StartTLS
|
||||
wm.BaseDN = e.BaseDN
|
||||
wm.UserObjectClass = e.UserObjectClass
|
||||
wm.UserUniqueAttribute = e.UserUniqueAttribute
|
||||
wm.Admin = e.Admin
|
||||
wm.Password = e.Password
|
||||
wm.BindDN = e.BindDN
|
||||
wm.BindPassword = e.BindPassword
|
||||
wm.UserBase = e.UserBase
|
||||
wm.UserObjectClasses = e.UserObjectClasses
|
||||
wm.UserFilters = e.UserFilters
|
||||
wm.Timeout = e.Timeout
|
||||
wm.LDAPAttributes = e.LDAPAttributes
|
||||
wm.Options = e.Options
|
||||
wm.State = domain.IDPStateActive
|
||||
@ -1060,44 +1063,48 @@ func (wm *LDAPIDPWriteModel) reduceChangedEvent(e *idp.LDAPIDPChangedEvent) {
|
||||
if e.Name != nil {
|
||||
wm.Name = *e.Name
|
||||
}
|
||||
if e.Host != nil {
|
||||
wm.Host = *e.Host
|
||||
if e.Servers != nil {
|
||||
wm.Servers = e.Servers
|
||||
}
|
||||
if e.Port != nil {
|
||||
wm.Port = *e.Port
|
||||
}
|
||||
if e.TLS != nil {
|
||||
wm.TLS = *e.TLS
|
||||
if e.StartTLS != nil {
|
||||
wm.StartTLS = *e.StartTLS
|
||||
}
|
||||
if e.BaseDN != nil {
|
||||
wm.BaseDN = *e.BaseDN
|
||||
}
|
||||
if e.UserObjectClass != nil {
|
||||
wm.UserObjectClass = *e.UserObjectClass
|
||||
if e.BindDN != nil {
|
||||
wm.BindDN = *e.BindDN
|
||||
}
|
||||
if e.UserUniqueAttribute != nil {
|
||||
wm.UserUniqueAttribute = *e.UserUniqueAttribute
|
||||
if e.BindPassword != nil {
|
||||
wm.BindPassword = e.BindPassword
|
||||
}
|
||||
if e.Admin != nil {
|
||||
wm.Admin = *e.Admin
|
||||
if e.UserBase != nil {
|
||||
wm.UserBase = *e.UserBase
|
||||
}
|
||||
if e.Password != nil {
|
||||
wm.Password = e.Password
|
||||
if e.UserObjectClasses != nil {
|
||||
wm.UserObjectClasses = e.UserObjectClasses
|
||||
}
|
||||
if e.UserFilters != nil {
|
||||
wm.UserFilters = e.UserFilters
|
||||
}
|
||||
if e.Timeout != nil {
|
||||
wm.Timeout = *e.Timeout
|
||||
}
|
||||
wm.LDAPAttributes.ReduceChanges(e.LDAPAttributeChanges)
|
||||
wm.Options.ReduceChanges(e.OptionChanges)
|
||||
}
|
||||
|
||||
func (wm *LDAPIDPWriteModel) NewChanges(
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password string,
|
||||
name string,
|
||||
servers []string,
|
||||
startTLS bool,
|
||||
baseDN string,
|
||||
bindDN string,
|
||||
bindPassword string,
|
||||
userBase string,
|
||||
userObjectClasses []string,
|
||||
userFilters []string,
|
||||
timeout time.Duration,
|
||||
secretCrypto crypto.Crypto,
|
||||
attributes idp.LDAPAttributes,
|
||||
options idp.Options,
|
||||
@ -1105,36 +1112,39 @@ func (wm *LDAPIDPWriteModel) NewChanges(
|
||||
changes := make([]idp.LDAPIDPChanges, 0)
|
||||
var cryptedPassword *crypto.CryptoValue
|
||||
var err error
|
||||
if password != "" {
|
||||
cryptedPassword, err = crypto.Crypt([]byte(password), secretCrypto)
|
||||
if bindPassword != "" {
|
||||
cryptedPassword, err = crypto.Crypt([]byte(bindPassword), secretCrypto)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
changes = append(changes, idp.ChangeLDAPPassword(cryptedPassword))
|
||||
changes = append(changes, idp.ChangeLDAPBindPassword(cryptedPassword))
|
||||
}
|
||||
if wm.Name != name {
|
||||
changes = append(changes, idp.ChangeLDAPName(name))
|
||||
}
|
||||
if wm.Host != host {
|
||||
changes = append(changes, idp.ChangeLDAPHost(host))
|
||||
if !reflect.DeepEqual(wm.Servers, servers) {
|
||||
changes = append(changes, idp.ChangeLDAPServers(servers))
|
||||
}
|
||||
if wm.Port != port {
|
||||
changes = append(changes, idp.ChangeLDAPPort(port))
|
||||
}
|
||||
if wm.TLS != tls {
|
||||
changes = append(changes, idp.ChangeLDAPTLS(tls))
|
||||
if wm.StartTLS != startTLS {
|
||||
changes = append(changes, idp.ChangeLDAPStartTLS(startTLS))
|
||||
}
|
||||
if wm.BaseDN != baseDN {
|
||||
changes = append(changes, idp.ChangeLDAPBaseDN(baseDN))
|
||||
}
|
||||
if wm.UserObjectClass != userObjectClass {
|
||||
changes = append(changes, idp.ChangeLDAPUserObjectClass(userObjectClass))
|
||||
if wm.BindDN != bindDN {
|
||||
changes = append(changes, idp.ChangeLDAPBindDN(bindDN))
|
||||
}
|
||||
if wm.UserUniqueAttribute != userUniqueAttribute {
|
||||
changes = append(changes, idp.ChangeLDAPUserUniqueAttribute(userUniqueAttribute))
|
||||
if wm.UserBase != userBase {
|
||||
changes = append(changes, idp.ChangeLDAPUserBase(userBase))
|
||||
}
|
||||
if wm.Admin != admin {
|
||||
changes = append(changes, idp.ChangeLDAPAdmin(admin))
|
||||
if !reflect.DeepEqual(wm.UserObjectClasses, userObjectClasses) {
|
||||
changes = append(changes, idp.ChangeLDAPUserObjectClasses(userObjectClasses))
|
||||
}
|
||||
if !reflect.DeepEqual(wm.UserFilters, userFilters) {
|
||||
changes = append(changes, idp.ChangeLDAPUserFilters(userFilters))
|
||||
}
|
||||
if wm.Timeout != timeout {
|
||||
changes = append(changes, idp.ChangeLDAPTimeout(timeout))
|
||||
}
|
||||
attrs := wm.LDAPAttributes.Changes(attributes)
|
||||
if !attrs.IsZero() {
|
||||
|
@ -1278,23 +1278,26 @@ func (c *Commands) prepareAddInstanceLDAPProvider(a *instance.Aggregate, writeMo
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-SAfdd", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Host = strings.TrimSpace(provider.Host); provider.Host == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-SDVg2", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.BaseDN = strings.TrimSpace(provider.BaseDN); provider.BaseDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-sv31s", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserObjectClass = strings.TrimSpace(provider.UserObjectClass); provider.UserObjectClass == "" {
|
||||
if provider.BindDN = strings.TrimSpace(provider.BindDN); provider.BindDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-sdgf4", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserUniqueAttribute = strings.TrimSpace(provider.UserUniqueAttribute); provider.UserUniqueAttribute == "" {
|
||||
if provider.BindPassword = strings.TrimSpace(provider.BindPassword); provider.BindPassword == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-AEG2w", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Admin = strings.TrimSpace(provider.Admin); provider.Admin == "" {
|
||||
if provider.UserBase = strings.TrimSpace(provider.UserBase); provider.UserBase == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-SAD5n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Password = strings.TrimSpace(provider.Password); provider.Password == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-sdf5h", "Errors.Invalid.Argument")
|
||||
if len(provider.Servers) == 0 {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-SAx905n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if len(provider.UserObjectClasses) == 0 {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-S1x905n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if len(provider.UserFilters) == 0 {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-aAx905n", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
@ -1305,7 +1308,7 @@ func (c *Commands) prepareAddInstanceLDAPProvider(a *instance.Aggregate, writeMo
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secret, err := crypto.Encrypt([]byte(provider.Password), c.idpConfigEncryption)
|
||||
secret, err := crypto.Encrypt([]byte(provider.BindPassword), c.idpConfigEncryption)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1315,14 +1318,15 @@ func (c *Commands) prepareAddInstanceLDAPProvider(a *instance.Aggregate, writeMo
|
||||
&a.Aggregate,
|
||||
writeModel.ID,
|
||||
provider.Name,
|
||||
provider.Host,
|
||||
provider.Port,
|
||||
provider.TLS,
|
||||
provider.Servers,
|
||||
provider.StartTLS,
|
||||
provider.BaseDN,
|
||||
provider.UserObjectClass,
|
||||
provider.UserUniqueAttribute,
|
||||
provider.Admin,
|
||||
provider.BindDN,
|
||||
secret,
|
||||
provider.UserBase,
|
||||
provider.UserObjectClasses,
|
||||
provider.UserFilters,
|
||||
provider.Timeout,
|
||||
provider.LDAPAttributes,
|
||||
provider.IDPOptions,
|
||||
),
|
||||
@ -1339,21 +1343,24 @@ func (c *Commands) prepareUpdateInstanceLDAPProvider(a *instance.Aggregate, writ
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Sffgd", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Host = strings.TrimSpace(provider.Host); provider.Host == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-Dz62d", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.BaseDN = strings.TrimSpace(provider.BaseDN); provider.BaseDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-vb3ss", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserObjectClass = strings.TrimSpace(provider.UserObjectClass); provider.UserObjectClass == "" {
|
||||
if provider.BindDN = strings.TrimSpace(provider.BindDN); provider.BindDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-hbere", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserUniqueAttribute = strings.TrimSpace(provider.UserUniqueAttribute); provider.UserUniqueAttribute == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-ASFt6", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Admin = strings.TrimSpace(provider.Admin); provider.Admin == "" {
|
||||
if provider.UserBase = strings.TrimSpace(provider.UserBase); provider.UserBase == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-DG45z", "Errors.Invalid.Argument")
|
||||
}
|
||||
if len(provider.Servers) == 0 {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-SAx945n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if len(provider.UserObjectClasses) == 0 {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-S1x605n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if len(provider.UserFilters) == 0 {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "INST-aAx901n", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
@ -1370,16 +1377,16 @@ func (c *Commands) prepareUpdateInstanceLDAPProvider(a *instance.Aggregate, writ
|
||||
ctx,
|
||||
&a.Aggregate,
|
||||
writeModel.ID,
|
||||
writeModel.Name,
|
||||
provider.Name,
|
||||
provider.Host,
|
||||
provider.Port,
|
||||
provider.TLS,
|
||||
provider.Servers,
|
||||
provider.StartTLS,
|
||||
provider.BaseDN,
|
||||
provider.UserObjectClass,
|
||||
provider.UserUniqueAttribute,
|
||||
provider.Admin,
|
||||
provider.Password,
|
||||
provider.BindDN,
|
||||
provider.BindPassword,
|
||||
provider.UserBase,
|
||||
provider.UserObjectClasses,
|
||||
provider.UserFilters,
|
||||
provider.Timeout,
|
||||
c.idpConfigEncryption,
|
||||
provider.LDAPAttributes,
|
||||
provider.IDPOptions,
|
||||
|
@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@ -744,16 +745,16 @@ func (wm *InstanceLDAPIDPWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
oldName,
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password string,
|
||||
name string,
|
||||
servers []string,
|
||||
startTLS bool,
|
||||
baseDN string,
|
||||
bindDN string,
|
||||
bindPassword string,
|
||||
userBase string,
|
||||
userObjectClasses []string,
|
||||
userFilters []string,
|
||||
timeout time.Duration,
|
||||
secretCrypto crypto.Crypto,
|
||||
attributes idp.LDAPAttributes,
|
||||
options idp.Options,
|
||||
@ -761,14 +762,15 @@ func (wm *InstanceLDAPIDPWriteModel) NewChangedEvent(
|
||||
|
||||
changes, err := wm.LDAPIDPWriteModel.NewChanges(
|
||||
name,
|
||||
host,
|
||||
port,
|
||||
tls,
|
||||
servers,
|
||||
startTLS,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin,
|
||||
password,
|
||||
bindDN,
|
||||
bindPassword,
|
||||
userBase,
|
||||
userObjectClasses,
|
||||
userFilters,
|
||||
timeout,
|
||||
secretCrypto,
|
||||
attributes,
|
||||
options,
|
||||
@ -776,7 +778,7 @@ func (wm *InstanceLDAPIDPWriteModel) NewChangedEvent(
|
||||
if err != nil || len(changes) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
return instance.NewLDAPIDPChangedEvent(ctx, aggregate, id, oldName, changes)
|
||||
return instance.NewLDAPIDPChangedEvent(ctx, aggregate, id, changes)
|
||||
}
|
||||
|
||||
type InstanceIDPRemoveWriteModel struct {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -18,7 +19,6 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
id_mock "github.com/zitadel/zitadel/internal/id/mock"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
)
|
||||
|
||||
@ -3677,24 +3677,6 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid host",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-SDVg2", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid baseDN",
|
||||
fields{
|
||||
@ -3705,7 +3687,6 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
},
|
||||
},
|
||||
res{
|
||||
@ -3715,7 +3696,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClass",
|
||||
"invalid bindDN",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
@ -3724,7 +3705,6 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
@ -3735,7 +3715,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userUniqueAttribute",
|
||||
"invalid bindPassword",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
@ -3743,10 +3723,9 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
Name: "name",
|
||||
BindDN: "binddn",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
res{
|
||||
@ -3756,7 +3735,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid admin",
|
||||
"invalid userBase",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
@ -3764,11 +3743,10 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Name: "name",
|
||||
BindDN: "binddn",
|
||||
BaseDN: "baseDN",
|
||||
BindPassword: "password",
|
||||
},
|
||||
},
|
||||
res{
|
||||
@ -3778,7 +3756,7 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid password",
|
||||
"invalid servers",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
@ -3786,17 +3764,63 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Name: "name",
|
||||
BindDN: "binddn",
|
||||
BaseDN: "baseDN",
|
||||
BindPassword: "password",
|
||||
UserBase: "user",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-sdf5h", ""))
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-SAx905n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClasses",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
BindDN: "binddn",
|
||||
BaseDN: "baseDN",
|
||||
BindPassword: "password",
|
||||
UserBase: "user",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-S1x905n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userFilters",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
BindDN: "binddn",
|
||||
BaseDN: "baseDN",
|
||||
BindPassword: "password",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-aAx905n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -3812,24 +3836,24 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"",
|
||||
[]string{"server"},
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
"dn",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
"user",
|
||||
[]string{"object"},
|
||||
[]string{"filter"},
|
||||
time.Second*30,
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraintWithInstanceID("instance1", idpconfig.NewAddIDPConfigNameUniqueConstraint("name", "instance1")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
@ -3838,13 +3862,16 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Password: "password",
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
StartTLS: false,
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "dn",
|
||||
BindPassword: "password",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
UserFilters: []string{"filter"},
|
||||
Timeout: time.Second * 30,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -3864,19 +3891,20 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
[]string{"server"},
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
"dn",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
"user",
|
||||
[]string{"object"},
|
||||
[]string{"filter"},
|
||||
time.Second*30,
|
||||
idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "firstName",
|
||||
@ -3900,7 +3928,6 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
},
|
||||
)),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraintWithInstanceID("instance1", idpconfig.NewAddIDPConfigNameUniqueConstraint("name", "instance1")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
@ -3909,15 +3936,16 @@ func TestCommandSide_AddInstanceLDAPIDP(t *testing.T) {
|
||||
args: args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
Port: "port",
|
||||
TLS: true,
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Password: "password",
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
StartTLS: false,
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "dn",
|
||||
BindPassword: "password",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
UserFilters: []string{"filter"},
|
||||
Timeout: time.Second * 30,
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "firstName",
|
||||
@ -4020,24 +4048,6 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid host",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-Dz62d", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid baseDN",
|
||||
fields{
|
||||
@ -4048,7 +4058,6 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
},
|
||||
},
|
||||
res{
|
||||
@ -4058,7 +4067,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClass",
|
||||
"invalid bindDN",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
@ -4067,7 +4076,6 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
@ -4078,7 +4086,7 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userUniqueAttribute",
|
||||
"invalid userbase",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
@ -4086,32 +4094,9 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-ASFt6", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid admin",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Name: "name",
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "bindDN",
|
||||
},
|
||||
},
|
||||
res{
|
||||
@ -4120,6 +4105,72 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid servers",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "bindDN",
|
||||
UserBase: "user",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-SAx945n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClasses",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "bindDN",
|
||||
UserBase: "user",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-S1x605n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userFilters",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "bindDN",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "INST-aAx901n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
fields: fields{
|
||||
@ -4131,16 +4182,20 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "binddn",
|
||||
BindPassword: "password",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
UserFilters: []string{"filter"},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errors.IsNotFound,
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowNotFound(nil, "INST-ASF3F", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -4152,19 +4207,20 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"",
|
||||
[]string{"server"},
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
"basedn",
|
||||
"binddn",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
"user",
|
||||
[]string{"object"},
|
||||
[]string{"filter"},
|
||||
time.Second*30,
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
@ -4175,12 +4231,15 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
StartTLS: false,
|
||||
BaseDN: "basedn",
|
||||
BindDN: "binddn",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
UserFilters: []string{"filter"},
|
||||
Timeout: time.Second * 30,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -4196,19 +4255,20 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
instance.NewLDAPIDPAddedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"port",
|
||||
[]string{"server"},
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
"basedn",
|
||||
"binddn",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
"user",
|
||||
[]string{"object"},
|
||||
[]string{"filter"},
|
||||
time.Second*30,
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
@ -4221,22 +4281,22 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
t := true
|
||||
event, _ := instance.NewLDAPIDPChangedEvent(context.Background(), &instance.NewAggregate("instance1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
[]idp.LDAPIDPChanges{
|
||||
idp.ChangeLDAPName("new name"),
|
||||
idp.ChangeLDAPHost("new host"),
|
||||
idp.ChangeLDAPPort("new port"),
|
||||
idp.ChangeLDAPTLS(true),
|
||||
idp.ChangeLDAPBaseDN("new baseDN"),
|
||||
idp.ChangeLDAPUserObjectClass("new userObjectClass"),
|
||||
idp.ChangeLDAPUserUniqueAttribute("new userUniqueAttribute"),
|
||||
idp.ChangeLDAPAdmin("new admin"),
|
||||
idp.ChangeLDAPPassword(&crypto.CryptoValue{
|
||||
idp.ChangeLDAPServers([]string{"new server"}),
|
||||
idp.ChangeLDAPStartTLS(true),
|
||||
idp.ChangeLDAPBaseDN("new basedn"),
|
||||
idp.ChangeLDAPBindDN("new binddn"),
|
||||
idp.ChangeLDAPBindPassword(&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("new password"),
|
||||
}),
|
||||
idp.ChangeLDAPUserBase("new user"),
|
||||
idp.ChangeLDAPUserObjectClasses([]string{"new object"}),
|
||||
idp.ChangeLDAPUserFilters([]string{"new filter"}),
|
||||
idp.ChangeLDAPTimeout(time.Second * 20),
|
||||
idp.ChangeLDAPAttributes(idp.LDAPAttributeChanges{
|
||||
IDAttribute: stringPointer("new id"),
|
||||
FirstNameAttribute: stringPointer("new firstName"),
|
||||
@ -4264,8 +4324,6 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
}(),
|
||||
),
|
||||
},
|
||||
uniqueConstraintsFromEventConstraintWithInstanceID("instance1", idpconfig.NewRemoveIDPConfigNameUniqueConstraint("name", "instance1")),
|
||||
uniqueConstraintsFromEventConstraintWithInstanceID("instance1", idpconfig.NewAddIDPConfigNameUniqueConstraint("new name", "instance1")),
|
||||
),
|
||||
),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
@ -4274,15 +4332,16 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "new name",
|
||||
Host: "new host",
|
||||
Port: "new port",
|
||||
TLS: true,
|
||||
BaseDN: "new baseDN",
|
||||
UserObjectClass: "new userObjectClass",
|
||||
UserUniqueAttribute: "new userUniqueAttribute",
|
||||
Admin: "new admin",
|
||||
Password: "new password",
|
||||
Name: "new name",
|
||||
Servers: []string{"new server"},
|
||||
StartTLS: true,
|
||||
BaseDN: "new basedn",
|
||||
BindDN: "new binddn",
|
||||
BindPassword: "new password",
|
||||
UserBase: "new user",
|
||||
UserObjectClasses: []string{"new object"},
|
||||
UserFilters: []string{"new filter"},
|
||||
Timeout: time.Second * 20,
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "new id",
|
||||
FirstNameAttribute: "new firstName",
|
||||
|
@ -1268,23 +1268,26 @@ func (c *Commands) prepareAddOrgLDAPProvider(a *org.Aggregate, writeModel *OrgLD
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-SAfdd", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Host = strings.TrimSpace(provider.Host); provider.Host == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-SDVg2", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.BaseDN = strings.TrimSpace(provider.BaseDN); provider.BaseDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-sv31s", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserObjectClass = strings.TrimSpace(provider.UserObjectClass); provider.UserObjectClass == "" {
|
||||
if provider.BindDN = strings.TrimSpace(provider.BindDN); provider.BindDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-sdgf4", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserUniqueAttribute = strings.TrimSpace(provider.UserUniqueAttribute); provider.UserUniqueAttribute == "" {
|
||||
if provider.BindPassword = strings.TrimSpace(provider.BindPassword); provider.BindPassword == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-AEG2w", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Admin = strings.TrimSpace(provider.Admin); provider.Admin == "" {
|
||||
if provider.UserBase = strings.TrimSpace(provider.UserBase); provider.UserBase == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-SAD5n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Password = strings.TrimSpace(provider.Password); provider.Password == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-sdf5h", "Errors.Invalid.Argument")
|
||||
if len(provider.Servers) == 0 {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-SAy945n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if len(provider.UserObjectClasses) == 0 {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-S1x705n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if len(provider.UserFilters) == 0 {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-aAx9x1n", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
@ -1295,7 +1298,7 @@ func (c *Commands) prepareAddOrgLDAPProvider(a *org.Aggregate, writeModel *OrgLD
|
||||
if err = writeModel.Reduce(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
secret, err := crypto.Encrypt([]byte(provider.Password), c.idpConfigEncryption)
|
||||
secret, err := crypto.Encrypt([]byte(provider.BindPassword), c.idpConfigEncryption)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -1305,14 +1308,15 @@ func (c *Commands) prepareAddOrgLDAPProvider(a *org.Aggregate, writeModel *OrgLD
|
||||
&a.Aggregate,
|
||||
writeModel.ID,
|
||||
provider.Name,
|
||||
provider.Host,
|
||||
provider.Port,
|
||||
provider.TLS,
|
||||
provider.Servers,
|
||||
provider.StartTLS,
|
||||
provider.BaseDN,
|
||||
provider.UserObjectClass,
|
||||
provider.UserUniqueAttribute,
|
||||
provider.Admin,
|
||||
provider.BindDN,
|
||||
secret,
|
||||
provider.UserBase,
|
||||
provider.UserObjectClasses,
|
||||
provider.UserFilters,
|
||||
provider.Timeout,
|
||||
provider.LDAPAttributes,
|
||||
provider.IDPOptions,
|
||||
),
|
||||
@ -1329,21 +1333,24 @@ func (c *Commands) prepareUpdateOrgLDAPProvider(a *org.Aggregate, writeModel *Or
|
||||
if provider.Name = strings.TrimSpace(provider.Name); provider.Name == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Sffgd", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Host = strings.TrimSpace(provider.Host); provider.Host == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Dz62d", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.BaseDN = strings.TrimSpace(provider.BaseDN); provider.BaseDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-vb3ss", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserObjectClass = strings.TrimSpace(provider.UserObjectClass); provider.UserObjectClass == "" {
|
||||
if provider.BindDN = strings.TrimSpace(provider.BindDN); provider.BindDN == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-hbere", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.UserUniqueAttribute = strings.TrimSpace(provider.UserUniqueAttribute); provider.UserUniqueAttribute == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-ASFt6", "Errors.Invalid.Argument")
|
||||
}
|
||||
if provider.Admin = strings.TrimSpace(provider.Admin); provider.Admin == "" {
|
||||
if provider.UserBase = strings.TrimSpace(provider.UserBase); provider.UserBase == "" {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-DG45z", "Errors.Invalid.Argument")
|
||||
}
|
||||
if len(provider.Servers) == 0 {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-Sxx945n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if len(provider.UserObjectClasses) == 0 {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-S1p605n", "Errors.Invalid.Argument")
|
||||
}
|
||||
if len(provider.UserFilters) == 0 {
|
||||
return nil, caos_errs.ThrowInvalidArgument(nil, "ORG-aBx901n", "Errors.Invalid.Argument")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
@ -1360,16 +1367,16 @@ func (c *Commands) prepareUpdateOrgLDAPProvider(a *org.Aggregate, writeModel *Or
|
||||
ctx,
|
||||
&a.Aggregate,
|
||||
writeModel.ID,
|
||||
writeModel.Name,
|
||||
provider.Name,
|
||||
provider.Host,
|
||||
provider.Port,
|
||||
provider.TLS,
|
||||
provider.Servers,
|
||||
provider.StartTLS,
|
||||
provider.BaseDN,
|
||||
provider.UserObjectClass,
|
||||
provider.UserUniqueAttribute,
|
||||
provider.Admin,
|
||||
provider.Password,
|
||||
provider.BindDN,
|
||||
provider.BindPassword,
|
||||
provider.UserBase,
|
||||
provider.UserObjectClasses,
|
||||
provider.UserFilters,
|
||||
provider.Timeout,
|
||||
c.idpConfigEncryption,
|
||||
provider.LDAPAttributes,
|
||||
provider.IDPOptions,
|
||||
|
@ -2,6 +2,7 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@ -754,16 +755,16 @@ func (wm *OrgLDAPIDPWriteModel) NewChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
oldName,
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password string,
|
||||
name string,
|
||||
servers []string,
|
||||
startTLS bool,
|
||||
baseDN string,
|
||||
bindDN string,
|
||||
bindPassword string,
|
||||
userBase string,
|
||||
userObjectClasses []string,
|
||||
userFilters []string,
|
||||
timeout time.Duration,
|
||||
secretCrypto crypto.Crypto,
|
||||
attributes idp.LDAPAttributes,
|
||||
options idp.Options,
|
||||
@ -771,14 +772,15 @@ func (wm *OrgLDAPIDPWriteModel) NewChangedEvent(
|
||||
|
||||
changes, err := wm.LDAPIDPWriteModel.NewChanges(
|
||||
name,
|
||||
host,
|
||||
port,
|
||||
tls,
|
||||
servers,
|
||||
startTLS,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin,
|
||||
password,
|
||||
bindDN,
|
||||
bindPassword,
|
||||
userBase,
|
||||
userObjectClasses,
|
||||
userFilters,
|
||||
timeout,
|
||||
secretCrypto,
|
||||
attributes,
|
||||
options,
|
||||
@ -786,7 +788,7 @@ func (wm *OrgLDAPIDPWriteModel) NewChangedEvent(
|
||||
if err != nil || len(changes) == 0 {
|
||||
return nil, err
|
||||
}
|
||||
return org.NewLDAPIDPChangedEvent(ctx, aggregate, id, oldName, changes)
|
||||
return org.NewLDAPIDPChangedEvent(ctx, aggregate, id, changes)
|
||||
}
|
||||
|
||||
type OrgIDPRemoveWriteModel struct {
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@ -17,7 +18,6 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/id"
|
||||
id_mock "github.com/zitadel/zitadel/internal/id/mock"
|
||||
"github.com/zitadel/zitadel/internal/repository/idp"
|
||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
)
|
||||
|
||||
@ -3734,25 +3734,6 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid host",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-SDVg2", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid baseDN",
|
||||
fields{
|
||||
@ -3764,7 +3745,6 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
},
|
||||
},
|
||||
res{
|
||||
@ -3774,7 +3754,7 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClass",
|
||||
"invalid binddn",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
@ -3784,7 +3764,6 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
@ -3794,51 +3773,6 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userUniqueAttribute",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-AEG2w", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid admin",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-SAD5n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid password",
|
||||
fields{
|
||||
@ -3849,17 +3783,108 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Name: "name",
|
||||
BindDN: "binddn",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-sdf5h", ""))
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-AEG2w", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userbase",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
BindDN: "binddn",
|
||||
BaseDN: "baseDN",
|
||||
BindPassword: "password",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-SAD5n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid servers",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
BindDN: "binddn",
|
||||
BaseDN: "baseDN",
|
||||
BindPassword: "password",
|
||||
UserBase: "user",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-SAy945n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClasses",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
BindDN: "binddn",
|
||||
BaseDN: "baseDN",
|
||||
BindPassword: "password",
|
||||
UserBase: "user",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-S1x705n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userFilters",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
BindDN: "binddn",
|
||||
BaseDN: "baseDN",
|
||||
BindPassword: "password",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-aAx9x1n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -3873,23 +3898,23 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"",
|
||||
[]string{"server"},
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
"dn",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
"user",
|
||||
[]string{"object"},
|
||||
[]string{"filter"},
|
||||
time.Second*30,
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
uniqueConstraintsFromEventConstraint(idpconfig.NewAddIDPConfigNameUniqueConstraint("name", "org1")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
@ -3899,13 +3924,16 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Password: "password",
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
StartTLS: false,
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "dn",
|
||||
BindPassword: "password",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
UserFilters: []string{"filter"},
|
||||
Timeout: time.Second * 30,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -3923,19 +3951,20 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
[]string{"server"},
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
"dn",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
"user",
|
||||
[]string{"object"},
|
||||
[]string{"filter"},
|
||||
time.Second*30,
|
||||
idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "firstName",
|
||||
@ -3958,7 +3987,6 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
IsAutoUpdate: true,
|
||||
},
|
||||
)),
|
||||
uniqueConstraintsFromEventConstraint(idpconfig.NewAddIDPConfigNameUniqueConstraint("name", "org1")),
|
||||
),
|
||||
),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
@ -3968,15 +3996,16 @@ func TestCommandSide_AddOrgLDAPIDP(t *testing.T) {
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
Port: "port",
|
||||
TLS: true,
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Password: "password",
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
StartTLS: false,
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "dn",
|
||||
BindPassword: "password",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
UserFilters: []string{"filter"},
|
||||
Timeout: time.Second * 30,
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "firstName",
|
||||
@ -4082,25 +4111,6 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid host",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-Dz62d", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid baseDN",
|
||||
fields{
|
||||
@ -4112,7 +4122,6 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
},
|
||||
},
|
||||
res{
|
||||
@ -4122,7 +4131,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClass",
|
||||
"invalid binddn",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
@ -4132,7 +4141,6 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
},
|
||||
},
|
||||
@ -4143,7 +4151,7 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userUniqueAttribute",
|
||||
"invalid userbase",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
@ -4152,33 +4160,9 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-ASFt6", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid admin",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Name: "name",
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "bindDN",
|
||||
},
|
||||
},
|
||||
res{
|
||||
@ -4187,6 +4171,75 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid servers",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "bindDN",
|
||||
UserBase: "user",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-Sxx945n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userObjectClasses",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "bindDN",
|
||||
UserBase: "user",
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-S1p605n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid userFilters",
|
||||
fields{
|
||||
eventstore: eventstoreExpect(t),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "bindDN",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowInvalidArgument(nil, "ORG-aBx901n", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
fields: fields{
|
||||
@ -4199,16 +4252,20 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
BaseDN: "baseDN",
|
||||
BindDN: "binddn",
|
||||
BindPassword: "password",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
UserFilters: []string{"filter"},
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: caos_errors.IsNotFound,
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, caos_errors.ThrowNotFound(nil, "ORG-ASF3F", ""))
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
@ -4220,19 +4277,20 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"",
|
||||
[]string{"server"},
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
"basedn",
|
||||
"binddn",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
"user",
|
||||
[]string{"object"},
|
||||
[]string{"filter"},
|
||||
time.Second*30,
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
@ -4244,12 +4302,14 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "name",
|
||||
Host: "host",
|
||||
BaseDN: "baseDN",
|
||||
UserObjectClass: "userObjectClass",
|
||||
UserUniqueAttribute: "userUniqueAttribute",
|
||||
Admin: "admin",
|
||||
Name: "name",
|
||||
Servers: []string{"server"},
|
||||
BaseDN: "basedn",
|
||||
BindDN: "binddn",
|
||||
UserObjectClasses: []string{"object"},
|
||||
UserFilters: []string{"filter"},
|
||||
UserBase: "user",
|
||||
Timeout: time.Second * 30,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@ -4265,19 +4325,20 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
org.NewLDAPIDPAddedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
"host",
|
||||
"port",
|
||||
[]string{"server"},
|
||||
false,
|
||||
"baseDN",
|
||||
"userObjectClass",
|
||||
"userUniqueAttribute",
|
||||
"admin",
|
||||
"basedn",
|
||||
"binddn",
|
||||
&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("password"),
|
||||
},
|
||||
"user",
|
||||
[]string{"object"},
|
||||
[]string{"filter"},
|
||||
time.Second*30,
|
||||
idp.LDAPAttributes{},
|
||||
idp.Options{},
|
||||
)),
|
||||
@ -4288,22 +4349,22 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
t := true
|
||||
event, _ := org.NewLDAPIDPChangedEvent(context.Background(), &org.NewAggregate("org1").Aggregate,
|
||||
"id1",
|
||||
"name",
|
||||
[]idp.LDAPIDPChanges{
|
||||
idp.ChangeLDAPName("new name"),
|
||||
idp.ChangeLDAPHost("new host"),
|
||||
idp.ChangeLDAPPort("new port"),
|
||||
idp.ChangeLDAPTLS(true),
|
||||
idp.ChangeLDAPBaseDN("new baseDN"),
|
||||
idp.ChangeLDAPUserObjectClass("new userObjectClass"),
|
||||
idp.ChangeLDAPUserUniqueAttribute("new userUniqueAttribute"),
|
||||
idp.ChangeLDAPAdmin("new admin"),
|
||||
idp.ChangeLDAPPassword(&crypto.CryptoValue{
|
||||
idp.ChangeLDAPServers([]string{"new server"}),
|
||||
idp.ChangeLDAPStartTLS(true),
|
||||
idp.ChangeLDAPBaseDN("new basedn"),
|
||||
idp.ChangeLDAPBindDN("new binddn"),
|
||||
idp.ChangeLDAPBindPassword(&crypto.CryptoValue{
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("new password"),
|
||||
}),
|
||||
idp.ChangeLDAPUserBase("new user"),
|
||||
idp.ChangeLDAPUserObjectClasses([]string{"new object"}),
|
||||
idp.ChangeLDAPUserFilters([]string{"new filter"}),
|
||||
idp.ChangeLDAPTimeout(time.Second * 20),
|
||||
idp.ChangeLDAPAttributes(idp.LDAPAttributeChanges{
|
||||
IDAttribute: stringPointer("new id"),
|
||||
FirstNameAttribute: stringPointer("new firstName"),
|
||||
@ -4330,8 +4391,6 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
return event
|
||||
}(),
|
||||
),
|
||||
uniqueConstraintsFromEventConstraint(idpconfig.NewRemoveIDPConfigNameUniqueConstraint("name", "org1")),
|
||||
uniqueConstraintsFromEventConstraint(idpconfig.NewAddIDPConfigNameUniqueConstraint("new name", "org1")),
|
||||
),
|
||||
),
|
||||
secretCrypto: crypto.CreateMockEncryptionAlg(gomock.NewController(t)),
|
||||
@ -4341,15 +4400,16 @@ func TestCommandSide_UpdateOrgLDAPIDP(t *testing.T) {
|
||||
resourceOwner: "org1",
|
||||
id: "id1",
|
||||
provider: LDAPProvider{
|
||||
Name: "new name",
|
||||
Host: "new host",
|
||||
Port: "new port",
|
||||
TLS: true,
|
||||
BaseDN: "new baseDN",
|
||||
UserObjectClass: "new userObjectClass",
|
||||
UserUniqueAttribute: "new userUniqueAttribute",
|
||||
Admin: "new admin",
|
||||
Password: "new password",
|
||||
Name: "new name",
|
||||
Servers: []string{"new server"},
|
||||
StartTLS: true,
|
||||
BaseDN: "new basedn",
|
||||
BindDN: "new binddn",
|
||||
BindPassword: "new password",
|
||||
UserBase: "new user",
|
||||
UserObjectClasses: []string{"new object"},
|
||||
UserFilters: []string{"new filter"},
|
||||
Timeout: time.Second * 20,
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "new id",
|
||||
FirstNameAttribute: "new firstName",
|
||||
|
@ -2,6 +2,7 @@ package ldap
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/idp"
|
||||
)
|
||||
@ -12,16 +13,18 @@ var _ idp.Provider = (*Provider)(nil)
|
||||
|
||||
// Provider is the [idp.Provider] implementation for a generic LDAP provider
|
||||
type Provider struct {
|
||||
name string
|
||||
host string
|
||||
port string
|
||||
tls bool
|
||||
baseDN string
|
||||
userObjectClass string
|
||||
userUniqueAttribute string
|
||||
admin string
|
||||
password string
|
||||
loginUrl string
|
||||
name string
|
||||
servers []string
|
||||
startTLS bool
|
||||
baseDN string
|
||||
bindDN string
|
||||
bindPassword string
|
||||
userBase string
|
||||
userObjectClasses []string
|
||||
userFilters []string
|
||||
timeout time.Duration
|
||||
|
||||
loginUrl string
|
||||
|
||||
isLinkingAllowed bool
|
||||
isCreationAllowed bool
|
||||
@ -74,17 +77,10 @@ func WithAutoUpdate() ProviderOpts {
|
||||
}
|
||||
}
|
||||
|
||||
// WithCustomPort configures a custom port used for the communication instead of :389 as per default
|
||||
func WithCustomPort(port string) ProviderOpts {
|
||||
// WithoutStartTLS configures to communication insecure with the LDAP server without startTLS
|
||||
func WithoutStartTLS() ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.port = port
|
||||
}
|
||||
}
|
||||
|
||||
// Insecure configures to communication insecure with the LDAP server without TLS
|
||||
func Insecure() ProviderOpts {
|
||||
return func(p *Provider) {
|
||||
p.tls = false
|
||||
p.startTLS = false
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,27 +177,29 @@ func WithProfileAttribute(name string) ProviderOpts {
|
||||
|
||||
func New(
|
||||
name string,
|
||||
host string,
|
||||
servers []string,
|
||||
baseDN string,
|
||||
userObjectClass string,
|
||||
userUniqueAttribute string,
|
||||
admin string,
|
||||
password string,
|
||||
bindDN string,
|
||||
bindPassword string,
|
||||
userBase string,
|
||||
userObjectClasses []string,
|
||||
userFilters []string,
|
||||
timeout time.Duration,
|
||||
loginUrl string,
|
||||
options ...ProviderOpts,
|
||||
) *Provider {
|
||||
provider := &Provider{
|
||||
name: name,
|
||||
host: host,
|
||||
port: DefaultPort,
|
||||
tls: true,
|
||||
baseDN: baseDN,
|
||||
userObjectClass: userObjectClass,
|
||||
userUniqueAttribute: userUniqueAttribute,
|
||||
admin: admin,
|
||||
password: password,
|
||||
loginUrl: loginUrl,
|
||||
idAttribute: userUniqueAttribute,
|
||||
name: name,
|
||||
servers: servers,
|
||||
startTLS: true,
|
||||
baseDN: baseDN,
|
||||
bindDN: bindDN,
|
||||
bindPassword: bindPassword,
|
||||
userBase: userBase,
|
||||
userObjectClasses: userObjectClasses,
|
||||
userFilters: userFilters,
|
||||
timeout: timeout,
|
||||
loginUrl: loginUrl,
|
||||
}
|
||||
for _, option := range options {
|
||||
option(provider)
|
||||
@ -216,7 +214,7 @@ func (p *Provider) Name() string {
|
||||
func (p *Provider) BeginAuth(ctx context.Context, state string, params ...any) (idp.Session, error) {
|
||||
return &Session{
|
||||
Provider: p,
|
||||
loginUrl: p.loginUrl + "?state=" + state,
|
||||
loginUrl: p.loginUrl + state,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -235,3 +233,47 @@ func (p *Provider) IsAutoCreation() bool {
|
||||
func (p *Provider) IsAutoUpdate() bool {
|
||||
return p.isAutoUpdate
|
||||
}
|
||||
|
||||
func (p *Provider) getNecessaryAttributes() []string {
|
||||
attributes := []string{p.userBase}
|
||||
if p.idAttribute != "" {
|
||||
attributes = append(attributes, p.idAttribute)
|
||||
}
|
||||
if p.firstNameAttribute != "" {
|
||||
attributes = append(attributes, p.firstNameAttribute)
|
||||
}
|
||||
if p.lastNameAttribute != "" {
|
||||
attributes = append(attributes, p.lastNameAttribute)
|
||||
}
|
||||
if p.displayNameAttribute != "" {
|
||||
attributes = append(attributes, p.displayNameAttribute)
|
||||
}
|
||||
if p.nickNameAttribute != "" {
|
||||
attributes = append(attributes, p.nickNameAttribute)
|
||||
}
|
||||
if p.preferredUsernameAttribute != "" {
|
||||
attributes = append(attributes, p.preferredUsernameAttribute)
|
||||
}
|
||||
if p.emailAttribute != "" {
|
||||
attributes = append(attributes, p.emailAttribute)
|
||||
}
|
||||
if p.emailVerifiedAttribute != "" {
|
||||
attributes = append(attributes, p.emailVerifiedAttribute)
|
||||
}
|
||||
if p.phoneAttribute != "" {
|
||||
attributes = append(attributes, p.phoneAttribute)
|
||||
}
|
||||
if p.phoneVerifiedAttribute != "" {
|
||||
attributes = append(attributes, p.phoneVerifiedAttribute)
|
||||
}
|
||||
if p.preferredLanguageAttribute != "" {
|
||||
attributes = append(attributes, p.preferredLanguageAttribute)
|
||||
}
|
||||
if p.avatarURLAttribute != "" {
|
||||
attributes = append(attributes, p.avatarURLAttribute)
|
||||
}
|
||||
if p.profileAttribute != "" {
|
||||
attributes = append(attributes, p.profileAttribute)
|
||||
}
|
||||
return attributes
|
||||
}
|
||||
|
@ -2,26 +2,28 @@ package ldap
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestProvider_Options(t *testing.T) {
|
||||
type fields struct {
|
||||
name string
|
||||
host string
|
||||
baseDN string
|
||||
userObjectClass string
|
||||
userUniqueAttribute string
|
||||
admin string
|
||||
password string
|
||||
loginUrl string
|
||||
opts []ProviderOpts
|
||||
name string
|
||||
servers []string
|
||||
baseDN string
|
||||
bindDN string
|
||||
bindPassword string
|
||||
userBase string
|
||||
userObjectClasses []string
|
||||
userFilters []string
|
||||
timeout time.Duration
|
||||
loginUrl string
|
||||
opts []ProviderOpts
|
||||
}
|
||||
type want struct {
|
||||
name string
|
||||
port string
|
||||
tls bool
|
||||
startTls bool
|
||||
linkingAllowed bool
|
||||
creationAllowed bool
|
||||
autoCreation bool
|
||||
@ -48,39 +50,43 @@ func TestProvider_Options(t *testing.T) {
|
||||
{
|
||||
name: "default",
|
||||
fields: fields{
|
||||
name: "ldap",
|
||||
host: "host",
|
||||
baseDN: "base",
|
||||
userObjectClass: "class",
|
||||
userUniqueAttribute: "attr",
|
||||
admin: "admin",
|
||||
password: "password",
|
||||
loginUrl: "url",
|
||||
opts: nil,
|
||||
name: "ldap",
|
||||
servers: []string{"server"},
|
||||
baseDN: "base",
|
||||
bindDN: "binddn",
|
||||
bindPassword: "password",
|
||||
userBase: "user",
|
||||
userObjectClasses: []string{"object"},
|
||||
userFilters: []string{"filter"},
|
||||
timeout: 30 * time.Second,
|
||||
loginUrl: "url",
|
||||
opts: nil,
|
||||
},
|
||||
want: want{
|
||||
name: "ldap",
|
||||
port: DefaultPort,
|
||||
tls: true,
|
||||
startTls: true,
|
||||
linkingAllowed: false,
|
||||
creationAllowed: false,
|
||||
autoCreation: false,
|
||||
autoUpdate: false,
|
||||
idAttribute: "attr",
|
||||
idAttribute: "",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "all true",
|
||||
fields: fields{
|
||||
name: "ldap",
|
||||
host: "host",
|
||||
baseDN: "base",
|
||||
userObjectClass: "class",
|
||||
userUniqueAttribute: "attr",
|
||||
admin: "admin",
|
||||
password: "password",
|
||||
loginUrl: "url",
|
||||
name: "ldap",
|
||||
servers: []string{"server"},
|
||||
baseDN: "base",
|
||||
bindDN: "binddn",
|
||||
bindPassword: "password",
|
||||
userBase: "user",
|
||||
userObjectClasses: []string{"object"},
|
||||
userFilters: []string{"filter"},
|
||||
timeout: 30 * time.Second,
|
||||
loginUrl: "url",
|
||||
opts: []ProviderOpts{
|
||||
WithoutStartTLS(),
|
||||
WithLinkingAllowed(),
|
||||
WithCreationAllowed(),
|
||||
WithAutoCreation(),
|
||||
@ -89,28 +95,28 @@ func TestProvider_Options(t *testing.T) {
|
||||
},
|
||||
want: want{
|
||||
name: "ldap",
|
||||
port: DefaultPort,
|
||||
tls: true,
|
||||
startTls: false,
|
||||
linkingAllowed: true,
|
||||
creationAllowed: true,
|
||||
autoCreation: true,
|
||||
autoUpdate: true,
|
||||
idAttribute: "attr",
|
||||
idAttribute: "",
|
||||
},
|
||||
}, {
|
||||
name: "all true, attributes set",
|
||||
fields: fields{
|
||||
name: "ldap",
|
||||
host: "host",
|
||||
baseDN: "base",
|
||||
userObjectClass: "class",
|
||||
userUniqueAttribute: "attr",
|
||||
admin: "admin",
|
||||
password: "password",
|
||||
loginUrl: "url",
|
||||
name: "ldap",
|
||||
servers: []string{"server"},
|
||||
baseDN: "base",
|
||||
bindDN: "binddn",
|
||||
bindPassword: "password",
|
||||
userBase: "user",
|
||||
userObjectClasses: []string{"object"},
|
||||
userFilters: []string{"filter"},
|
||||
timeout: 30 * time.Second,
|
||||
loginUrl: "url",
|
||||
opts: []ProviderOpts{
|
||||
Insecure(),
|
||||
WithCustomPort("port"),
|
||||
WithoutStartTLS(),
|
||||
WithLinkingAllowed(),
|
||||
WithCreationAllowed(),
|
||||
WithAutoCreation(),
|
||||
@ -132,8 +138,7 @@ func TestProvider_Options(t *testing.T) {
|
||||
},
|
||||
want: want{
|
||||
name: "ldap",
|
||||
port: "port",
|
||||
tls: false,
|
||||
startTls: false,
|
||||
linkingAllowed: true,
|
||||
creationAllowed: true,
|
||||
autoCreation: true,
|
||||
@ -157,11 +162,22 @@ func TestProvider_Options(t *testing.T) {
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
provider := New(tt.fields.name, tt.fields.host, tt.fields.baseDN, tt.fields.userObjectClass, tt.fields.userUniqueAttribute, tt.fields.admin, tt.fields.password, tt.fields.loginUrl, tt.fields.opts...)
|
||||
provider := New(
|
||||
tt.fields.name,
|
||||
tt.fields.servers,
|
||||
tt.fields.baseDN,
|
||||
tt.fields.bindDN,
|
||||
tt.fields.bindPassword,
|
||||
tt.fields.userBase,
|
||||
tt.fields.userObjectClasses,
|
||||
tt.fields.userFilters,
|
||||
tt.fields.timeout,
|
||||
tt.fields.loginUrl,
|
||||
tt.fields.opts...,
|
||||
)
|
||||
|
||||
a.Equal(tt.want.name, provider.Name())
|
||||
a.Equal(tt.want.port, provider.port)
|
||||
a.Equal(tt.want.tls, provider.tls)
|
||||
a.Equal(tt.want.startTls, provider.startTLS)
|
||||
a.Equal(tt.want.linkingAllowed, provider.IsLinkingAllowed())
|
||||
a.Equal(tt.want.creationAllowed, provider.IsCreationAllowed())
|
||||
a.Equal(tt.want.autoCreation, provider.IsAutoCreation())
|
||||
|
@ -4,8 +4,10 @@ import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"golang.org/x/text/language"
|
||||
@ -15,49 +17,154 @@ import (
|
||||
)
|
||||
|
||||
var ErrNoSingleUser = errors.New("user does not exist or too many entries returned")
|
||||
var ErrFailedLogin = errors.New("user failed to login")
|
||||
|
||||
var _ idp.Session = (*Session)(nil)
|
||||
|
||||
type Session struct {
|
||||
Provider *Provider
|
||||
loginUrl string
|
||||
user string
|
||||
password string
|
||||
User string
|
||||
Password string
|
||||
}
|
||||
|
||||
func (s *Session) GetAuthURL() string {
|
||||
return s.loginUrl
|
||||
}
|
||||
func (s *Session) FetchUser(_ context.Context) (idp.User, error) {
|
||||
l, err := ldap.DialURL("ldap://" + s.Provider.host + ":" + s.Provider.port)
|
||||
|
||||
func (s *Session) FetchUser(_ context.Context) (_ idp.User, err error) {
|
||||
var user *ldap.Entry
|
||||
for _, server := range s.Provider.servers {
|
||||
user, err = tryBind(server,
|
||||
s.Provider.startTLS,
|
||||
s.Provider.bindDN,
|
||||
s.Provider.bindPassword,
|
||||
s.Provider.baseDN,
|
||||
s.Provider.getNecessaryAttributes(),
|
||||
s.Provider.userObjectClasses,
|
||||
s.Provider.userFilters,
|
||||
s.User,
|
||||
s.Password, s.Provider.timeout)
|
||||
// If there were invalid credentials or multiple users with the credentials cancel process
|
||||
if err != nil && (errors.Is(err, ErrFailedLogin) || errors.Is(err, ErrNoSingleUser)) {
|
||||
return nil, err
|
||||
}
|
||||
// If a user bind was successful and user is filled continue with login, otherwise try next server
|
||||
if err == nil && user != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer l.Close()
|
||||
|
||||
if s.Provider.tls {
|
||||
err = l.StartTLS(&tls.Config{ServerName: s.Provider.host})
|
||||
return mapLDAPEntryToUser(
|
||||
user,
|
||||
s.Provider.idAttribute,
|
||||
s.Provider.firstNameAttribute,
|
||||
s.Provider.lastNameAttribute,
|
||||
s.Provider.displayNameAttribute,
|
||||
s.Provider.nickNameAttribute,
|
||||
s.Provider.preferredUsernameAttribute,
|
||||
s.Provider.emailAttribute,
|
||||
s.Provider.emailVerifiedAttribute,
|
||||
s.Provider.phoneAttribute,
|
||||
s.Provider.phoneVerifiedAttribute,
|
||||
s.Provider.preferredLanguageAttribute,
|
||||
s.Provider.avatarURLAttribute,
|
||||
s.Provider.profileAttribute,
|
||||
)
|
||||
}
|
||||
|
||||
func tryBind(
|
||||
server string,
|
||||
startTLS bool,
|
||||
bindDN string,
|
||||
bindPassword string,
|
||||
baseDN string,
|
||||
attributes []string,
|
||||
objectClasses []string,
|
||||
userFilters []string,
|
||||
username string,
|
||||
password string,
|
||||
timeout time.Duration,
|
||||
) (*ldap.Entry, error) {
|
||||
conn, err := getConnection(server, startTLS, timeout)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
if err := conn.Bind(bindDN, bindPassword); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return trySearchAndUserBind(
|
||||
conn,
|
||||
baseDN,
|
||||
attributes,
|
||||
objectClasses,
|
||||
userFilters,
|
||||
username,
|
||||
password,
|
||||
timeout,
|
||||
)
|
||||
}
|
||||
|
||||
func getConnection(
|
||||
server string,
|
||||
startTLS bool,
|
||||
timeout time.Duration,
|
||||
) (*ldap.Conn, error) {
|
||||
if timeout == 0 {
|
||||
timeout = ldap.DefaultTimeout
|
||||
}
|
||||
|
||||
conn, err := ldap.DialURL(server, ldap.DialWithDialer(&net.Dialer{Timeout: timeout}))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u, err := url.Parse(server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if u.Scheme == "ldaps" && startTLS {
|
||||
err = conn.StartTLS(&tls.Config{ServerName: u.Host})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
// Bind as the admin to search for user
|
||||
err = l.Bind("cn="+s.Provider.admin+","+s.Provider.baseDN, s.Provider.password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func trySearchAndUserBind(
|
||||
conn *ldap.Conn,
|
||||
baseDN string,
|
||||
attributes []string,
|
||||
objectClasses []string,
|
||||
userFilters []string,
|
||||
username string,
|
||||
password string,
|
||||
timeout time.Duration,
|
||||
) (*ldap.Entry, error) {
|
||||
searchQuery := queriesAndToSearchQuery(
|
||||
objectClassesToSearchQuery(objectClasses),
|
||||
queriesOrToSearchQuery(
|
||||
userFiltersToSearchQuery(userFilters, username),
|
||||
),
|
||||
)
|
||||
|
||||
// Search for user with the unique attribute for the userDN
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
s.Provider.baseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
fmt.Sprintf("(&(objectClass="+s.Provider.userObjectClass+")("+s.Provider.userUniqueAttribute+"=%s))", ldap.EscapeFilter(s.user)),
|
||||
[]string{"dn"},
|
||||
baseDN,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, int(timeout.Seconds()), false,
|
||||
searchQuery,
|
||||
attributes,
|
||||
nil,
|
||||
)
|
||||
|
||||
sr, err := l.Search(searchRequest)
|
||||
sr, err := conn.Search(searchRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -67,33 +174,100 @@ func (s *Session) FetchUser(_ context.Context) (idp.User, error) {
|
||||
|
||||
user := sr.Entries[0]
|
||||
// Bind as the user to verify their password
|
||||
err = l.Bind(user.DN, s.password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if err = conn.Bind(user.DN, password); err != nil {
|
||||
return nil, ErrFailedLogin
|
||||
}
|
||||
return user, nil
|
||||
}
|
||||
|
||||
emailVerified, err := strconv.ParseBool(user.GetAttributeValue(s.Provider.emailVerifiedAttribute))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
func queriesAndToSearchQuery(queries ...string) string {
|
||||
if len(queries) == 0 {
|
||||
return ""
|
||||
}
|
||||
phoneVerified, err := strconv.ParseBool(user.GetAttributeValue(s.Provider.phoneVerifiedAttribute))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if len(queries) == 1 {
|
||||
return queries[0]
|
||||
}
|
||||
joinQueries := "(&"
|
||||
for _, s := range queries {
|
||||
joinQueries += s
|
||||
}
|
||||
return joinQueries + ")"
|
||||
}
|
||||
|
||||
func queriesOrToSearchQuery(queries ...string) string {
|
||||
if len(queries) == 0 {
|
||||
return ""
|
||||
}
|
||||
if len(queries) == 1 {
|
||||
return queries[0]
|
||||
}
|
||||
joinQueries := "(|"
|
||||
for _, s := range queries {
|
||||
joinQueries += s
|
||||
}
|
||||
return joinQueries + ")"
|
||||
}
|
||||
|
||||
func objectClassesToSearchQuery(classes []string) string {
|
||||
searchQuery := ""
|
||||
for _, class := range classes {
|
||||
searchQuery += "(objectClass=" + class + ")"
|
||||
}
|
||||
return searchQuery
|
||||
}
|
||||
|
||||
func userFiltersToSearchQuery(filters []string, username string) string {
|
||||
searchQuery := ""
|
||||
for _, filter := range filters {
|
||||
searchQuery += "(" + filter + "=" + ldap.EscapeFilter(username) + ")"
|
||||
}
|
||||
return searchQuery
|
||||
}
|
||||
|
||||
func mapLDAPEntryToUser(
|
||||
user *ldap.Entry,
|
||||
idAttribute,
|
||||
firstNameAttribute,
|
||||
lastNameAttribute,
|
||||
displayNameAttribute,
|
||||
nickNameAttribute,
|
||||
preferredUsernameAttribute,
|
||||
emailAttribute,
|
||||
emailVerifiedAttribute,
|
||||
phoneAttribute,
|
||||
phoneVerifiedAttribute,
|
||||
preferredLanguageAttribute,
|
||||
avatarURLAttribute,
|
||||
profileAttribute string,
|
||||
) (_ *User, err error) {
|
||||
var emailVerified bool
|
||||
if v := user.GetAttributeValue(emailVerifiedAttribute); v != "" {
|
||||
emailVerified, err = strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
var phoneVerified bool
|
||||
if v := user.GetAttributeValue(phoneVerifiedAttribute); v != "" {
|
||||
phoneVerified, err = strconv.ParseBool(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return NewUser(
|
||||
user.GetAttributeValue(s.Provider.idAttribute),
|
||||
user.GetAttributeValue(s.Provider.firstNameAttribute),
|
||||
user.GetAttributeValue(s.Provider.lastNameAttribute),
|
||||
user.GetAttributeValue(s.Provider.displayNameAttribute),
|
||||
user.GetAttributeValue(s.Provider.nickNameAttribute),
|
||||
user.GetAttributeValue(s.Provider.preferredUsernameAttribute),
|
||||
domain.EmailAddress(user.GetAttributeValue(s.Provider.emailAttribute)),
|
||||
user.GetAttributeValue(idAttribute),
|
||||
user.GetAttributeValue(firstNameAttribute),
|
||||
user.GetAttributeValue(lastNameAttribute),
|
||||
user.GetAttributeValue(displayNameAttribute),
|
||||
user.GetAttributeValue(nickNameAttribute),
|
||||
user.GetAttributeValue(preferredUsernameAttribute),
|
||||
domain.EmailAddress(user.GetAttributeValue(emailAttribute)),
|
||||
emailVerified,
|
||||
domain.PhoneNumber(user.GetAttributeValue(s.Provider.phoneAttribute)),
|
||||
domain.PhoneNumber(user.GetAttributeValue(phoneAttribute)),
|
||||
phoneVerified,
|
||||
language.Make(user.GetAttributeValue(s.Provider.preferredLanguageAttribute)),
|
||||
user.GetAttributeValue(s.Provider.avatarURLAttribute),
|
||||
user.GetAttributeValue(s.Provider.profileAttribute),
|
||||
language.Make(user.GetAttributeValue(preferredLanguageAttribute)),
|
||||
user.GetAttributeValue(avatarURLAttribute),
|
||||
user.GetAttributeValue(profileAttribute),
|
||||
), nil
|
||||
}
|
||||
|
400
internal/idp/providers/ldap/session_test.go
Normal file
400
internal/idp/providers/ldap/session_test.go
Normal file
@ -0,0 +1,400 @@
|
||||
package ldap
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func TestProvider_objectClassesToSearchQuery(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fields []string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "zero",
|
||||
fields: []string{},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "one",
|
||||
fields: []string{"test"},
|
||||
want: "(objectClass=test)",
|
||||
},
|
||||
{
|
||||
name: "three",
|
||||
fields: []string{"test1", "test2", "test3"},
|
||||
want: "(objectClass=test1)(objectClass=test2)(objectClass=test3)",
|
||||
},
|
||||
{
|
||||
name: "five",
|
||||
fields: []string{"test1", "test2", "test3", "test4", "test5"},
|
||||
want: "(objectClass=test1)(objectClass=test2)(objectClass=test3)(objectClass=test4)(objectClass=test5)",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
|
||||
a.Equal(tt.want, objectClassesToSearchQuery(tt.fields))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider_userFiltersToSearchQuery(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fields []string
|
||||
username string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "zero",
|
||||
fields: []string{},
|
||||
username: "user",
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "one",
|
||||
fields: []string{"test"},
|
||||
username: "user",
|
||||
want: "(test=user)",
|
||||
},
|
||||
{
|
||||
name: "three",
|
||||
fields: []string{"test1", "test2", "test3"},
|
||||
username: "user",
|
||||
want: "(test1=user)(test2=user)(test3=user)",
|
||||
},
|
||||
{
|
||||
name: "five",
|
||||
fields: []string{"test1", "test2", "test3", "test4", "test5"},
|
||||
username: "user",
|
||||
want: "(test1=user)(test2=user)(test3=user)(test4=user)(test5=user)",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
|
||||
a.Equal(tt.want, userFiltersToSearchQuery(tt.fields, tt.username))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider_queriesAndToSearchQuery(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fields []string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "zero",
|
||||
fields: []string{},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "one",
|
||||
fields: []string{"(test)"},
|
||||
want: "(test)",
|
||||
},
|
||||
{
|
||||
name: "three",
|
||||
fields: []string{"(test1)", "(test2)", "(test3)"},
|
||||
want: "(&(test1)(test2)(test3))",
|
||||
},
|
||||
{
|
||||
name: "five",
|
||||
fields: []string{"(test1)", "(test2)", "(test3)", "(test4)", "(test5)"},
|
||||
want: "(&(test1)(test2)(test3)(test4)(test5))",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
|
||||
a.Equal(tt.want, queriesAndToSearchQuery(tt.fields...))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider_queriesOrToSearchQuery(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
fields []string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
name: "zero",
|
||||
fields: []string{},
|
||||
want: "",
|
||||
},
|
||||
{
|
||||
name: "one",
|
||||
fields: []string{"(test)"},
|
||||
want: "(test)",
|
||||
},
|
||||
{
|
||||
name: "three",
|
||||
fields: []string{"(test1)", "(test2)", "(test3)"},
|
||||
want: "(|(test1)(test2)(test3))",
|
||||
},
|
||||
{
|
||||
name: "five",
|
||||
fields: []string{"(test1)", "(test2)", "(test3)", "(test4)", "(test5)"},
|
||||
want: "(|(test1)(test2)(test3)(test4)(test5))",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
a := assert.New(t)
|
||||
|
||||
a.Equal(tt.want, queriesOrToSearchQuery(tt.fields...))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProvider_mapLDAPEntryToUser(t *testing.T) {
|
||||
type fields struct {
|
||||
user *ldap.Entry
|
||||
idAttribute string
|
||||
firstNameAttribute string
|
||||
lastNameAttribute string
|
||||
displayNameAttribute string
|
||||
nickNameAttribute string
|
||||
preferredUsernameAttribute string
|
||||
emailAttribute string
|
||||
emailVerifiedAttribute string
|
||||
phoneAttribute string
|
||||
phoneVerifiedAttribute string
|
||||
preferredLanguageAttribute string
|
||||
avatarURLAttribute string
|
||||
profileAttribute string
|
||||
}
|
||||
type want struct {
|
||||
user *User
|
||||
err func(error) bool
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
fields fields
|
||||
want want
|
||||
}{
|
||||
{
|
||||
name: "empty",
|
||||
fields: fields{
|
||||
user: &ldap.Entry{
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{Name: "id", Values: []string{"id"}},
|
||||
{Name: "first", Values: []string{"first"}},
|
||||
{Name: "last", Values: []string{"last"}},
|
||||
{Name: "display", Values: []string{"display"}},
|
||||
{Name: "nick", Values: []string{"nick"}},
|
||||
{Name: "preferred", Values: []string{"preferred"}},
|
||||
{Name: "email", Values: []string{"email"}},
|
||||
{Name: "emailVerified", Values: []string{"false"}},
|
||||
{Name: "phone", Values: []string{"phone"}},
|
||||
{Name: "phoneVerified", Values: []string{"false"}},
|
||||
{Name: "lang", Values: []string{"und"}},
|
||||
{Name: "avatar", Values: []string{"avatar"}},
|
||||
{Name: "profile", Values: []string{"profile"}},
|
||||
},
|
||||
},
|
||||
idAttribute: "",
|
||||
firstNameAttribute: "",
|
||||
lastNameAttribute: "",
|
||||
displayNameAttribute: "",
|
||||
nickNameAttribute: "",
|
||||
preferredUsernameAttribute: "",
|
||||
emailAttribute: "",
|
||||
emailVerifiedAttribute: "",
|
||||
phoneAttribute: "",
|
||||
phoneVerifiedAttribute: "",
|
||||
preferredLanguageAttribute: "",
|
||||
avatarURLAttribute: "",
|
||||
profileAttribute: "",
|
||||
},
|
||||
want: want{
|
||||
user: &User{
|
||||
id: "",
|
||||
firstName: "",
|
||||
lastName: "",
|
||||
displayName: "",
|
||||
nickName: "",
|
||||
preferredUsername: "",
|
||||
email: "",
|
||||
emailVerified: false,
|
||||
phone: "",
|
||||
phoneVerified: false,
|
||||
preferredLanguage: language.Tag{},
|
||||
avatarURL: "",
|
||||
profile: "",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "failed parse emailVerified",
|
||||
fields: fields{
|
||||
user: &ldap.Entry{
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{Name: "id", Values: []string{"id"}},
|
||||
{Name: "first", Values: []string{"first"}},
|
||||
{Name: "last", Values: []string{"last"}},
|
||||
{Name: "display", Values: []string{"display"}},
|
||||
{Name: "nick", Values: []string{"nick"}},
|
||||
{Name: "preferred", Values: []string{"preferred"}},
|
||||
{Name: "email", Values: []string{"email"}},
|
||||
{Name: "emailVerified", Values: []string{"failure"}},
|
||||
{Name: "phone", Values: []string{"phone"}},
|
||||
{Name: "phoneVerified", Values: []string{"false"}},
|
||||
{Name: "lang", Values: []string{"und"}},
|
||||
{Name: "avatar", Values: []string{"avatar"}},
|
||||
{Name: "profile", Values: []string{"profile"}},
|
||||
},
|
||||
},
|
||||
idAttribute: "id",
|
||||
firstNameAttribute: "first",
|
||||
lastNameAttribute: "last",
|
||||
displayNameAttribute: "display",
|
||||
nickNameAttribute: "nick",
|
||||
preferredUsernameAttribute: "preferred",
|
||||
emailAttribute: "email",
|
||||
emailVerifiedAttribute: "emailVerified",
|
||||
phoneAttribute: "phone",
|
||||
phoneVerifiedAttribute: "phoneVerified",
|
||||
preferredLanguageAttribute: "lang",
|
||||
avatarURLAttribute: "avatar",
|
||||
profileAttribute: "profile",
|
||||
},
|
||||
want: want{
|
||||
err: func(err error) bool {
|
||||
return err != nil
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "failed parse phoneVerified",
|
||||
fields: fields{
|
||||
user: &ldap.Entry{
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{Name: "id", Values: []string{"id"}},
|
||||
{Name: "first", Values: []string{"first"}},
|
||||
{Name: "last", Values: []string{"last"}},
|
||||
{Name: "display", Values: []string{"display"}},
|
||||
{Name: "nick", Values: []string{"nick"}},
|
||||
{Name: "preferred", Values: []string{"preferred"}},
|
||||
{Name: "email", Values: []string{"email"}},
|
||||
{Name: "emailVerified", Values: []string{"false"}},
|
||||
{Name: "phone", Values: []string{"phone"}},
|
||||
{Name: "phoneVerified", Values: []string{"failure"}},
|
||||
{Name: "lang", Values: []string{"und"}},
|
||||
{Name: "avatar", Values: []string{"avatar"}},
|
||||
{Name: "profile", Values: []string{"profile"}},
|
||||
},
|
||||
},
|
||||
idAttribute: "id",
|
||||
firstNameAttribute: "first",
|
||||
lastNameAttribute: "last",
|
||||
displayNameAttribute: "display",
|
||||
nickNameAttribute: "nick",
|
||||
preferredUsernameAttribute: "preferred",
|
||||
emailAttribute: "email",
|
||||
emailVerifiedAttribute: "emailVerified",
|
||||
phoneAttribute: "phone",
|
||||
phoneVerifiedAttribute: "phoneVerified",
|
||||
preferredLanguageAttribute: "lang",
|
||||
avatarURLAttribute: "avatar",
|
||||
profileAttribute: "profile",
|
||||
},
|
||||
want: want{
|
||||
err: func(err error) bool {
|
||||
return err != nil
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "full user",
|
||||
fields: fields{
|
||||
user: &ldap.Entry{
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{Name: "id", Values: []string{"id"}},
|
||||
{Name: "first", Values: []string{"first"}},
|
||||
{Name: "last", Values: []string{"last"}},
|
||||
{Name: "display", Values: []string{"display"}},
|
||||
{Name: "nick", Values: []string{"nick"}},
|
||||
{Name: "preferred", Values: []string{"preferred"}},
|
||||
{Name: "email", Values: []string{"email"}},
|
||||
{Name: "emailVerified", Values: []string{"false"}},
|
||||
{Name: "phone", Values: []string{"phone"}},
|
||||
{Name: "phoneVerified", Values: []string{"false"}},
|
||||
{Name: "lang", Values: []string{"und"}},
|
||||
{Name: "avatar", Values: []string{"avatar"}},
|
||||
{Name: "profile", Values: []string{"profile"}},
|
||||
},
|
||||
},
|
||||
idAttribute: "id",
|
||||
firstNameAttribute: "first",
|
||||
lastNameAttribute: "last",
|
||||
displayNameAttribute: "display",
|
||||
nickNameAttribute: "nick",
|
||||
preferredUsernameAttribute: "preferred",
|
||||
emailAttribute: "email",
|
||||
emailVerifiedAttribute: "emailVerified",
|
||||
phoneAttribute: "phone",
|
||||
phoneVerifiedAttribute: "phoneVerified",
|
||||
preferredLanguageAttribute: "lang",
|
||||
avatarURLAttribute: "avatar",
|
||||
profileAttribute: "profile",
|
||||
},
|
||||
want: want{
|
||||
user: &User{
|
||||
id: "id",
|
||||
firstName: "first",
|
||||
lastName: "last",
|
||||
displayName: "display",
|
||||
nickName: "nick",
|
||||
preferredUsername: "preferred",
|
||||
email: "email",
|
||||
emailVerified: false,
|
||||
phone: "phone",
|
||||
phoneVerified: false,
|
||||
preferredLanguage: language.Make("und"),
|
||||
avatarURL: "avatar",
|
||||
profile: "profile",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := mapLDAPEntryToUser(
|
||||
tt.fields.user,
|
||||
tt.fields.idAttribute,
|
||||
tt.fields.firstNameAttribute,
|
||||
tt.fields.lastNameAttribute,
|
||||
tt.fields.displayNameAttribute,
|
||||
tt.fields.nickNameAttribute,
|
||||
tt.fields.preferredUsernameAttribute,
|
||||
tt.fields.emailAttribute,
|
||||
tt.fields.emailVerifiedAttribute,
|
||||
tt.fields.phoneAttribute,
|
||||
tt.fields.phoneVerifiedAttribute,
|
||||
tt.fields.preferredLanguageAttribute,
|
||||
tt.fields.avatarURLAttribute,
|
||||
tt.fields.profileAttribute,
|
||||
)
|
||||
if tt.want.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.want.err != nil && !tt.want.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
if tt.want.err == nil {
|
||||
assert.Equal(t, tt.want.user, got)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
@ -128,15 +128,16 @@ type GoogleIDPTemplate struct {
|
||||
}
|
||||
|
||||
type LDAPIDPTemplate struct {
|
||||
IDPID string
|
||||
Host string
|
||||
Port string
|
||||
TLS bool
|
||||
BaseDN string
|
||||
UserObjectClass string
|
||||
UserUniqueAttribute string
|
||||
Admin string
|
||||
Password *crypto.CryptoValue
|
||||
IDPID string
|
||||
Servers []string
|
||||
StartTLS bool
|
||||
BaseDN string
|
||||
BindDN string
|
||||
BindPassword *crypto.CryptoValue
|
||||
UserBase string
|
||||
UserObjectClasses []string
|
||||
UserFilters []string
|
||||
Timeout time.Duration
|
||||
idp.LDAPAttributes
|
||||
}
|
||||
|
||||
@ -515,36 +516,40 @@ var (
|
||||
name: projection.LDAPInstanceIDCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPHostCol = Column{
|
||||
name: projection.LDAPHostCol,
|
||||
LDAPServersCol = Column{
|
||||
name: projection.LDAPServersCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPPortCol = Column{
|
||||
name: projection.LDAPPortCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPTlsCol = Column{
|
||||
name: projection.LDAPTlsCol,
|
||||
LDAPStartTLSCol = Column{
|
||||
name: projection.LDAPStartTLSCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPBaseDNCol = Column{
|
||||
name: projection.LDAPBaseDNCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPUserObjectClassCol = Column{
|
||||
name: projection.LDAPUserObjectClassCol,
|
||||
LDAPBindDNCol = Column{
|
||||
name: projection.LDAPBindDNCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPUserUniqueAttributeCol = Column{
|
||||
name: projection.LDAPUserUniqueAttributeCol,
|
||||
LDAPBindPasswordCol = Column{
|
||||
name: projection.LDAPBindPasswordCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPAdminCol = Column{
|
||||
name: projection.LDAPAdminCol,
|
||||
LDAPUserBaseCol = Column{
|
||||
name: projection.LDAPUserBaseCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPPasswordCol = Column{
|
||||
name: projection.LDAPPasswordCol,
|
||||
LDAPUserObjectClassesCol = Column{
|
||||
name: projection.LDAPUserObjectClassesCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPUserFiltersCol = Column{
|
||||
name: projection.LDAPUserFiltersCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPTimeoutCol = Column{
|
||||
name: projection.LDAPTimeoutCol,
|
||||
table: ldapIdpTemplateTable,
|
||||
}
|
||||
LDAPIDAttributeCol = Column{
|
||||
@ -772,14 +777,15 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se
|
||||
GoogleScopesCol.identifier(),
|
||||
// ldap
|
||||
LDAPIDCol.identifier(),
|
||||
LDAPHostCol.identifier(),
|
||||
LDAPPortCol.identifier(),
|
||||
LDAPTlsCol.identifier(),
|
||||
LDAPServersCol.identifier(),
|
||||
LDAPStartTLSCol.identifier(),
|
||||
LDAPBaseDNCol.identifier(),
|
||||
LDAPUserObjectClassCol.identifier(),
|
||||
LDAPUserUniqueAttributeCol.identifier(),
|
||||
LDAPAdminCol.identifier(),
|
||||
LDAPPasswordCol.identifier(),
|
||||
LDAPBindDNCol.identifier(),
|
||||
LDAPBindPasswordCol.identifier(),
|
||||
LDAPUserBaseCol.identifier(),
|
||||
LDAPUserObjectClassesCol.identifier(),
|
||||
LDAPUserFiltersCol.identifier(),
|
||||
LDAPTimeoutCol.identifier(),
|
||||
LDAPIDAttributeCol.identifier(),
|
||||
LDAPFirstNameAttributeCol.identifier(),
|
||||
LDAPLastNameAttributeCol.identifier(),
|
||||
@ -869,14 +875,15 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se
|
||||
googleScopes := database.StringArray{}
|
||||
|
||||
ldapID := sql.NullString{}
|
||||
ldapHost := sql.NullString{}
|
||||
ldapPort := sql.NullString{}
|
||||
ldapTls := sql.NullBool{}
|
||||
ldapServers := database.StringArray{}
|
||||
ldapStartTls := sql.NullBool{}
|
||||
ldapBaseDN := sql.NullString{}
|
||||
ldapUserObjectClass := sql.NullString{}
|
||||
ldapUserUniqueAttribute := sql.NullString{}
|
||||
ldapAdmin := sql.NullString{}
|
||||
ldapPassword := new(crypto.CryptoValue)
|
||||
ldapBindDN := sql.NullString{}
|
||||
ldapBindPassword := new(crypto.CryptoValue)
|
||||
ldapUserBase := sql.NullString{}
|
||||
ldapUserObjectClasses := database.StringArray{}
|
||||
ldapUserFilters := database.StringArray{}
|
||||
ldapTimeout := sql.NullInt64{}
|
||||
ldapIDAttribute := sql.NullString{}
|
||||
ldapFirstNameAttribute := sql.NullString{}
|
||||
ldapLastNameAttribute := sql.NullString{}
|
||||
@ -965,14 +972,15 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se
|
||||
&googleScopes,
|
||||
// ldap
|
||||
&ldapID,
|
||||
&ldapHost,
|
||||
&ldapPort,
|
||||
&ldapTls,
|
||||
&ldapServers,
|
||||
&ldapStartTls,
|
||||
&ldapBaseDN,
|
||||
&ldapUserObjectClass,
|
||||
&ldapUserUniqueAttribute,
|
||||
&ldapAdmin,
|
||||
&ldapPassword,
|
||||
&ldapBindDN,
|
||||
&ldapBindPassword,
|
||||
&ldapUserBase,
|
||||
&ldapUserObjectClasses,
|
||||
&ldapUserFilters,
|
||||
&ldapTimeout,
|
||||
&ldapIDAttribute,
|
||||
&ldapFirstNameAttribute,
|
||||
&ldapLastNameAttribute,
|
||||
@ -1083,15 +1091,16 @@ func prepareIDPTemplateByIDQuery(ctx context.Context, db prepareDatabase) (sq.Se
|
||||
}
|
||||
if ldapID.Valid {
|
||||
idpTemplate.LDAPIDPTemplate = &LDAPIDPTemplate{
|
||||
IDPID: ldapID.String,
|
||||
Host: ldapHost.String,
|
||||
Port: ldapPort.String,
|
||||
TLS: ldapTls.Bool,
|
||||
BaseDN: ldapBaseDN.String,
|
||||
UserObjectClass: ldapUserObjectClass.String,
|
||||
UserUniqueAttribute: ldapUserUniqueAttribute.String,
|
||||
Admin: ldapAdmin.String,
|
||||
Password: ldapPassword,
|
||||
IDPID: ldapID.String,
|
||||
Servers: ldapServers,
|
||||
StartTLS: ldapStartTls.Bool,
|
||||
BaseDN: ldapBaseDN.String,
|
||||
BindDN: ldapBindDN.String,
|
||||
BindPassword: ldapBindPassword,
|
||||
UserBase: ldapUserBase.String,
|
||||
UserObjectClasses: ldapUserObjectClasses,
|
||||
UserFilters: ldapUserFilters,
|
||||
Timeout: time.Duration(ldapTimeout.Int64),
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: ldapIDAttribute.String,
|
||||
FirstNameAttribute: ldapFirstNameAttribute.String,
|
||||
@ -1189,14 +1198,15 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec
|
||||
GoogleScopesCol.identifier(),
|
||||
// ldap
|
||||
LDAPIDCol.identifier(),
|
||||
LDAPHostCol.identifier(),
|
||||
LDAPPortCol.identifier(),
|
||||
LDAPTlsCol.identifier(),
|
||||
LDAPServersCol.identifier(),
|
||||
LDAPStartTLSCol.identifier(),
|
||||
LDAPBaseDNCol.identifier(),
|
||||
LDAPUserObjectClassCol.identifier(),
|
||||
LDAPUserUniqueAttributeCol.identifier(),
|
||||
LDAPAdminCol.identifier(),
|
||||
LDAPPasswordCol.identifier(),
|
||||
LDAPBindDNCol.identifier(),
|
||||
LDAPBindPasswordCol.identifier(),
|
||||
LDAPUserBaseCol.identifier(),
|
||||
LDAPUserObjectClassesCol.identifier(),
|
||||
LDAPUserFiltersCol.identifier(),
|
||||
LDAPTimeoutCol.identifier(),
|
||||
LDAPIDAttributeCol.identifier(),
|
||||
LDAPFirstNameAttributeCol.identifier(),
|
||||
LDAPLastNameAttributeCol.identifier(),
|
||||
@ -1290,14 +1300,15 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec
|
||||
googleScopes := database.StringArray{}
|
||||
|
||||
ldapID := sql.NullString{}
|
||||
ldapHost := sql.NullString{}
|
||||
ldapPort := sql.NullString{}
|
||||
ldapTls := sql.NullBool{}
|
||||
ldapServers := database.StringArray{}
|
||||
ldapStartTls := sql.NullBool{}
|
||||
ldapBaseDN := sql.NullString{}
|
||||
ldapUserObjectClass := sql.NullString{}
|
||||
ldapUserUniqueAttribute := sql.NullString{}
|
||||
ldapAdmin := sql.NullString{}
|
||||
ldapPassword := new(crypto.CryptoValue)
|
||||
ldapBindDN := sql.NullString{}
|
||||
ldapBindPassword := new(crypto.CryptoValue)
|
||||
ldapUserBase := sql.NullString{}
|
||||
ldapUserObjectClasses := database.StringArray{}
|
||||
ldapUserFilters := database.StringArray{}
|
||||
ldapTimeout := sql.NullInt64{}
|
||||
ldapIDAttribute := sql.NullString{}
|
||||
ldapFirstNameAttribute := sql.NullString{}
|
||||
ldapLastNameAttribute := sql.NullString{}
|
||||
@ -1386,14 +1397,15 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec
|
||||
&googleScopes,
|
||||
// ldap
|
||||
&ldapID,
|
||||
&ldapHost,
|
||||
&ldapPort,
|
||||
&ldapTls,
|
||||
&ldapServers,
|
||||
&ldapStartTls,
|
||||
&ldapBaseDN,
|
||||
&ldapUserObjectClass,
|
||||
&ldapUserUniqueAttribute,
|
||||
&ldapAdmin,
|
||||
&ldapPassword,
|
||||
&ldapBindDN,
|
||||
&ldapBindPassword,
|
||||
&ldapUserBase,
|
||||
&ldapUserObjectClasses,
|
||||
&ldapUserFilters,
|
||||
&ldapTimeout,
|
||||
&ldapIDAttribute,
|
||||
&ldapFirstNameAttribute,
|
||||
&ldapLastNameAttribute,
|
||||
@ -1503,15 +1515,16 @@ func prepareIDPTemplatesQuery(ctx context.Context, db prepareDatabase) (sq.Selec
|
||||
}
|
||||
if ldapID.Valid {
|
||||
idpTemplate.LDAPIDPTemplate = &LDAPIDPTemplate{
|
||||
IDPID: ldapID.String,
|
||||
Host: ldapHost.String,
|
||||
Port: ldapPort.String,
|
||||
TLS: ldapTls.Bool,
|
||||
BaseDN: ldapBaseDN.String,
|
||||
UserObjectClass: ldapUserObjectClass.String,
|
||||
UserUniqueAttribute: ldapUserUniqueAttribute.String,
|
||||
Admin: ldapAdmin.String,
|
||||
Password: ldapPassword,
|
||||
IDPID: ldapID.String,
|
||||
Servers: ldapServers,
|
||||
StartTLS: ldapStartTls.Bool,
|
||||
BaseDN: ldapBaseDN.String,
|
||||
BindDN: ldapBindDN.String,
|
||||
BindPassword: ldapBindPassword,
|
||||
UserBase: ldapUserBase.String,
|
||||
UserObjectClasses: ldapUserObjectClasses,
|
||||
UserFilters: ldapUserFilters,
|
||||
Timeout: time.Duration(ldapTimeout.Int64),
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: ldapIDAttribute.String,
|
||||
FirstNameAttribute: ldapFirstNameAttribute.String,
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@ -87,28 +88,29 @@ var (
|
||||
` projections.idp_templates4_google.client_secret,` +
|
||||
` projections.idp_templates4_google.scopes,` +
|
||||
// ldap
|
||||
` projections.idp_templates4_ldap.idp_id,` +
|
||||
` projections.idp_templates4_ldap.host,` +
|
||||
` projections.idp_templates4_ldap.port,` +
|
||||
` projections.idp_templates4_ldap.tls,` +
|
||||
` projections.idp_templates4_ldap.base_dn,` +
|
||||
` projections.idp_templates4_ldap.user_object_class,` +
|
||||
` projections.idp_templates4_ldap.user_unique_attribute,` +
|
||||
` projections.idp_templates4_ldap.admin,` +
|
||||
` projections.idp_templates4_ldap.password,` +
|
||||
` projections.idp_templates4_ldap.id_attribute,` +
|
||||
` projections.idp_templates4_ldap.first_name_attribute,` +
|
||||
` projections.idp_templates4_ldap.last_name_attribute,` +
|
||||
` projections.idp_templates4_ldap.display_name_attribute,` +
|
||||
` projections.idp_templates4_ldap.nick_name_attribute,` +
|
||||
` projections.idp_templates4_ldap.preferred_username_attribute,` +
|
||||
` projections.idp_templates4_ldap.email_attribute,` +
|
||||
` projections.idp_templates4_ldap.email_verified,` +
|
||||
` projections.idp_templates4_ldap.phone_attribute,` +
|
||||
` projections.idp_templates4_ldap.phone_verified_attribute,` +
|
||||
` projections.idp_templates4_ldap.preferred_language_attribute,` +
|
||||
` projections.idp_templates4_ldap.avatar_url_attribute,` +
|
||||
` projections.idp_templates4_ldap.profile_attribute` +
|
||||
` projections.idp_templates4_ldap2.idp_id,` +
|
||||
` projections.idp_templates4_ldap2.servers,` +
|
||||
` projections.idp_templates4_ldap2.start_tls,` +
|
||||
` projections.idp_templates4_ldap2.base_dn,` +
|
||||
` projections.idp_templates4_ldap2.bind_dn,` +
|
||||
` projections.idp_templates4_ldap2.bind_password,` +
|
||||
` projections.idp_templates4_ldap2.user_base,` +
|
||||
` projections.idp_templates4_ldap2.user_object_classes,` +
|
||||
` projections.idp_templates4_ldap2.user_filters,` +
|
||||
` projections.idp_templates4_ldap2.timeout,` +
|
||||
` projections.idp_templates4_ldap2.id_attribute,` +
|
||||
` projections.idp_templates4_ldap2.first_name_attribute,` +
|
||||
` projections.idp_templates4_ldap2.last_name_attribute,` +
|
||||
` projections.idp_templates4_ldap2.display_name_attribute,` +
|
||||
` projections.idp_templates4_ldap2.nick_name_attribute,` +
|
||||
` projections.idp_templates4_ldap2.preferred_username_attribute,` +
|
||||
` projections.idp_templates4_ldap2.email_attribute,` +
|
||||
` projections.idp_templates4_ldap2.email_verified,` +
|
||||
` projections.idp_templates4_ldap2.phone_attribute,` +
|
||||
` projections.idp_templates4_ldap2.phone_verified_attribute,` +
|
||||
` projections.idp_templates4_ldap2.preferred_language_attribute,` +
|
||||
` projections.idp_templates4_ldap2.avatar_url_attribute,` +
|
||||
` projections.idp_templates4_ldap2.profile_attribute` +
|
||||
` FROM projections.idp_templates4` +
|
||||
` LEFT JOIN projections.idp_templates4_oauth2 ON projections.idp_templates4.id = projections.idp_templates4_oauth2.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_oauth2.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates4_oidc ON projections.idp_templates4.id = projections.idp_templates4_oidc.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_oidc.instance_id` +
|
||||
@ -119,7 +121,7 @@ var (
|
||||
` LEFT JOIN projections.idp_templates4_gitlab ON projections.idp_templates4.id = projections.idp_templates4_gitlab.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_gitlab.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates4_gitlab_self_hosted ON projections.idp_templates4.id = projections.idp_templates4_gitlab_self_hosted.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_gitlab_self_hosted.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates4_google ON projections.idp_templates4.id = projections.idp_templates4_google.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_google.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates4_ldap ON projections.idp_templates4.id = projections.idp_templates4_ldap.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_ldap.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates4_ldap2 ON projections.idp_templates4.id = projections.idp_templates4_ldap2.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_ldap2.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
idpTemplateCols = []string{
|
||||
"id",
|
||||
@ -195,14 +197,15 @@ var (
|
||||
"scopes",
|
||||
// ldap config
|
||||
"idp_id",
|
||||
"host",
|
||||
"port",
|
||||
"tls",
|
||||
"servers",
|
||||
"start_tls",
|
||||
"base_dn",
|
||||
"user_object_class",
|
||||
"user_unique_attribute",
|
||||
"admin",
|
||||
"password",
|
||||
"bind_dn",
|
||||
"bind_password",
|
||||
"user_base",
|
||||
"user_object_classes",
|
||||
"user_filters",
|
||||
"timeout",
|
||||
"id_attribute",
|
||||
"first_name_attribute",
|
||||
"last_name_attribute",
|
||||
@ -289,28 +292,29 @@ var (
|
||||
` projections.idp_templates4_google.client_secret,` +
|
||||
` projections.idp_templates4_google.scopes,` +
|
||||
// ldap
|
||||
` projections.idp_templates4_ldap.idp_id,` +
|
||||
` projections.idp_templates4_ldap.host,` +
|
||||
` projections.idp_templates4_ldap.port,` +
|
||||
` projections.idp_templates4_ldap.tls,` +
|
||||
` projections.idp_templates4_ldap.base_dn,` +
|
||||
` projections.idp_templates4_ldap.user_object_class,` +
|
||||
` projections.idp_templates4_ldap.user_unique_attribute,` +
|
||||
` projections.idp_templates4_ldap.admin,` +
|
||||
` projections.idp_templates4_ldap.password,` +
|
||||
` projections.idp_templates4_ldap.id_attribute,` +
|
||||
` projections.idp_templates4_ldap.first_name_attribute,` +
|
||||
` projections.idp_templates4_ldap.last_name_attribute,` +
|
||||
` projections.idp_templates4_ldap.display_name_attribute,` +
|
||||
` projections.idp_templates4_ldap.nick_name_attribute,` +
|
||||
` projections.idp_templates4_ldap.preferred_username_attribute,` +
|
||||
` projections.idp_templates4_ldap.email_attribute,` +
|
||||
` projections.idp_templates4_ldap.email_verified,` +
|
||||
` projections.idp_templates4_ldap.phone_attribute,` +
|
||||
` projections.idp_templates4_ldap.phone_verified_attribute,` +
|
||||
` projections.idp_templates4_ldap.preferred_language_attribute,` +
|
||||
` projections.idp_templates4_ldap.avatar_url_attribute,` +
|
||||
` projections.idp_templates4_ldap.profile_attribute,` +
|
||||
` projections.idp_templates4_ldap2.idp_id,` +
|
||||
` projections.idp_templates4_ldap2.servers,` +
|
||||
` projections.idp_templates4_ldap2.start_tls,` +
|
||||
` projections.idp_templates4_ldap2.base_dn,` +
|
||||
` projections.idp_templates4_ldap2.bind_dn,` +
|
||||
` projections.idp_templates4_ldap2.bind_password,` +
|
||||
` projections.idp_templates4_ldap2.user_base,` +
|
||||
` projections.idp_templates4_ldap2.user_object_classes,` +
|
||||
` projections.idp_templates4_ldap2.user_filters,` +
|
||||
` projections.idp_templates4_ldap2.timeout,` +
|
||||
` projections.idp_templates4_ldap2.id_attribute,` +
|
||||
` projections.idp_templates4_ldap2.first_name_attribute,` +
|
||||
` projections.idp_templates4_ldap2.last_name_attribute,` +
|
||||
` projections.idp_templates4_ldap2.display_name_attribute,` +
|
||||
` projections.idp_templates4_ldap2.nick_name_attribute,` +
|
||||
` projections.idp_templates4_ldap2.preferred_username_attribute,` +
|
||||
` projections.idp_templates4_ldap2.email_attribute,` +
|
||||
` projections.idp_templates4_ldap2.email_verified,` +
|
||||
` projections.idp_templates4_ldap2.phone_attribute,` +
|
||||
` projections.idp_templates4_ldap2.phone_verified_attribute,` +
|
||||
` projections.idp_templates4_ldap2.preferred_language_attribute,` +
|
||||
` projections.idp_templates4_ldap2.avatar_url_attribute,` +
|
||||
` projections.idp_templates4_ldap2.profile_attribute,` +
|
||||
` COUNT(*) OVER ()` +
|
||||
` FROM projections.idp_templates4` +
|
||||
` LEFT JOIN projections.idp_templates4_oauth2 ON projections.idp_templates4.id = projections.idp_templates4_oauth2.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_oauth2.instance_id` +
|
||||
@ -322,7 +326,7 @@ var (
|
||||
` LEFT JOIN projections.idp_templates4_gitlab ON projections.idp_templates4.id = projections.idp_templates4_gitlab.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_gitlab.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates4_gitlab_self_hosted ON projections.idp_templates4.id = projections.idp_templates4_gitlab_self_hosted.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_gitlab_self_hosted.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates4_google ON projections.idp_templates4.id = projections.idp_templates4_google.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_google.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates4_ldap ON projections.idp_templates4.id = projections.idp_templates4_ldap.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_ldap.instance_id` +
|
||||
` LEFT JOIN projections.idp_templates4_ldap2 ON projections.idp_templates4.id = projections.idp_templates4_ldap2.idp_id AND projections.idp_templates4.instance_id = projections.idp_templates4_ldap2.instance_id` +
|
||||
` AS OF SYSTEM TIME '-1 ms'`
|
||||
idpTemplatesCols = []string{
|
||||
"id",
|
||||
@ -398,14 +402,15 @@ var (
|
||||
"scopes",
|
||||
// ldap config
|
||||
"idp_id",
|
||||
"host",
|
||||
"port",
|
||||
"tls",
|
||||
"servers",
|
||||
"start_tls",
|
||||
"base_dn",
|
||||
"user_object_class",
|
||||
"user_unique_attribute",
|
||||
"admin",
|
||||
"password",
|
||||
"bind_dn",
|
||||
"bind_password",
|
||||
"user_base",
|
||||
"user_object_classes",
|
||||
"user_filters",
|
||||
"timeout",
|
||||
"id_attribute",
|
||||
"first_name_attribute",
|
||||
"last_name_attribute",
|
||||
@ -554,6 +559,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@ -685,6 +691,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@ -814,6 +821,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@ -942,6 +950,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@ -1069,6 +1078,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@ -1196,6 +1206,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@ -1324,6 +1335,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@ -1430,14 +1442,15 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
// ldap config
|
||||
"idp-id",
|
||||
"host",
|
||||
"port",
|
||||
database.StringArray{"server"},
|
||||
true,
|
||||
"base",
|
||||
"user",
|
||||
"uid",
|
||||
"admin",
|
||||
"dn",
|
||||
nil,
|
||||
"user",
|
||||
database.StringArray{"object"},
|
||||
database.StringArray{"filter"},
|
||||
time.Duration(30000000000),
|
||||
"id",
|
||||
"first",
|
||||
"last",
|
||||
@ -1469,14 +1482,15 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
LDAPIDPTemplate: &LDAPIDPTemplate{
|
||||
IDPID: "idp-id",
|
||||
Host: "host",
|
||||
Port: "port",
|
||||
TLS: true,
|
||||
BaseDN: "base",
|
||||
UserObjectClass: "user",
|
||||
UserUniqueAttribute: "uid",
|
||||
Admin: "admin",
|
||||
IDPID: "idp-id",
|
||||
Servers: []string{"server"},
|
||||
StartTLS: true,
|
||||
BaseDN: "base",
|
||||
BindDN: "dn",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
UserFilters: []string{"filter"},
|
||||
Timeout: time.Duration(30000000000),
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "first",
|
||||
@ -1597,6 +1611,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
),
|
||||
},
|
||||
@ -1733,14 +1748,15 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
// ldap config
|
||||
"idp-id",
|
||||
"host",
|
||||
"port",
|
||||
database.StringArray{"server"},
|
||||
true,
|
||||
"base",
|
||||
"user",
|
||||
"uid",
|
||||
"admin",
|
||||
"dn",
|
||||
nil,
|
||||
"user",
|
||||
database.StringArray{"object"},
|
||||
database.StringArray{"filter"},
|
||||
time.Duration(30000000000),
|
||||
"id",
|
||||
"first",
|
||||
"last",
|
||||
@ -1778,14 +1794,15 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
LDAPIDPTemplate: &LDAPIDPTemplate{
|
||||
IDPID: "idp-id",
|
||||
Host: "host",
|
||||
Port: "port",
|
||||
TLS: true,
|
||||
BaseDN: "base",
|
||||
UserObjectClass: "user",
|
||||
UserUniqueAttribute: "uid",
|
||||
Admin: "admin",
|
||||
IDPID: "idp-id",
|
||||
Servers: []string{"server"},
|
||||
StartTLS: true,
|
||||
BaseDN: "base",
|
||||
BindDN: "dn",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
UserFilters: []string{"filter"},
|
||||
Timeout: time.Duration(30000000000),
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "first",
|
||||
@ -1909,6 +1926,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@ -2018,14 +2036,15 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
// ldap config
|
||||
"idp-id-ldap",
|
||||
"host",
|
||||
"port",
|
||||
database.StringArray{"server"},
|
||||
true,
|
||||
"base",
|
||||
"user",
|
||||
"uid",
|
||||
"admin",
|
||||
"dn",
|
||||
nil,
|
||||
"user",
|
||||
database.StringArray{"object"},
|
||||
database.StringArray{"filter"},
|
||||
time.Duration(30000000000),
|
||||
"id",
|
||||
"first",
|
||||
"last",
|
||||
@ -2135,6 +2154,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"idp-id-oauth",
|
||||
@ -2231,6 +2251,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"idp-id-oidc",
|
||||
@ -2327,6 +2348,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"idp-id-jwt",
|
||||
@ -2423,6 +2445,7 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
nil,
|
||||
},
|
||||
},
|
||||
),
|
||||
@ -2447,14 +2470,15 @@ func Test_IDPTemplateTemplatesPrepares(t *testing.T) {
|
||||
IsAutoCreation: true,
|
||||
IsAutoUpdate: true,
|
||||
LDAPIDPTemplate: &LDAPIDPTemplate{
|
||||
IDPID: "idp-id-ldap",
|
||||
Host: "host",
|
||||
Port: "port",
|
||||
TLS: true,
|
||||
BaseDN: "base",
|
||||
UserObjectClass: "user",
|
||||
UserUniqueAttribute: "uid",
|
||||
Admin: "admin",
|
||||
IDPID: "idp-id-ldap",
|
||||
Servers: []string{"server"},
|
||||
StartTLS: true,
|
||||
BaseDN: "base",
|
||||
BindDN: "dn",
|
||||
UserBase: "user",
|
||||
UserObjectClasses: []string{"object"},
|
||||
UserFilters: []string{"filter"},
|
||||
Timeout: time.Duration(30000000000),
|
||||
LDAPAttributes: idp.LDAPAttributes{
|
||||
IDAttribute: "id",
|
||||
FirstNameAttribute: "first",
|
||||
|
@ -38,7 +38,7 @@ const (
|
||||
IDPTemplateGitLabSuffix = "gitlab"
|
||||
IDPTemplateGitLabSelfHostedSuffix = "gitlab_self_hosted"
|
||||
IDPTemplateGoogleSuffix = "google"
|
||||
IDPTemplateLDAPSuffix = "ldap"
|
||||
IDPTemplateLDAPSuffix = "ldap2"
|
||||
|
||||
IDPTemplateIDCol = "id"
|
||||
IDPTemplateCreationDateCol = "creation_date"
|
||||
@ -125,14 +125,15 @@ const (
|
||||
|
||||
LDAPIDCol = "idp_id"
|
||||
LDAPInstanceIDCol = "instance_id"
|
||||
LDAPHostCol = "host"
|
||||
LDAPPortCol = "port"
|
||||
LDAPTlsCol = "tls"
|
||||
LDAPServersCol = "servers"
|
||||
LDAPStartTLSCol = "start_tls"
|
||||
LDAPBaseDNCol = "base_dn"
|
||||
LDAPUserObjectClassCol = "user_object_class"
|
||||
LDAPUserUniqueAttributeCol = "user_unique_attribute"
|
||||
LDAPAdminCol = "admin"
|
||||
LDAPPasswordCol = "password"
|
||||
LDAPBindDNCol = "bind_dn"
|
||||
LDAPBindPasswordCol = "bind_password"
|
||||
LDAPUserBaseCol = "user_base"
|
||||
LDAPUserObjectClassesCol = "user_object_classes"
|
||||
LDAPUserFiltersCol = "user_filters"
|
||||
LDAPTimeoutCol = "timeout"
|
||||
LDAPIDAttributeCol = "id_attribute"
|
||||
LDAPFirstNameAttributeCol = "first_name_attribute"
|
||||
LDAPLastNameAttributeCol = "last_name_attribute"
|
||||
@ -293,14 +294,15 @@ func newIDPTemplateProjection(ctx context.Context, config crdb.StatementHandlerC
|
||||
crdb.NewSuffixedTable([]*crdb.Column{
|
||||
crdb.NewColumn(LDAPIDCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(LDAPInstanceIDCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(LDAPHostCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPPortCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPTlsCol, crdb.ColumnTypeBool, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPBaseDNCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPUserObjectClassCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPUserUniqueAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPAdminCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPPasswordCol, crdb.ColumnTypeJSONB, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPServersCol, crdb.ColumnTypeTextArray),
|
||||
crdb.NewColumn(LDAPStartTLSCol, crdb.ColumnTypeBool),
|
||||
crdb.NewColumn(LDAPBaseDNCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(LDAPBindDNCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(LDAPBindPasswordCol, crdb.ColumnTypeJSONB),
|
||||
crdb.NewColumn(LDAPUserBaseCol, crdb.ColumnTypeText),
|
||||
crdb.NewColumn(LDAPUserObjectClassesCol, crdb.ColumnTypeTextArray),
|
||||
crdb.NewColumn(LDAPUserFiltersCol, crdb.ColumnTypeTextArray),
|
||||
crdb.NewColumn(LDAPTimeoutCol, crdb.ColumnTypeInt64),
|
||||
crdb.NewColumn(LDAPIDAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPFirstNameAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
crdb.NewColumn(LDAPLastNameAttributeCol, crdb.ColumnTypeText, crdb.Nullable()),
|
||||
@ -1663,14 +1665,15 @@ func (p *idpTemplateProjection) reduceLDAPIDPAdded(event eventstore.Event) (*han
|
||||
[]handler.Column{
|
||||
handler.NewCol(LDAPIDCol, idpEvent.ID),
|
||||
handler.NewCol(LDAPInstanceIDCol, idpEvent.Aggregate().InstanceID),
|
||||
handler.NewCol(LDAPHostCol, idpEvent.Host),
|
||||
handler.NewCol(LDAPPortCol, idpEvent.Port),
|
||||
handler.NewCol(LDAPTlsCol, idpEvent.TLS),
|
||||
handler.NewCol(LDAPServersCol, database.StringArray(idpEvent.Servers)),
|
||||
handler.NewCol(LDAPStartTLSCol, idpEvent.StartTLS),
|
||||
handler.NewCol(LDAPBaseDNCol, idpEvent.BaseDN),
|
||||
handler.NewCol(LDAPUserObjectClassCol, idpEvent.UserObjectClass),
|
||||
handler.NewCol(LDAPUserUniqueAttributeCol, idpEvent.UserUniqueAttribute),
|
||||
handler.NewCol(LDAPAdminCol, idpEvent.Admin),
|
||||
handler.NewCol(LDAPPasswordCol, idpEvent.Password),
|
||||
handler.NewCol(LDAPBindDNCol, idpEvent.BindDN),
|
||||
handler.NewCol(LDAPBindPasswordCol, idpEvent.BindPassword),
|
||||
handler.NewCol(LDAPUserBaseCol, idpEvent.UserBase),
|
||||
handler.NewCol(LDAPUserObjectClassesCol, database.StringArray(idpEvent.UserObjectClasses)),
|
||||
handler.NewCol(LDAPUserFiltersCol, database.StringArray(idpEvent.UserFilters)),
|
||||
handler.NewCol(LDAPTimeoutCol, idpEvent.Timeout),
|
||||
handler.NewCol(LDAPIDAttributeCol, idpEvent.IDAttribute),
|
||||
handler.NewCol(LDAPFirstNameAttributeCol, idpEvent.FirstNameAttribute),
|
||||
handler.NewCol(LDAPLastNameAttributeCol, idpEvent.LastNameAttribute),
|
||||
@ -1962,29 +1965,32 @@ func reduceGoogleIDPChangedColumns(idpEvent idp.GoogleIDPChangedEvent) []handler
|
||||
|
||||
func reduceLDAPIDPChangedColumns(idpEvent idp.LDAPIDPChangedEvent) []handler.Column {
|
||||
ldapCols := make([]handler.Column, 0, 4)
|
||||
if idpEvent.Host != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPHostCol, *idpEvent.Host))
|
||||
if idpEvent.Servers != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPServersCol, database.StringArray(idpEvent.Servers)))
|
||||
}
|
||||
if idpEvent.Port != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPPortCol, *idpEvent.Port))
|
||||
}
|
||||
if idpEvent.TLS != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPTlsCol, *idpEvent.TLS))
|
||||
if idpEvent.StartTLS != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPStartTLSCol, *idpEvent.StartTLS))
|
||||
}
|
||||
if idpEvent.BaseDN != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPBaseDNCol, *idpEvent.BaseDN))
|
||||
}
|
||||
if idpEvent.UserObjectClass != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPUserObjectClassCol, *idpEvent.UserObjectClass))
|
||||
if idpEvent.BindDN != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPBindDNCol, *idpEvent.BindDN))
|
||||
}
|
||||
if idpEvent.UserUniqueAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPUserUniqueAttributeCol, *idpEvent.UserUniqueAttribute))
|
||||
if idpEvent.BindPassword != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPBindPasswordCol, idpEvent.BindPassword))
|
||||
}
|
||||
if idpEvent.Admin != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPAdminCol, *idpEvent.Admin))
|
||||
if idpEvent.UserBase != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPUserBaseCol, *idpEvent.UserBase))
|
||||
}
|
||||
if idpEvent.Password != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPPasswordCol, *idpEvent.Password))
|
||||
if idpEvent.UserObjectClasses != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPUserObjectClassesCol, database.StringArray(idpEvent.UserObjectClasses)))
|
||||
}
|
||||
if idpEvent.UserFilters != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPUserFiltersCol, database.StringArray(idpEvent.UserFilters)))
|
||||
}
|
||||
if idpEvent.Timeout != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPTimeoutCol, *idpEvent.Timeout))
|
||||
}
|
||||
if idpEvent.IDAttribute != nil {
|
||||
ldapCols = append(ldapCols, handler.NewCol(LDAPIDAttributeCol, *idpEvent.IDAttribute))
|
||||
|
@ -2,6 +2,7 @@ package projection
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/database"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
@ -2033,18 +2034,19 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) {
|
||||
[]byte(`{
|
||||
"id": "idp-id",
|
||||
"name": "custom-zitadel-instance",
|
||||
"host": "host",
|
||||
"port": "port",
|
||||
"tls": true,
|
||||
"baseDN": "base",
|
||||
"userObjectClass": "user",
|
||||
"userUniqueAttribute": "uid",
|
||||
"admin": "admin",
|
||||
"password": {
|
||||
"servers": ["server"],
|
||||
"startTls": false,
|
||||
"baseDN": "basedn",
|
||||
"bindDN": "binddn",
|
||||
"bindPassword": {
|
||||
"cryptoType": 0,
|
||||
"algorithm": "RSA-265",
|
||||
"keyId": "key-id"
|
||||
},
|
||||
"userBase": "user",
|
||||
"userObjectClasses": ["object"],
|
||||
"userFilters": ["filter"],
|
||||
"timeout": 30000000000,
|
||||
"idAttribute": "id",
|
||||
"firstNameAttribute": "first",
|
||||
"lastNameAttribute": "last",
|
||||
@ -2092,18 +2094,19 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates4_ldap (idp_id, instance_id, host, port, tls, base_dn, user_object_class, user_unique_attribute, admin, password, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)",
|
||||
expectedStmt: "INSERT INTO projections.idp_templates4_ldap2 (idp_id, instance_id, servers, start_tls, base_dn, bind_dn, bind_password, user_base, user_object_classes, user_filters, timeout, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
"base",
|
||||
"user",
|
||||
"uid",
|
||||
"admin",
|
||||
database.StringArray{"server"},
|
||||
false,
|
||||
"basedn",
|
||||
"binddn",
|
||||
anyArg{},
|
||||
"user",
|
||||
database.StringArray{"object"},
|
||||
database.StringArray{"filter"},
|
||||
time.Duration(30000000000),
|
||||
"id",
|
||||
"first",
|
||||
"last",
|
||||
@ -2132,18 +2135,19 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) {
|
||||
[]byte(`{
|
||||
"id": "idp-id",
|
||||
"name": "custom-zitadel-instance",
|
||||
"host": "host",
|
||||
"port": "port",
|
||||
"tls": true,
|
||||
"baseDN": "base",
|
||||
"userObjectClass": "user",
|
||||
"userUniqueAttribute": "uid",
|
||||
"admin": "admin",
|
||||
"password": {
|
||||
"servers": ["server"],
|
||||
"startTls": false,
|
||||
"baseDN": "basedn",
|
||||
"bindDN": "binddn",
|
||||
"bindPassword": {
|
||||
"cryptoType": 0,
|
||||
"algorithm": "RSA-265",
|
||||
"keyId": "key-id"
|
||||
},
|
||||
"userBase": "user",
|
||||
"userObjectClasses": ["object"],
|
||||
"userFilters": ["filter"],
|
||||
"timeout": 30000000000,
|
||||
"idAttribute": "id",
|
||||
"firstNameAttribute": "first",
|
||||
"lastNameAttribute": "last",
|
||||
@ -2191,18 +2195,19 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "INSERT INTO projections.idp_templates4_ldap (idp_id, instance_id, host, port, tls, base_dn, user_object_class, user_unique_attribute, admin, password, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23)",
|
||||
expectedStmt: "INSERT INTO projections.idp_templates4_ldap2 (idp_id, instance_id, servers, start_tls, base_dn, bind_dn, bind_password, user_base, user_object_classes, user_filters, timeout, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24)",
|
||||
expectedArgs: []interface{}{
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
"base",
|
||||
"user",
|
||||
"uid",
|
||||
"admin",
|
||||
database.StringArray{"server"},
|
||||
false,
|
||||
"basedn",
|
||||
"binddn",
|
||||
anyArg{},
|
||||
"user",
|
||||
database.StringArray{"object"},
|
||||
database.StringArray{"filter"},
|
||||
time.Duration(30000000000),
|
||||
"id",
|
||||
"first",
|
||||
"last",
|
||||
@ -2231,7 +2236,7 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) {
|
||||
[]byte(`{
|
||||
"id": "idp-id",
|
||||
"name": "custom-zitadel-instance",
|
||||
"host": "host"
|
||||
"baseDN": "basedn"
|
||||
}`),
|
||||
), instance.LDAPIDPChangedEventMapper),
|
||||
},
|
||||
@ -2253,9 +2258,9 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates4_ldap SET host = $1 WHERE (idp_id = $2) AND (instance_id = $3)",
|
||||
expectedStmt: "UPDATE projections.idp_templates4_ldap2 SET base_dn = $1 WHERE (idp_id = $2) AND (instance_id = $3)",
|
||||
expectedArgs: []interface{}{
|
||||
"host",
|
||||
"basedn",
|
||||
"idp-id",
|
||||
"instance-id",
|
||||
},
|
||||
@ -2273,18 +2278,19 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) {
|
||||
[]byte(`{
|
||||
"id": "idp-id",
|
||||
"name": "custom-zitadel-instance",
|
||||
"host": "host",
|
||||
"port": "port",
|
||||
"tls": true,
|
||||
"baseDN": "base",
|
||||
"userObjectClass": "user",
|
||||
"userUniqueAttribute": "uid",
|
||||
"admin": "admin",
|
||||
"password": {
|
||||
"servers": ["server"],
|
||||
"startTls": false,
|
||||
"baseDN": "basedn",
|
||||
"bindDN": "binddn",
|
||||
"bindPassword": {
|
||||
"cryptoType": 0,
|
||||
"algorithm": "RSA-265",
|
||||
"keyId": "key-id"
|
||||
},
|
||||
"userBase": "user",
|
||||
"userObjectClasses": ["object"],
|
||||
"userFilters": ["filter"],
|
||||
"timeout": 30000000000,
|
||||
"idAttribute": "id",
|
||||
"firstNameAttribute": "first",
|
||||
"lastNameAttribute": "last",
|
||||
@ -2327,16 +2333,17 @@ func TestIDPTemplateProjection_reducesLDAP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
expectedStmt: "UPDATE projections.idp_templates4_ldap SET (host, port, tls, base_dn, user_object_class, user_unique_attribute, admin, password, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21) WHERE (idp_id = $22) AND (instance_id = $23)",
|
||||
expectedStmt: "UPDATE projections.idp_templates4_ldap2 SET (servers, start_tls, base_dn, bind_dn, bind_password, user_base, user_object_classes, user_filters, timeout, id_attribute, first_name_attribute, last_name_attribute, display_name_attribute, nick_name_attribute, preferred_username_attribute, email_attribute, email_verified, phone_attribute, phone_verified_attribute, preferred_language_attribute, avatar_url_attribute, profile_attribute) = ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22) WHERE (idp_id = $23) AND (instance_id = $24)",
|
||||
expectedArgs: []interface{}{
|
||||
"host",
|
||||
"port",
|
||||
true,
|
||||
"base",
|
||||
"user",
|
||||
"uid",
|
||||
"admin",
|
||||
database.StringArray{"server"},
|
||||
false,
|
||||
"basedn",
|
||||
"binddn",
|
||||
anyArg{},
|
||||
"user",
|
||||
database.StringArray{"object"},
|
||||
database.StringArray{"filter"},
|
||||
time.Duration(30000000000),
|
||||
"id",
|
||||
"first",
|
||||
"last",
|
||||
|
@ -2,27 +2,28 @@ package idp
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/errors"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/eventstore/repository"
|
||||
"github.com/zitadel/zitadel/internal/repository/idpconfig"
|
||||
)
|
||||
|
||||
type LDAPIDPAddedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Host string `json:"host"`
|
||||
Port string `json:"port,omitempty"`
|
||||
TLS bool `json:"tls"`
|
||||
BaseDN string `json:"baseDN"`
|
||||
UserObjectClass string `json:"userObjectClass"`
|
||||
UserUniqueAttribute string `json:"userUniqueAttribute"`
|
||||
Admin string `json:"admin"`
|
||||
Password *crypto.CryptoValue `json:"password"`
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Servers []string `json:"servers"`
|
||||
StartTLS bool `json:"startTLS"`
|
||||
BaseDN string `json:"baseDN"`
|
||||
BindDN string `json:"bindDN"`
|
||||
BindPassword *crypto.CryptoValue `json:"bindPassword"`
|
||||
UserBase string `json:"userBase"`
|
||||
UserObjectClasses []string `json:"userObjectClasses"`
|
||||
UserFilters []string `json:"userFilters"`
|
||||
Timeout time.Duration `json:"timeout"`
|
||||
|
||||
LDAPAttributes
|
||||
Options
|
||||
@ -132,33 +133,35 @@ func (o *LDAPAttributes) ReduceChanges(changes LDAPAttributeChanges) {
|
||||
|
||||
func NewLDAPIDPAddedEvent(
|
||||
base *eventstore.BaseEvent,
|
||||
id,
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password *crypto.CryptoValue,
|
||||
id string,
|
||||
name string,
|
||||
servers []string,
|
||||
startTLS bool,
|
||||
baseDN string,
|
||||
bindDN string,
|
||||
bindPassword *crypto.CryptoValue,
|
||||
userBase string,
|
||||
userObjectClasses []string,
|
||||
userFilters []string,
|
||||
timeout time.Duration,
|
||||
attributes LDAPAttributes,
|
||||
options Options,
|
||||
) *LDAPIDPAddedEvent {
|
||||
return &LDAPIDPAddedEvent{
|
||||
BaseEvent: *base,
|
||||
ID: id,
|
||||
Name: name,
|
||||
Host: host,
|
||||
Port: port,
|
||||
TLS: tls,
|
||||
BaseDN: baseDN,
|
||||
UserObjectClass: userObjectClass,
|
||||
UserUniqueAttribute: userUniqueAttribute,
|
||||
Admin: admin,
|
||||
Password: password,
|
||||
LDAPAttributes: attributes,
|
||||
Options: options,
|
||||
BaseEvent: *base,
|
||||
ID: id,
|
||||
Name: name,
|
||||
Servers: servers,
|
||||
StartTLS: startTLS,
|
||||
BaseDN: baseDN,
|
||||
BindDN: bindDN,
|
||||
BindPassword: bindPassword,
|
||||
UserBase: userBase,
|
||||
UserObjectClasses: userObjectClasses,
|
||||
UserFilters: userFilters,
|
||||
Timeout: timeout,
|
||||
LDAPAttributes: attributes,
|
||||
Options: options,
|
||||
}
|
||||
}
|
||||
|
||||
@ -167,7 +170,7 @@ func (e *LDAPIDPAddedEvent) Data() interface{} {
|
||||
}
|
||||
|
||||
func (e *LDAPIDPAddedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
return []*eventstore.EventUniqueConstraint{idpconfig.NewAddIDPConfigNameUniqueConstraint(e.Name, e.Aggregate().ResourceOwner)}
|
||||
return nil
|
||||
}
|
||||
|
||||
func LDAPIDPAddedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
@ -186,18 +189,17 @@ func LDAPIDPAddedEventMapper(event *repository.Event) (eventstore.Event, error)
|
||||
type LDAPIDPChangedEvent struct {
|
||||
eventstore.BaseEvent `json:"-"`
|
||||
|
||||
oldName string
|
||||
|
||||
ID string `json:"id"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Host *string `json:"host,omitempty"`
|
||||
Port *string `json:"port,omitempty"`
|
||||
TLS *bool `json:"tls,omitempty"`
|
||||
BaseDN *string `json:"baseDN,omitempty"`
|
||||
UserObjectClass *string `json:"userObjectClass,omitempty"`
|
||||
UserUniqueAttribute *string `json:"userUniqueAttribute,omitempty"`
|
||||
Admin *string `json:"admin,omitempty"`
|
||||
Password *crypto.CryptoValue `json:"password,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
Servers []string `json:"servers,omitempty"`
|
||||
StartTLS *bool `json:"startTLS,omitempty"`
|
||||
BaseDN *string `json:"baseDN,omitempty"`
|
||||
BindDN *string `json:"bindDN,omitempty"`
|
||||
BindPassword *crypto.CryptoValue `json:"bindPassword,omitempty"`
|
||||
UserBase *string `json:"userBase,omitempty"`
|
||||
UserObjectClasses []string `json:"userObjectClasses,omitempty"`
|
||||
UserFilters []string `json:"userFilters,omitempty"`
|
||||
Timeout *time.Duration `json:"timeout,omitempty"`
|
||||
|
||||
LDAPAttributeChanges
|
||||
OptionChanges
|
||||
@ -238,7 +240,6 @@ func (o LDAPAttributeChanges) IsZero() bool {
|
||||
func NewLDAPIDPChangedEvent(
|
||||
base *eventstore.BaseEvent,
|
||||
id string,
|
||||
oldName string,
|
||||
changes []LDAPIDPChanges,
|
||||
) (*LDAPIDPChangedEvent, error) {
|
||||
if len(changes) == 0 {
|
||||
@ -247,7 +248,6 @@ func NewLDAPIDPChangedEvent(
|
||||
changedEvent := &LDAPIDPChangedEvent{
|
||||
BaseEvent: *base,
|
||||
ID: id,
|
||||
oldName: oldName,
|
||||
}
|
||||
for _, change := range changes {
|
||||
change(changedEvent)
|
||||
@ -263,51 +263,57 @@ func ChangeLDAPName(name string) func(*LDAPIDPChangedEvent) {
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPHost(host string) func(*LDAPIDPChangedEvent) {
|
||||
func ChangeLDAPServers(servers []string) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.Host = &host
|
||||
e.Servers = servers
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPPort(port string) func(*LDAPIDPChangedEvent) {
|
||||
func ChangeLDAPStartTLS(startTls bool) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.Port = &port
|
||||
e.StartTLS = &startTls
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPTLS(tls bool) func(*LDAPIDPChangedEvent) {
|
||||
func ChangeLDAPBaseDN(baseDN string) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.TLS = &tls
|
||||
e.BaseDN = &baseDN
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPBaseDN(basDN string) func(*LDAPIDPChangedEvent) {
|
||||
func ChangeLDAPBindDN(bindDN string) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.BaseDN = &basDN
|
||||
e.BindDN = &bindDN
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPUserObjectClass(userObjectClass string) func(*LDAPIDPChangedEvent) {
|
||||
func ChangeLDAPBindPassword(password *crypto.CryptoValue) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.UserObjectClass = &userObjectClass
|
||||
e.BindPassword = password
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPUserUniqueAttribute(userUniqueAttribute string) func(*LDAPIDPChangedEvent) {
|
||||
func ChangeLDAPUserBase(userBase string) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.UserUniqueAttribute = &userUniqueAttribute
|
||||
e.UserBase = &userBase
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPAdmin(admin string) func(*LDAPIDPChangedEvent) {
|
||||
func ChangeLDAPUserObjectClasses(objectClasses []string) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.Admin = &admin
|
||||
e.UserObjectClasses = objectClasses
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPPassword(password *crypto.CryptoValue) func(*LDAPIDPChangedEvent) {
|
||||
func ChangeLDAPUserFilters(userFilters []string) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.Password = password
|
||||
e.UserFilters = userFilters
|
||||
}
|
||||
}
|
||||
|
||||
func ChangeLDAPTimeout(timeout time.Duration) func(*LDAPIDPChangedEvent) {
|
||||
return func(e *LDAPIDPChangedEvent) {
|
||||
e.Timeout = &timeout
|
||||
}
|
||||
}
|
||||
|
||||
@ -328,13 +334,7 @@ func (e *LDAPIDPChangedEvent) Data() interface{} {
|
||||
}
|
||||
|
||||
func (e *LDAPIDPChangedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint {
|
||||
if e.Name == nil || e.oldName == *e.Name { // TODO: nil check should be enough?
|
||||
return nil
|
||||
}
|
||||
return []*eventstore.EventUniqueConstraint{
|
||||
idpconfig.NewRemoveIDPConfigNameUniqueConstraint(e.oldName, e.Aggregate().ResourceOwner),
|
||||
idpconfig.NewAddIDPConfigNameUniqueConstraint(*e.Name, e.Aggregate().ResourceOwner),
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func LDAPIDPChangedEventMapper(event *repository.Event) (eventstore.Event, error) {
|
||||
|
@ -2,6 +2,7 @@ package instance
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@ -28,8 +29,8 @@ const (
|
||||
GitLabSelfHostedIDPChangedEventType eventstore.EventType = "instance.idp.gitlab_self_hosted.changed"
|
||||
GoogleIDPAddedEventType eventstore.EventType = "instance.idp.google.added"
|
||||
GoogleIDPChangedEventType eventstore.EventType = "instance.idp.google.changed"
|
||||
LDAPIDPAddedEventType eventstore.EventType = "instance.idp.ldap.added"
|
||||
LDAPIDPChangedEventType eventstore.EventType = "instance.idp.ldap.changed"
|
||||
LDAPIDPAddedEventType eventstore.EventType = "instance.idp.ldap.v2.added"
|
||||
LDAPIDPChangedEventType eventstore.EventType = "instance.idp.ldap.v2.changed"
|
||||
IDPRemovedEventType eventstore.EventType = "instance.idp.removed"
|
||||
)
|
||||
|
||||
@ -751,15 +752,16 @@ func NewLDAPIDPAddedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password *crypto.CryptoValue,
|
||||
name string,
|
||||
servers []string,
|
||||
startTLS bool,
|
||||
baseDN string,
|
||||
bindDN string,
|
||||
bindPassword *crypto.CryptoValue,
|
||||
userBase string,
|
||||
userObjectClasses []string,
|
||||
userFilters []string,
|
||||
timeout time.Duration,
|
||||
attributes idp.LDAPAttributes,
|
||||
options idp.Options,
|
||||
) *LDAPIDPAddedEvent {
|
||||
@ -773,14 +775,15 @@ func NewLDAPIDPAddedEvent(
|
||||
),
|
||||
id,
|
||||
name,
|
||||
host,
|
||||
port,
|
||||
tls,
|
||||
servers,
|
||||
startTLS,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin,
|
||||
password,
|
||||
bindDN,
|
||||
bindPassword,
|
||||
userBase,
|
||||
userObjectClasses,
|
||||
userFilters,
|
||||
timeout,
|
||||
attributes,
|
||||
options,
|
||||
),
|
||||
@ -803,8 +806,7 @@ type LDAPIDPChangedEvent struct {
|
||||
func NewLDAPIDPChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
oldName string,
|
||||
id string,
|
||||
changes []idp.LDAPIDPChanges,
|
||||
) (*LDAPIDPChangedEvent, error) {
|
||||
|
||||
@ -815,7 +817,6 @@ func NewLDAPIDPChangedEvent(
|
||||
LDAPIDPChangedEventType,
|
||||
),
|
||||
id,
|
||||
oldName,
|
||||
changes,
|
||||
)
|
||||
if err != nil {
|
||||
|
@ -2,6 +2,7 @@ package org
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
@ -751,15 +752,16 @@ func NewLDAPIDPAddedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
name,
|
||||
host,
|
||||
port string,
|
||||
tls bool,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin string,
|
||||
password *crypto.CryptoValue,
|
||||
name string,
|
||||
servers []string,
|
||||
startTLS bool,
|
||||
baseDN string,
|
||||
bindDN string,
|
||||
bindPassword *crypto.CryptoValue,
|
||||
userBase string,
|
||||
userObjectClasses []string,
|
||||
userFilters []string,
|
||||
timeout time.Duration,
|
||||
attributes idp.LDAPAttributes,
|
||||
options idp.Options,
|
||||
) *LDAPIDPAddedEvent {
|
||||
@ -773,14 +775,15 @@ func NewLDAPIDPAddedEvent(
|
||||
),
|
||||
id,
|
||||
name,
|
||||
host,
|
||||
port,
|
||||
tls,
|
||||
servers,
|
||||
startTLS,
|
||||
baseDN,
|
||||
userObjectClass,
|
||||
userUniqueAttribute,
|
||||
admin,
|
||||
password,
|
||||
bindDN,
|
||||
bindPassword,
|
||||
userBase,
|
||||
userObjectClasses,
|
||||
userFilters,
|
||||
timeout,
|
||||
attributes,
|
||||
options,
|
||||
),
|
||||
@ -803,8 +806,7 @@ type LDAPIDPChangedEvent struct {
|
||||
func NewLDAPIDPChangedEvent(
|
||||
ctx context.Context,
|
||||
aggregate *eventstore.Aggregate,
|
||||
id,
|
||||
oldName string,
|
||||
id string,
|
||||
changes []idp.LDAPIDPChanges,
|
||||
) (*LDAPIDPChangedEvent, error) {
|
||||
|
||||
@ -815,7 +817,6 @@ func NewLDAPIDPChangedEvent(
|
||||
LDAPIDPChangedEventType,
|
||||
),
|
||||
id,
|
||||
oldName,
|
||||
changes,
|
||||
)
|
||||
if err != nil {
|
||||
|
@ -4732,16 +4732,17 @@ message UpdateGoogleProviderResponse {
|
||||
|
||||
message AddLDAPProviderRequest {
|
||||
string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string host = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string port = 3 [(validate.rules).string = {max_len: 5}];
|
||||
bool tls = 4;
|
||||
string base_dn = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_object_class = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_unique_attribute = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string admin = 8 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string password = 9 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
zitadel.idp.v1.LDAPAttributes attributes = 10;
|
||||
zitadel.idp.v1.Options provider_options = 11;
|
||||
repeated string servers = 2 [(validate.rules).repeated = {min_items: 1, max_items: 20, items: {string: {min_len: 1, max_len: 200}}}];
|
||||
bool start_tls = 3;
|
||||
string base_dn = 4 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string bind_dn = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string bind_password = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_base = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
repeated string user_object_classes = 8 [(validate.rules).repeated = {min_items: 1, max_items: 20, items: {string: {min_len: 1, max_len: 200}}}];
|
||||
repeated string user_filters = 9 [(validate.rules).repeated = {min_items: 1, max_items: 20, items: {string: {min_len: 1, max_len: 200}}}];
|
||||
google.protobuf.Duration timeout = 10;
|
||||
zitadel.idp.v1.LDAPAttributes attributes = 11;
|
||||
zitadel.idp.v1.Options provider_options = 12;
|
||||
}
|
||||
|
||||
message AddLDAPProviderResponse {
|
||||
@ -4752,16 +4753,17 @@ message AddLDAPProviderResponse {
|
||||
message UpdateLDAPProviderRequest {
|
||||
string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string host = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string port = 4 [(validate.rules).string = {max_len: 5}];
|
||||
bool tls = 5;
|
||||
string base_dn = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_object_class = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_unique_attribute = 8 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string admin = 9 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string password = 10 [(validate.rules).string = {max_len: 200}];
|
||||
zitadel.idp.v1.LDAPAttributes attributes = 11;
|
||||
zitadel.idp.v1.Options provider_options = 12;
|
||||
repeated string servers = 3 [(validate.rules).repeated = {min_items: 1, max_items: 20, items: {string: {min_len: 1, max_len: 200}}}];
|
||||
bool start_tls = 4;
|
||||
string base_dn = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string bind_dn = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string bind_password = 7 [(validate.rules).string = {max_len: 200}];
|
||||
string user_base = 8 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
repeated string user_object_classes = 9 [(validate.rules).repeated = {min_items: 1, max_items: 20, items: {string: {min_len: 1, max_len: 200}}}];
|
||||
repeated string user_filters = 10 [(validate.rules).repeated = {min_items: 1, max_items: 20, items: {string: {min_len: 1, max_len: 200}}}];
|
||||
google.protobuf.Duration timeout = 11;
|
||||
zitadel.idp.v1.LDAPAttributes attributes = 12;
|
||||
zitadel.idp.v1.Options provider_options = 13;
|
||||
}
|
||||
|
||||
message UpdateLDAPProviderResponse {
|
||||
|
@ -3,6 +3,7 @@ syntax = "proto3";
|
||||
import "zitadel/object.proto";
|
||||
import "validate/validate.proto";
|
||||
import "protoc-gen-openapiv2/options/annotations.proto";
|
||||
import "google/protobuf/duration.proto";
|
||||
|
||||
package zitadel.idp.v1;
|
||||
|
||||
@ -321,15 +322,15 @@ message GitLabSelfHostedConfig {
|
||||
}
|
||||
|
||||
message LDAPConfig {
|
||||
string host = 1;
|
||||
string port = 2;
|
||||
bool tls = 3;
|
||||
string base_dn = 4;
|
||||
string user_object_class = 5;
|
||||
string user_unique_attribute = 6;
|
||||
string admin = 7;
|
||||
LDAPAttributes attributes = 8;
|
||||
Options provider_options = 9;
|
||||
repeated string servers = 1;
|
||||
bool start_tls = 2;
|
||||
string base_dn = 3;
|
||||
string bind_dn = 4;
|
||||
string user_base = 5;
|
||||
repeated string user_object_classes = 6;
|
||||
repeated string user_filters = 7;
|
||||
google.protobuf.Duration timeout = 8;
|
||||
LDAPAttributes attributes = 9;
|
||||
}
|
||||
|
||||
message AzureADConfig {
|
||||
|
@ -11406,16 +11406,17 @@ message UpdateGoogleProviderResponse {
|
||||
|
||||
message AddLDAPProviderRequest {
|
||||
string name = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string host = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string port = 3 [(validate.rules).string = {max_len: 5}];
|
||||
bool tls = 4;
|
||||
string base_dn = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_object_class = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_unique_attribute = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string admin = 8 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string password = 9 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
zitadel.idp.v1.LDAPAttributes attributes = 10;
|
||||
zitadel.idp.v1.Options provider_options = 11;
|
||||
repeated string servers = 2 [(validate.rules).repeated = {min_items: 1, max_items: 20, items: {string: {min_len: 1, max_len: 200}}}];
|
||||
bool start_tls = 3;
|
||||
string base_dn = 4 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string bind_dn = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string bind_password = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_base = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
repeated string user_object_classes = 8 [(validate.rules).repeated = {min_items: 1, max_items: 20, items: {string: {min_len: 1, max_len: 200}}}];
|
||||
repeated string user_filters = 9 [(validate.rules).repeated = {min_items: 1, max_items: 20, items: {string: {min_len: 1, max_len: 200}}}];
|
||||
google.protobuf.Duration timeout = 10;
|
||||
zitadel.idp.v1.LDAPAttributes attributes = 11;
|
||||
zitadel.idp.v1.Options provider_options = 12;
|
||||
}
|
||||
|
||||
message AddLDAPProviderResponse {
|
||||
@ -11426,16 +11427,17 @@ message AddLDAPProviderResponse {
|
||||
message UpdateLDAPProviderRequest {
|
||||
string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string host = 3 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string port = 4 [(validate.rules).string = {max_len: 5}];
|
||||
bool tls = 5;
|
||||
string base_dn = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_object_class = 7 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string user_unique_attribute = 8 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string admin = 9 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string password = 10 [(validate.rules).string = {max_len: 200}];
|
||||
zitadel.idp.v1.LDAPAttributes attributes = 11;
|
||||
zitadel.idp.v1.Options provider_options = 12;
|
||||
repeated string servers = 3 [(validate.rules).repeated = {min_items: 1, max_items: 20, items: {string: {min_len: 1, max_len: 200}}}];
|
||||
bool start_tls = 4;
|
||||
string base_dn = 5 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string bind_dn = 6 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
string bind_password = 7 [(validate.rules).string = {max_len: 200}];
|
||||
string user_base = 8 [(validate.rules).string = {min_len: 1, max_len: 200}];
|
||||
repeated string user_object_classes = 9 [(validate.rules).repeated = {min_items: 1, max_items: 20, items: {string: {min_len: 1, max_len: 200}}}];
|
||||
repeated string user_filters = 10 [(validate.rules).repeated = {min_items: 1, max_items: 20, items: {string: {min_len: 1, max_len: 200}}}];
|
||||
google.protobuf.Duration timeout = 11;
|
||||
zitadel.idp.v1.LDAPAttributes attributes = 12;
|
||||
zitadel.idp.v1.Options provider_options = 13;
|
||||
}
|
||||
|
||||
message UpdateLDAPProviderResponse {
|
||||
|
Loading…
x
Reference in New Issue
Block a user