2023-02-15 08:14:59 +00:00
|
|
|
package ldap
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2023-03-24 15:18:56 +00:00
|
|
|
"time"
|
2023-02-15 08:14:59 +00:00
|
|
|
|
|
|
|
"github.com/zitadel/zitadel/internal/idp"
|
|
|
|
)
|
|
|
|
|
|
|
|
const DefaultPort = "389"
|
|
|
|
|
|
|
|
var _ idp.Provider = (*Provider)(nil)
|
|
|
|
|
|
|
|
// Provider is the [idp.Provider] implementation for a generic LDAP provider
|
|
|
|
type Provider struct {
|
2023-03-24 15:18:56 +00:00
|
|
|
name string
|
|
|
|
servers []string
|
|
|
|
startTLS bool
|
|
|
|
baseDN string
|
|
|
|
bindDN string
|
|
|
|
bindPassword string
|
|
|
|
userBase string
|
|
|
|
userObjectClasses []string
|
|
|
|
userFilters []string
|
|
|
|
timeout time.Duration
|
|
|
|
|
|
|
|
loginUrl string
|
2023-02-15 08:14:59 +00:00
|
|
|
|
|
|
|
isLinkingAllowed bool
|
|
|
|
isCreationAllowed bool
|
|
|
|
isAutoCreation bool
|
|
|
|
isAutoUpdate bool
|
|
|
|
|
|
|
|
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 ProviderOpts func(provider *Provider)
|
|
|
|
|
|
|
|
// WithLinkingAllowed allows end users to link the federated user to an existing one.
|
|
|
|
func WithLinkingAllowed() ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.isLinkingAllowed = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithCreationAllowed allows end users to create a new user using the federated information.
|
|
|
|
func WithCreationAllowed() ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.isCreationAllowed = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithAutoCreation enables that federated users are automatically created if not already existing.
|
|
|
|
func WithAutoCreation() ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.isAutoCreation = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithAutoUpdate enables that information retrieved from the provider is automatically used to update
|
|
|
|
// the existing user on each authentication.
|
|
|
|
func WithAutoUpdate() ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.isAutoUpdate = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-03-24 15:18:56 +00:00
|
|
|
// WithoutStartTLS configures to communication insecure with the LDAP server without startTLS
|
|
|
|
func WithoutStartTLS() ProviderOpts {
|
2023-02-15 08:14:59 +00:00
|
|
|
return func(p *Provider) {
|
2023-03-24 15:18:56 +00:00
|
|
|
p.startTLS = false
|
2023-02-15 08:14:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithCustomIDAttribute configures to map the LDAP attribute to the user, default is the uniqueUserAttribute
|
|
|
|
func WithCustomIDAttribute(name string) ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.idAttribute = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithFirstNameAttribute configures to map the LDAP attribute to the user
|
|
|
|
func WithFirstNameAttribute(name string) ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.firstNameAttribute = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithLastNameAttribute configures to map the LDAP attribute to the user
|
|
|
|
func WithLastNameAttribute(name string) ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.lastNameAttribute = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithDisplayNameAttribute configures to map the LDAP attribute to the user
|
|
|
|
func WithDisplayNameAttribute(name string) ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.displayNameAttribute = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithNickNameAttribute configures to map the LDAP attribute to the user
|
|
|
|
func WithNickNameAttribute(name string) ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.nickNameAttribute = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithPreferredUsernameAttribute configures to map the LDAP attribute to the user
|
|
|
|
func WithPreferredUsernameAttribute(name string) ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.preferredUsernameAttribute = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithEmailAttribute configures to map the LDAP attribute to the user
|
|
|
|
func WithEmailAttribute(name string) ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.emailAttribute = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithEmailVerifiedAttribute configures to map the LDAP attribute to the user
|
|
|
|
func WithEmailVerifiedAttribute(name string) ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.emailVerifiedAttribute = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithPhoneAttribute configures to map the LDAP attribute to the user
|
|
|
|
func WithPhoneAttribute(name string) ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.phoneAttribute = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithPhoneVerifiedAttribute configures to map the LDAP attribute to the user
|
|
|
|
func WithPhoneVerifiedAttribute(name string) ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.phoneVerifiedAttribute = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithPreferredLanguageAttribute configures to map the LDAP attribute to the user
|
|
|
|
func WithPreferredLanguageAttribute(name string) ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.preferredLanguageAttribute = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithAvatarURLAttribute configures to map the LDAP attribute to the user
|
|
|
|
func WithAvatarURLAttribute(name string) ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.avatarURLAttribute = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithProfileAttribute configures to map the LDAP attribute to the user
|
|
|
|
func WithProfileAttribute(name string) ProviderOpts {
|
|
|
|
return func(p *Provider) {
|
|
|
|
p.profileAttribute = name
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func New(
|
|
|
|
name string,
|
2023-03-24 15:18:56 +00:00
|
|
|
servers []string,
|
2023-02-15 08:14:59 +00:00
|
|
|
baseDN string,
|
2023-03-24 15:18:56 +00:00
|
|
|
bindDN string,
|
|
|
|
bindPassword string,
|
|
|
|
userBase string,
|
|
|
|
userObjectClasses []string,
|
|
|
|
userFilters []string,
|
|
|
|
timeout time.Duration,
|
2023-02-15 08:14:59 +00:00
|
|
|
loginUrl string,
|
|
|
|
options ...ProviderOpts,
|
|
|
|
) *Provider {
|
|
|
|
provider := &Provider{
|
2023-03-24 15:18:56 +00:00
|
|
|
name: name,
|
|
|
|
servers: servers,
|
|
|
|
startTLS: true,
|
|
|
|
baseDN: baseDN,
|
|
|
|
bindDN: bindDN,
|
|
|
|
bindPassword: bindPassword,
|
|
|
|
userBase: userBase,
|
|
|
|
userObjectClasses: userObjectClasses,
|
|
|
|
userFilters: userFilters,
|
|
|
|
timeout: timeout,
|
|
|
|
loginUrl: loginUrl,
|
2023-02-15 08:14:59 +00:00
|
|
|
}
|
|
|
|
for _, option := range options {
|
|
|
|
option(provider)
|
|
|
|
}
|
|
|
|
return provider
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Provider) Name() string {
|
|
|
|
return p.name
|
|
|
|
}
|
|
|
|
|
2023-11-13 08:25:26 +00:00
|
|
|
func (p *Provider) BeginAuth(ctx context.Context, state string, _ ...idp.Parameter) (idp.Session, error) {
|
2023-02-15 08:14:59 +00:00
|
|
|
return &Session{
|
|
|
|
Provider: p,
|
2023-03-24 15:18:56 +00:00
|
|
|
loginUrl: p.loginUrl + state,
|
2023-02-15 08:14:59 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2023-08-16 11:29:57 +00:00
|
|
|
func (p *Provider) GetSession(username, password string) *Session {
|
|
|
|
return &Session{
|
|
|
|
Provider: p,
|
|
|
|
User: username,
|
|
|
|
Password: password,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-15 08:14:59 +00:00
|
|
|
func (p *Provider) IsLinkingAllowed() bool {
|
|
|
|
return p.isLinkingAllowed
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Provider) IsCreationAllowed() bool {
|
|
|
|
return p.isCreationAllowed
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Provider) IsAutoCreation() bool {
|
|
|
|
return p.isAutoCreation
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Provider) IsAutoUpdate() bool {
|
|
|
|
return p.isAutoUpdate
|
|
|
|
}
|
2023-03-24 15:18:56 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|