mirror of
https://github.com/0rangebananaspy/authelia.git
synced 2024-09-14 22:47:21 +07:00
perf(authentication): improve ldap dynamic replacement performance (#2239)
This change means we only check the filters for the existence of placeholders that cannot be replaced at startup. We then utilized cached results of that lookup for subsequent replacements.
This commit is contained in:
parent
c5c6bda8b0
commit
a3b14871ba
|
@ -183,10 +183,8 @@ authentication_backend:
|
|||
additional_users_dn: ou=users
|
||||
|
||||
## The users filter used in search queries to find the user profile based on input filled in login form.
|
||||
## Various placeholders are available in the user filter:
|
||||
## - {input} is a placeholder replaced by what the user inputs in the login form.
|
||||
## - {username_attribute} is a mandatory placeholder replaced by what is configured in `username_attribute`.
|
||||
## - {mail_attribute} is a placeholder replaced by what is configured in `mail_attribute`.
|
||||
## Various placeholders are available in the user filter which you can read about in the documentation which can
|
||||
## be found at: https://www.authelia.com/docs/configuration/authentication/ldap.html#users-filter-replacements
|
||||
##
|
||||
## Recommended settings are as follows:
|
||||
## - Microsoft Active Directory: (&({username_attribute}={input})(objectCategory=person)(objectClass=user))
|
||||
|
@ -202,16 +200,13 @@ authentication_backend:
|
|||
## i.e. with this set to OU=Groups and base_dn set to DC=a,DC=com; OU=Groups,DC=a,DC=com is searched for groups.
|
||||
additional_groups_dn: ou=groups
|
||||
|
||||
## The groups filter used in search queries to find the groups of the user.
|
||||
## - {input} is a placeholder replaced by what the user inputs in the login form.
|
||||
## - {username} is a placeholder replace by the username stored in LDAP (based on `username_attribute`).
|
||||
## - {dn} is a matcher replaced by the user distinguished name, aka, user DN.
|
||||
## - {username_attribute} is a placeholder replaced by what is configured in `username_attribute`.
|
||||
## - {mail_attribute} is a placeholder replaced by what is configured in `mail_attribute`.
|
||||
## The groups filter used in search queries to find the groups based on relevant authenticated user.
|
||||
## Various placeholders are available in the groups filter which you can read about in the documentation which can
|
||||
## be found at: https://www.authelia.com/docs/configuration/authentication/ldap.html#groups-filter-replacements
|
||||
##
|
||||
## If your groups use the `groupOfUniqueNames` structure use this instead:
|
||||
## (&(uniquemember={dn})(objectclass=groupOfUniqueNames))
|
||||
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||
## (&(uniqueMember={dn})(objectClass=groupOfUniqueNames))
|
||||
groups_filter: (&(member={dn})(objectClass=groupOfNames))
|
||||
|
||||
## The attribute holding the name of the group.
|
||||
# group_name_attribute: cn
|
||||
|
@ -221,7 +216,7 @@ authentication_backend:
|
|||
# mail_attribute: mail
|
||||
|
||||
## The attribute holding the display name of the user. This will be used to greet an authenticated user.
|
||||
# display_name_attribute: displayname
|
||||
# display_name_attribute: displayName
|
||||
|
||||
## The username and password of the admin user.
|
||||
user: cn=admin,dc=example,dc=com
|
||||
|
|
|
@ -29,10 +29,10 @@ authentication_backend:
|
|||
additional_users_dn: ou=users
|
||||
users_filter: (&({username_attribute}={input})(objectClass=person))
|
||||
additional_groups_dn: ou=groups
|
||||
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||
groups_filter: (&(member={dn})(objectClass=groupOfNames))
|
||||
group_name_attribute: cn
|
||||
mail_attribute: mail
|
||||
display_name_attribute: displayname
|
||||
display_name_attribute: displayName
|
||||
user: cn=admin,dc=example,dc=com
|
||||
password: password
|
||||
```
|
||||
|
@ -182,6 +182,28 @@ must be used if you wish to allow users to change or reset their password as Act
|
|||
uses a custom attribute for this, and an input format other implementations do not use. The long term
|
||||
intention of this is to have logical defaults for various RFC implementations of LDAP.
|
||||
|
||||
### Filter replacements
|
||||
|
||||
Various replacements occur in the user and groups filter. The replacements either occur at startup or upon an LDAP
|
||||
search.
|
||||
|
||||
#### Users filter replacements
|
||||
|
||||
|Placeholder |Phase |Replacement |
|
||||
|:----------------------:|:-----:|:--------------------------------------------------------------:|
|
||||
|{username_attribute} |startup|The [username attribute](#username_attribute) configured |
|
||||
|{mail_attribute} |startup|The [mail attribute](#mail_attribute) configured |
|
||||
|{display_name_attribute}|startup|The [display name attribute](#display_name_attribute) configured|
|
||||
|{input} |search |The input into the username field |
|
||||
|
||||
#### Groups filter replacements
|
||||
|
||||
|Placeholder |Phase |Replacement |
|
||||
|:----------------------:|:-----:|:-------------------------------------------------------------------------:|
|
||||
|{input} |search |The input into the username field |
|
||||
|{username} |search |The username from the profile lookup obtained from the [username attribute]|
|
||||
|{dn} |search |The distinguished name from the profile lookup |
|
||||
|
||||
### Defaults
|
||||
|
||||
The below tables describes the current attribute defaults for each implementation.
|
||||
|
@ -192,8 +214,8 @@ described by the Username column.
|
|||
|
||||
|Implementation |Username |Display Name|Mail|Group Name|
|
||||
|:-------------:|:------------:|:----------:|:--:|:--------:|
|
||||
|custom |n/a |displayname |mail|cn |
|
||||
|activedirectory|sAMAccountName|displayname |mail|cn |
|
||||
|custom |n/a |displayName |mail|cn |
|
||||
|activedirectory|sAMAccountName|displayName |mail|cn |
|
||||
|
||||
#### Filter defaults
|
||||
|
||||
|
@ -245,3 +267,7 @@ As of versions > `4.24.0` the `users_filter` must include the `username_attribut
|
|||
result in Authelia throwing an error.
|
||||
In versions <= `4.24.0` not including the `username_attribute` placeholder will cause issues with the session refresh
|
||||
and will result in session resets when the refresh interval has expired, default of 5 minutes.
|
||||
|
||||
[LDAP GeneralizedTime]: https://ldapwiki.com/wiki/GeneralizedTime
|
||||
[username attribute]: #username_attribute
|
||||
[TechNet wiki]: https://social.technet.microsoft.com/wiki/contents/articles/5392.active-directory-ldap-syntax-filters.aspx
|
|
@ -30,6 +30,12 @@ const (
|
|||
ldapOIDPasswdModifyExtension = "1.3.6.1.4.1.4203.1.11.1" // http://oidref.com/1.3.6.1.4.1.4203.1.11.1
|
||||
)
|
||||
|
||||
const (
|
||||
ldapPlaceholderInput = "{input}"
|
||||
ldapPlaceholderDistinguishedName = "{dn}"
|
||||
ldapPlaceholderUsername = "{username}"
|
||||
)
|
||||
|
||||
// PossibleMethods is the set of all possible 2FA methods.
|
||||
var PossibleMethods = []string{TOTP, U2F, Push}
|
||||
|
||||
|
|
|
@ -15,17 +15,28 @@ import (
|
|||
"github.com/authelia/authelia/internal/utils"
|
||||
)
|
||||
|
||||
// LDAPUserProvider is a provider using a LDAP or AD as a user database.
|
||||
// LDAPUserProvider is a UserProvider that connects to LDAP servers like ActiveDirectory, OpenLDAP, OpenDJ, FreeIPA, etc.
|
||||
type LDAPUserProvider struct {
|
||||
configuration schema.LDAPAuthenticationBackendConfiguration
|
||||
tlsConfig *tls.Config
|
||||
dialOpts ldap.DialOpt
|
||||
logger *logrus.Logger
|
||||
connectionFactory LDAPConnectionFactory
|
||||
usersBaseDN string
|
||||
groupsBaseDN string
|
||||
|
||||
// Automatically detected ldap features.
|
||||
supportExtensionPasswdModify bool
|
||||
|
||||
// Dynamically generated users values.
|
||||
usersBaseDN string
|
||||
usersAttributes []string
|
||||
usersFilterReplacementInput bool
|
||||
|
||||
// Dynamically generated groups values.
|
||||
groupsBaseDN string
|
||||
groupsAttributes []string
|
||||
groupsFilterReplacementInput bool
|
||||
groupsFilterReplacementUsername bool
|
||||
groupsFilterReplacementDN bool
|
||||
}
|
||||
|
||||
// NewLDAPUserProvider creates a new instance of LDAPUserProvider.
|
||||
|
@ -72,74 +83,12 @@ func newLDAPUserProvider(configuration schema.LDAPAuthenticationBackendConfigura
|
|||
connectionFactory: factory,
|
||||
}
|
||||
|
||||
provider.parseDynamicConfiguration()
|
||||
provider.parseDynamicUsersConfiguration()
|
||||
provider.parseDynamicGroupsConfiguration()
|
||||
|
||||
return provider
|
||||
}
|
||||
|
||||
func (p *LDAPUserProvider) parseDynamicConfiguration() {
|
||||
p.configuration.UsersFilter = strings.ReplaceAll(p.configuration.UsersFilter, "{username_attribute}", p.configuration.UsernameAttribute)
|
||||
p.configuration.UsersFilter = strings.ReplaceAll(p.configuration.UsersFilter, "{mail_attribute}", p.configuration.MailAttribute)
|
||||
p.configuration.UsersFilter = strings.ReplaceAll(p.configuration.UsersFilter, "{display_name_attribute}", p.configuration.DisplayNameAttribute)
|
||||
|
||||
p.logger.Tracef("Dynamically generated users filter is %s", p.configuration.UsersFilter)
|
||||
|
||||
if p.configuration.AdditionalUsersDN != "" {
|
||||
p.usersBaseDN = p.configuration.AdditionalUsersDN + "," + p.configuration.BaseDN
|
||||
} else {
|
||||
p.usersBaseDN = p.configuration.BaseDN
|
||||
}
|
||||
|
||||
p.logger.Tracef("Dynamically generated users BaseDN is %s", p.usersBaseDN)
|
||||
|
||||
if p.configuration.AdditionalGroupsDN != "" {
|
||||
p.groupsBaseDN = ldap.EscapeFilter(p.configuration.AdditionalGroupsDN + "," + p.configuration.BaseDN)
|
||||
} else {
|
||||
p.groupsBaseDN = p.configuration.BaseDN
|
||||
}
|
||||
|
||||
p.logger.Tracef("Dynamically generated groups BaseDN is %s", p.groupsBaseDN)
|
||||
}
|
||||
|
||||
func (p *LDAPUserProvider) checkServer() (err error) {
|
||||
conn, err := p.connect(p.configuration.User, p.configuration.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
searchRequest := ldap.NewSearchRequest("", ldap.ScopeBaseObject, ldap.NeverDerefAliases,
|
||||
1, 0, false, "(objectClass=*)", []string{ldapSupportedExtensionAttribute}, nil)
|
||||
|
||||
sr, err := conn.Search(searchRequest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(sr.Entries) != 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Iterate the attribute values to see what the server supports.
|
||||
for _, attr := range sr.Entries[0].Attributes {
|
||||
if attr.Name == ldapSupportedExtensionAttribute {
|
||||
p.logger.Tracef("LDAP Supported Extension OIDs: %s", strings.Join(attr.Values, ", "))
|
||||
|
||||
for _, oid := range attr.Values {
|
||||
if oid == ldapOIDPasswdModifyExtension {
|
||||
p.supportExtensionPasswdModify = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *LDAPUserProvider) connect(userDN string, password string) (LDAPConnection, error) {
|
||||
conn, err := p.connectionFactory.DialURL(p.configuration.URL, p.dialOpts)
|
||||
if err != nil {
|
||||
|
@ -197,34 +146,31 @@ type ldapUserProfile struct {
|
|||
Username string
|
||||
}
|
||||
|
||||
func (p *LDAPUserProvider) resolveUsersFilter(userFilter string, inputUsername string) string {
|
||||
inputUsername = p.ldapEscape(inputUsername)
|
||||
func (p *LDAPUserProvider) resolveUsersFilter(inputUsername string) (filter string) {
|
||||
filter = p.configuration.UsersFilter
|
||||
|
||||
// The {input} placeholder is replaced by the users username input.
|
||||
userFilter = strings.ReplaceAll(userFilter, "{input}", inputUsername)
|
||||
if p.usersFilterReplacementInput {
|
||||
// The {input} placeholder is replaced by the users username input.
|
||||
filter = strings.ReplaceAll(filter, ldapPlaceholderInput, p.ldapEscape(inputUsername))
|
||||
}
|
||||
|
||||
p.logger.Tracef("Computed user filter is %s", userFilter)
|
||||
p.logger.Tracef("Computed user filter is %s", filter)
|
||||
|
||||
return userFilter
|
||||
return filter
|
||||
}
|
||||
|
||||
func (p *LDAPUserProvider) getUserProfile(conn LDAPConnection, inputUsername string) (*ldapUserProfile, error) {
|
||||
userFilter := p.resolveUsersFilter(p.configuration.UsersFilter, inputUsername)
|
||||
|
||||
attributes := []string{"dn",
|
||||
p.configuration.DisplayNameAttribute,
|
||||
p.configuration.MailAttribute,
|
||||
p.configuration.UsernameAttribute}
|
||||
userFilter := p.resolveUsersFilter(inputUsername)
|
||||
|
||||
// Search for the given username.
|
||||
searchRequest := ldap.NewSearchRequest(
|
||||
p.usersBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
|
||||
1, 0, false, userFilter, attributes, nil,
|
||||
1, 0, false, userFilter, p.usersAttributes, nil,
|
||||
)
|
||||
|
||||
sr, err := conn.Search(searchRequest)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Cannot find user DN of user %s. Cause: %s", inputUsername, err)
|
||||
return nil, fmt.Errorf("cannot find user DN of user '%s'. Cause: %w", inputUsername, err)
|
||||
}
|
||||
|
||||
if len(sr.Entries) == 0 {
|
||||
|
@ -232,7 +178,7 @@ func (p *LDAPUserProvider) getUserProfile(conn LDAPConnection, inputUsername str
|
|||
}
|
||||
|
||||
if len(sr.Entries) > 1 {
|
||||
return nil, fmt.Errorf("Multiple users %s found", inputUsername)
|
||||
return nil, fmt.Errorf("multiple users %s found", inputUsername)
|
||||
}
|
||||
|
||||
userProfile := ldapUserProfile{
|
||||
|
@ -250,7 +196,7 @@ func (p *LDAPUserProvider) getUserProfile(conn LDAPConnection, inputUsername str
|
|||
|
||||
if attr.Name == p.configuration.UsernameAttribute {
|
||||
if len(attr.Values) != 1 {
|
||||
return nil, fmt.Errorf("User %s cannot have multiple value for attribute %s",
|
||||
return nil, fmt.Errorf("user '%s' cannot have multiple value for attribute '%s'",
|
||||
inputUsername, p.configuration.UsernameAttribute)
|
||||
}
|
||||
|
||||
|
@ -259,26 +205,33 @@ func (p *LDAPUserProvider) getUserProfile(conn LDAPConnection, inputUsername str
|
|||
}
|
||||
|
||||
if userProfile.DN == "" {
|
||||
return nil, fmt.Errorf("No DN has been found for user %s", inputUsername)
|
||||
return nil, fmt.Errorf("no DN has been found for user %s", inputUsername)
|
||||
}
|
||||
|
||||
return &userProfile, nil
|
||||
}
|
||||
|
||||
func (p *LDAPUserProvider) resolveGroupsFilter(inputUsername string, profile *ldapUserProfile) (string, error) { //nolint:unparam
|
||||
inputUsername = p.ldapEscape(inputUsername)
|
||||
func (p *LDAPUserProvider) resolveGroupsFilter(inputUsername string, profile *ldapUserProfile) (filter string, err error) { //nolint:unparam
|
||||
filter = p.configuration.GroupsFilter
|
||||
|
||||
// The {input} placeholder is replaced by the users username input.
|
||||
groupFilter := strings.ReplaceAll(p.configuration.GroupsFilter, "{input}", inputUsername)
|
||||
|
||||
if profile != nil {
|
||||
groupFilter = strings.ReplaceAll(groupFilter, "{username}", ldap.EscapeFilter(profile.Username))
|
||||
groupFilter = strings.ReplaceAll(groupFilter, "{dn}", ldap.EscapeFilter(profile.DN))
|
||||
if p.groupsFilterReplacementInput {
|
||||
// The {input} placeholder is replaced by the users username input.
|
||||
filter = strings.ReplaceAll(p.configuration.GroupsFilter, ldapPlaceholderInput, p.ldapEscape(inputUsername))
|
||||
}
|
||||
|
||||
p.logger.Tracef("Computed groups filter is %s", groupFilter)
|
||||
if profile != nil {
|
||||
if p.groupsFilterReplacementUsername {
|
||||
filter = strings.ReplaceAll(filter, ldapPlaceholderUsername, ldap.EscapeFilter(profile.Username))
|
||||
}
|
||||
|
||||
return groupFilter, nil
|
||||
if p.groupsFilterReplacementDN {
|
||||
filter = strings.ReplaceAll(filter, ldapPlaceholderDistinguishedName, ldap.EscapeFilter(profile.DN))
|
||||
}
|
||||
}
|
||||
|
||||
p.logger.Tracef("Computed groups filter is %s", filter)
|
||||
|
||||
return filter, nil
|
||||
}
|
||||
|
||||
// GetDetails retrieve the groups a user belongs to.
|
||||
|
@ -296,19 +249,19 @@ func (p *LDAPUserProvider) GetDetails(inputUsername string) (*UserDetails, error
|
|||
|
||||
groupsFilter, err := p.resolveGroupsFilter(inputUsername, profile)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to create group filter for user %s. Cause: %s", inputUsername, err)
|
||||
return nil, fmt.Errorf("unable to create group filter for user '%s'. Cause: %w", inputUsername, err)
|
||||
}
|
||||
|
||||
// Search for the given username.
|
||||
searchGroupRequest := ldap.NewSearchRequest(
|
||||
p.groupsBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
|
||||
0, 0, false, groupsFilter, []string{p.configuration.GroupNameAttribute}, nil,
|
||||
0, 0, false, groupsFilter, p.groupsAttributes, nil,
|
||||
)
|
||||
|
||||
sr, err := conn.Search(searchGroupRequest)
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to retrieve groups of user %s. Cause: %s", inputUsername, err)
|
||||
return nil, fmt.Errorf("unable to retrieve groups of user '%s'. Cause: %w", inputUsername, err)
|
||||
}
|
||||
|
||||
groups := make([]string, 0)
|
||||
|
@ -318,6 +271,7 @@ func (p *LDAPUserProvider) GetDetails(inputUsername string) (*UserDetails, error
|
|||
p.logger.Warningf("No groups retrieved from LDAP for user %s", inputUsername)
|
||||
break
|
||||
}
|
||||
|
||||
// Append all values of the document. Normally there should be only one per document.
|
||||
groups = append(groups, res.Attributes[0].Values...)
|
||||
}
|
||||
|
@ -334,14 +288,14 @@ func (p *LDAPUserProvider) GetDetails(inputUsername string) (*UserDetails, error
|
|||
func (p *LDAPUserProvider) UpdatePassword(inputUsername string, newPassword string) error {
|
||||
conn, err := p.connect(p.configuration.User, p.configuration.Password)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to update password. Cause: %s", err)
|
||||
return fmt.Errorf("unable to update password. Cause: %w", err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
profile, err := p.getUserProfile(conn, inputUsername)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to update password. Cause: %s", err)
|
||||
return fmt.Errorf("unable to update password. Cause: %w", err)
|
||||
}
|
||||
|
||||
switch {
|
||||
|
@ -370,7 +324,7 @@ func (p *LDAPUserProvider) UpdatePassword(inputUsername string, newPassword stri
|
|||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("Unable to update password. Cause: %s", err)
|
||||
return fmt.Errorf("unable to update password. Cause: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
103
internal/authentication/ldap_user_provider_startup.go
Normal file
103
internal/authentication/ldap_user_provider_startup.go
Normal file
|
@ -0,0 +1,103 @@
|
|||
package authentication
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/go-ldap/ldap/v3"
|
||||
)
|
||||
|
||||
func (p *LDAPUserProvider) checkServer() (err error) {
|
||||
conn, err := p.connect(p.configuration.User, p.configuration.Password)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer conn.Close()
|
||||
|
||||
searchRequest := ldap.NewSearchRequest("", ldap.ScopeBaseObject, ldap.NeverDerefAliases,
|
||||
1, 0, false, "(objectClass=*)", []string{ldapSupportedExtensionAttribute}, nil)
|
||||
|
||||
sr, err := conn.Search(searchRequest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(sr.Entries) != 1 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Iterate the attribute values to see what the server supports.
|
||||
for _, attr := range sr.Entries[0].Attributes {
|
||||
if attr.Name == ldapSupportedExtensionAttribute {
|
||||
p.logger.Tracef("LDAP Supported Extension OIDs: %s", strings.Join(attr.Values, ", "))
|
||||
|
||||
for _, oid := range attr.Values {
|
||||
if oid == ldapOIDPasswdModifyExtension {
|
||||
p.supportExtensionPasswdModify = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *LDAPUserProvider) parseDynamicUsersConfiguration() {
|
||||
p.configuration.UsersFilter = strings.ReplaceAll(p.configuration.UsersFilter, "{username_attribute}", p.configuration.UsernameAttribute)
|
||||
p.configuration.UsersFilter = strings.ReplaceAll(p.configuration.UsersFilter, "{mail_attribute}", p.configuration.MailAttribute)
|
||||
p.configuration.UsersFilter = strings.ReplaceAll(p.configuration.UsersFilter, "{display_name_attribute}", p.configuration.DisplayNameAttribute)
|
||||
|
||||
p.logger.Tracef("Dynamically generated users filter is %s", p.configuration.UsersFilter)
|
||||
|
||||
p.usersAttributes = []string{
|
||||
p.configuration.DisplayNameAttribute,
|
||||
p.configuration.MailAttribute,
|
||||
p.configuration.UsernameAttribute,
|
||||
}
|
||||
|
||||
if p.configuration.AdditionalUsersDN != "" {
|
||||
p.usersBaseDN = p.configuration.AdditionalUsersDN + "," + p.configuration.BaseDN
|
||||
} else {
|
||||
p.usersBaseDN = p.configuration.BaseDN
|
||||
}
|
||||
|
||||
p.logger.Tracef("Dynamically generated users BaseDN is %s", p.usersBaseDN)
|
||||
|
||||
if strings.Contains(p.configuration.UsersFilter, ldapPlaceholderInput) {
|
||||
p.usersFilterReplacementInput = true
|
||||
}
|
||||
|
||||
p.logger.Tracef("Detected user filter replacements that need to be resolved per lookup are: %s=%v",
|
||||
ldapPlaceholderInput, p.usersFilterReplacementInput)
|
||||
}
|
||||
|
||||
func (p *LDAPUserProvider) parseDynamicGroupsConfiguration() {
|
||||
p.groupsAttributes = []string{
|
||||
p.configuration.GroupNameAttribute,
|
||||
}
|
||||
|
||||
if p.configuration.AdditionalGroupsDN != "" {
|
||||
p.groupsBaseDN = ldap.EscapeFilter(p.configuration.AdditionalGroupsDN + "," + p.configuration.BaseDN)
|
||||
} else {
|
||||
p.groupsBaseDN = p.configuration.BaseDN
|
||||
}
|
||||
|
||||
p.logger.Tracef("Dynamically generated groups BaseDN is %s", p.groupsBaseDN)
|
||||
|
||||
if strings.Contains(p.configuration.GroupsFilter, ldapPlaceholderInput) {
|
||||
p.groupsFilterReplacementInput = true
|
||||
}
|
||||
|
||||
if strings.Contains(p.configuration.GroupsFilter, ldapPlaceholderUsername) {
|
||||
p.groupsFilterReplacementUsername = true
|
||||
}
|
||||
|
||||
if strings.Contains(p.configuration.GroupsFilter, ldapPlaceholderDistinguishedName) {
|
||||
p.groupsFilterReplacementDN = true
|
||||
}
|
||||
|
||||
p.logger.Tracef("Detected group filter replacements that need to be resolved per lookup are: input=%v, username=%v, dn=%v", p.groupsFilterReplacementInput, p.groupsFilterReplacementUsername, p.groupsFilterReplacementDN)
|
||||
}
|
|
@ -174,7 +174,7 @@ func TestShouldCheckLDAPServerExtensions(t *testing.T) {
|
|||
UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
Password: "password",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
|
@ -230,7 +230,7 @@ func TestShouldNotEnablePasswdModifyExtension(t *testing.T) {
|
|||
UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
Password: "password",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
|
@ -286,7 +286,7 @@ func TestShouldReturnCheckServerConnectError(t *testing.T) {
|
|||
UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
Password: "password",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
|
@ -318,7 +318,7 @@ func TestShouldReturnCheckServerSearchError(t *testing.T) {
|
|||
UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
Password: "password",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
|
@ -379,7 +379,7 @@ func TestShouldEscapeUserInput(t *testing.T) {
|
|||
UsersFilter: "(|({username_attribute}={input})({mail_attribute}={input}))",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
Password: "password",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
|
@ -414,11 +414,13 @@ func TestShouldCombineUsernameFilterAndUsersFilter(t *testing.T) {
|
|||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
},
|
||||
nil,
|
||||
mockFactory)
|
||||
|
||||
assert.True(t, ldapClient.usersFilterReplacementInput)
|
||||
|
||||
mockConn.EXPECT().
|
||||
Search(NewSearchRequestMatcher("(&(uid=john)(&(objectCategory=person)(objectClass=user)))")).
|
||||
Return(&ldap.SearchResult{}, nil)
|
||||
|
@ -456,7 +458,7 @@ func TestShouldNotCrashWhenGroupsAreNotRetrievedFromLDAP(t *testing.T) {
|
|||
Password: "password",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
UsersFilter: "uid={input}",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
|
@ -486,7 +488,7 @@ func TestShouldNotCrashWhenGroupsAreNotRetrievedFromLDAP(t *testing.T) {
|
|||
DN: "uid=test,dc=example,dc=com",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "displayname",
|
||||
Name: "displayName",
|
||||
Values: []string{"John Doe"},
|
||||
},
|
||||
{
|
||||
|
@ -587,7 +589,7 @@ func TestShouldReturnUsernameFromLDAP(t *testing.T) {
|
|||
Password: "password",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
UsersFilter: "uid={input}",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
|
@ -617,7 +619,7 @@ func TestShouldReturnUsernameFromLDAP(t *testing.T) {
|
|||
DN: "uid=test,dc=example,dc=com",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "displayname",
|
||||
Name: "displayName",
|
||||
Values: []string{"John Doe"},
|
||||
},
|
||||
{
|
||||
|
@ -658,7 +660,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtension(t *testing.T) {
|
|||
Password: "password",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
UsersFilter: "uid={input}",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
|
@ -716,7 +718,7 @@ func TestShouldUpdateUserPasswordPasswdModifyExtension(t *testing.T) {
|
|||
DN: "uid=test,dc=example,dc=com",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "displayname",
|
||||
Name: "displayName",
|
||||
Values: []string{"John Doe"},
|
||||
},
|
||||
{
|
||||
|
@ -822,7 +824,7 @@ func TestShouldUpdateUserPasswordActiveDirectory(t *testing.T) {
|
|||
DN: "cn=test,dc=example,dc=com",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "displayname",
|
||||
Name: "displayName",
|
||||
Values: []string{"John Doe"},
|
||||
},
|
||||
{
|
||||
|
@ -968,7 +970,7 @@ func TestShouldCheckValidUserPassword(t *testing.T) {
|
|||
Password: "password",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
UsersFilter: "uid={input}",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
|
@ -991,7 +993,7 @@ func TestShouldCheckValidUserPassword(t *testing.T) {
|
|||
DN: "uid=test,dc=example,dc=com",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "displayname",
|
||||
Name: "displayName",
|
||||
Values: []string{"John Doe"},
|
||||
},
|
||||
{
|
||||
|
@ -1035,7 +1037,7 @@ func TestShouldCheckInvalidUserPassword(t *testing.T) {
|
|||
Password: "password",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
UsersFilter: "uid={input}",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
|
@ -1058,7 +1060,7 @@ func TestShouldCheckInvalidUserPassword(t *testing.T) {
|
|||
DN: "uid=test,dc=example,dc=com",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "displayname",
|
||||
Name: "displayName",
|
||||
Values: []string{"John Doe"},
|
||||
},
|
||||
{
|
||||
|
@ -1102,7 +1104,7 @@ func TestShouldCallStartTLSWhenEnabled(t *testing.T) {
|
|||
Password: "password",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
UsersFilter: "uid={input}",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
|
@ -1136,7 +1138,7 @@ func TestShouldCallStartTLSWhenEnabled(t *testing.T) {
|
|||
DN: "uid=test,dc=example,dc=com",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "displayname",
|
||||
Name: "displayName",
|
||||
Values: []string{"John Doe"},
|
||||
},
|
||||
{
|
||||
|
@ -1176,7 +1178,7 @@ func TestShouldParseDynamicConfiguration(t *testing.T) {
|
|||
Password: "password",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input})({display_name_attribute}={input}))(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2)(!pwdLastSet=0))",
|
||||
GroupsFilter: "(&(|(member={dn})(member={input})(member={username}))(objectClass=group))",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
|
@ -1187,7 +1189,13 @@ func TestShouldParseDynamicConfiguration(t *testing.T) {
|
|||
nil,
|
||||
mockFactory)
|
||||
|
||||
assert.Equal(t, "(&(|(uid={input})(mail={input})(displayname={input}))(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2)(!pwdLastSet=0))", ldapClient.configuration.UsersFilter)
|
||||
assert.True(t, ldapClient.groupsFilterReplacementInput)
|
||||
assert.True(t, ldapClient.groupsFilterReplacementUsername)
|
||||
assert.True(t, ldapClient.groupsFilterReplacementDN)
|
||||
|
||||
assert.True(t, ldapClient.usersFilterReplacementInput)
|
||||
|
||||
assert.Equal(t, "(&(|(uid={input})(mail={input})(displayName={input}))(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2)(!pwdLastSet=0))", ldapClient.configuration.UsersFilter)
|
||||
assert.Equal(t, "(&(|(member={dn})(member={input})(member={username}))(objectClass=group))", ldapClient.configuration.GroupsFilter)
|
||||
assert.Equal(t, "ou=users,dc=example,dc=com", ldapClient.usersBaseDN)
|
||||
assert.Equal(t, "ou=groups,dc=example,dc=com", ldapClient.groupsBaseDN)
|
||||
|
@ -1207,7 +1215,7 @@ func TestShouldCallStartTLSWithInsecureSkipVerifyWhenSkipVerifyTrue(t *testing.T
|
|||
Password: "password",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
UsersFilter: "uid={input}",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
|
@ -1219,6 +1227,10 @@ func TestShouldCallStartTLSWithInsecureSkipVerifyWhenSkipVerifyTrue(t *testing.T
|
|||
nil,
|
||||
mockFactory)
|
||||
|
||||
assert.False(t, ldapClient.groupsFilterReplacementInput)
|
||||
assert.False(t, ldapClient.groupsFilterReplacementUsername)
|
||||
assert.False(t, ldapClient.groupsFilterReplacementDN)
|
||||
|
||||
dialURL := mockFactory.EXPECT().
|
||||
DialURL(gomock.Eq("ldap://127.0.0.1:389"), gomock.Any()).
|
||||
Return(mockConn, nil)
|
||||
|
@ -1244,7 +1256,7 @@ func TestShouldCallStartTLSWithInsecureSkipVerifyWhenSkipVerifyTrue(t *testing.T
|
|||
DN: "uid=test,dc=example,dc=com",
|
||||
Attributes: []*ldap.EntryAttribute{
|
||||
{
|
||||
Name: "displayname",
|
||||
Name: "displayName",
|
||||
Values: []string{"John Doe"},
|
||||
},
|
||||
{
|
||||
|
@ -1285,7 +1297,7 @@ func TestShouldReturnLDAPSAlreadySecuredWhenStartTLSAttempted(t *testing.T) {
|
|||
Password: "password",
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
UsersFilter: "uid={input}",
|
||||
AdditionalUsersDN: "ou=users",
|
||||
BaseDN: "dc=example,dc=com",
|
||||
|
|
|
@ -183,10 +183,8 @@ authentication_backend:
|
|||
additional_users_dn: ou=users
|
||||
|
||||
## The users filter used in search queries to find the user profile based on input filled in login form.
|
||||
## Various placeholders are available in the user filter:
|
||||
## - {input} is a placeholder replaced by what the user inputs in the login form.
|
||||
## - {username_attribute} is a mandatory placeholder replaced by what is configured in `username_attribute`.
|
||||
## - {mail_attribute} is a placeholder replaced by what is configured in `mail_attribute`.
|
||||
## Various placeholders are available in the user filter which you can read about in the documentation which can
|
||||
## be found at: https://www.authelia.com/docs/configuration/authentication/ldap.html#users-filter-replacements
|
||||
##
|
||||
## Recommended settings are as follows:
|
||||
## - Microsoft Active Directory: (&({username_attribute}={input})(objectCategory=person)(objectClass=user))
|
||||
|
@ -202,16 +200,13 @@ authentication_backend:
|
|||
## i.e. with this set to OU=Groups and base_dn set to DC=a,DC=com; OU=Groups,DC=a,DC=com is searched for groups.
|
||||
additional_groups_dn: ou=groups
|
||||
|
||||
## The groups filter used in search queries to find the groups of the user.
|
||||
## - {input} is a placeholder replaced by what the user inputs in the login form.
|
||||
## - {username} is a placeholder replace by the username stored in LDAP (based on `username_attribute`).
|
||||
## - {dn} is a matcher replaced by the user distinguished name, aka, user DN.
|
||||
## - {username_attribute} is a placeholder replaced by what is configured in `username_attribute`.
|
||||
## - {mail_attribute} is a placeholder replaced by what is configured in `mail_attribute`.
|
||||
## The groups filter used in search queries to find the groups based on relevant authenticated user.
|
||||
## Various placeholders are available in the groups filter which you can read about in the documentation which can
|
||||
## be found at: https://www.authelia.com/docs/configuration/authentication/ldap.html#groups-filter-replacements
|
||||
##
|
||||
## If your groups use the `groupOfUniqueNames` structure use this instead:
|
||||
## (&(uniquemember={dn})(objectclass=groupOfUniqueNames))
|
||||
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||
## (&(uniqueMember={dn})(objectClass=groupOfUniqueNames))
|
||||
groups_filter: (&(member={dn})(objectClass=groupOfNames))
|
||||
|
||||
## The attribute holding the name of the group.
|
||||
# group_name_attribute: cn
|
||||
|
@ -221,7 +216,7 @@ authentication_backend:
|
|||
# mail_attribute: mail
|
||||
|
||||
## The attribute holding the display name of the user. This will be used to greet an authenticated user.
|
||||
# display_name_attribute: displayname
|
||||
# display_name_attribute: displayName
|
||||
|
||||
## The username and password of the admin user.
|
||||
user: cn=admin,dc=example,dc=com
|
||||
|
|
|
@ -75,7 +75,7 @@ var DefaultLDAPAuthenticationBackendConfiguration = LDAPAuthenticationBackendCon
|
|||
Implementation: LDAPImplementationCustom,
|
||||
UsernameAttribute: "uid",
|
||||
MailAttribute: "mail",
|
||||
DisplayNameAttribute: "displayname",
|
||||
DisplayNameAttribute: "displayName",
|
||||
GroupNameAttribute: "cn",
|
||||
TLS: &TLSConfig{
|
||||
MinimumVersion: "TLS1.2",
|
||||
|
|
|
@ -23,7 +23,7 @@ authentication_backend:
|
|||
additional_users_dn: ou=users
|
||||
users_filter: (&({username_attribute}={input})(objectCategory=person)(objectClass=user))
|
||||
additional_groups_dn: ou=groups
|
||||
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||
groups_filter: (&(member={dn})(objectClass=groupOfNames))
|
||||
group_name_attribute: cn
|
||||
mail_attribute: mail
|
||||
user: cn=admin,dc=example,dc=com
|
||||
|
|
|
@ -23,7 +23,7 @@ authentication_backend:
|
|||
additional_users_dn: ou=users
|
||||
users_filter: (&({username_attribute}={input})(objectCategory=person)(objectClass=user))
|
||||
additional_groups_dn: ou=groups
|
||||
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||
groups_filter: (&(member={dn})(objectClass=groupOfNames))
|
||||
group_name_attribute: cn
|
||||
mail_attribute: mail
|
||||
user: cn=admin,dc=example,dc=com
|
||||
|
|
|
@ -24,7 +24,7 @@ authentication_backend:
|
|||
additional_users_dn: ou=users
|
||||
users_filter: (&({username_attribute}={input})(objectCategory=person)(objectClass=user))
|
||||
additional_groups_dn: ou=groups
|
||||
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||
groups_filter: (&(member={dn})(objectClass=groupOfNames))
|
||||
group_name_attribute: cn
|
||||
mail_attribute: mail
|
||||
user: cn=admin,dc=example,dc=com
|
||||
|
|
|
@ -25,7 +25,7 @@ authentication_backend:
|
|||
additional_users_dn: ou=users
|
||||
users_filter: (&({username_attribute}={input})(objectCategory=person)(objectClass=user))
|
||||
additional_groups_dn: ou=groups
|
||||
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||
groups_filter: (&(member={dn})(objectClass=groupOfNames))
|
||||
group_name_attribute: cn
|
||||
mail_attribute: mail
|
||||
user: cn=admin,dc=example,dc=com
|
||||
|
|
|
@ -387,7 +387,7 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldSetDefaultDisplayNameAttr
|
|||
suite.Assert().False(suite.validator.HasWarnings())
|
||||
suite.Assert().False(suite.validator.HasErrors())
|
||||
|
||||
suite.Assert().Equal("displayname", suite.configuration.LDAP.DisplayNameAttribute)
|
||||
suite.Assert().Equal("displayName", suite.configuration.LDAP.DisplayNameAttribute)
|
||||
}
|
||||
|
||||
func (suite *LDAPAuthenticationBackendSuite) TestShouldSetDefaultRefreshInterval() {
|
||||
|
|
|
@ -25,7 +25,7 @@ authentication_backend:
|
|||
additional_users_dn: ou=users
|
||||
users_filter: (&({username_attribute}={input})(objectClass=person))
|
||||
additional_groups_dn: ou=groups
|
||||
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||
groups_filter: (&(member={dn})(objectClass=groupOfNames))
|
||||
group_name_attribute: cn
|
||||
mail_attribute: mail
|
||||
display_name_attribute: displayName
|
||||
|
|
|
@ -26,7 +26,7 @@ authentication_backend:
|
|||
additional_users_dn: ou=users
|
||||
users_filter: (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person)(objectClass=inetOrgPerson)) # yamllint disable-line rule:line-length
|
||||
additional_groups_dn: ou=groups
|
||||
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||
groups_filter: (&(member={dn})(objectClass=groupOfNames))
|
||||
group_name_attribute: cn
|
||||
mail_attribute: mail
|
||||
display_name_attribute: displayName
|
||||
|
|
|
@ -1,78 +1,78 @@
|
|||
dn: cn=pwmanager,{{ LDAP_BASE_DN }}
|
||||
cn: Password Manager
|
||||
displayname: Password Manager
|
||||
displayName: Password Manager
|
||||
givenName: Password
|
||||
objectclass: inetOrgPerson
|
||||
objectclass: top
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: top
|
||||
mail: password.manager@authelia.com
|
||||
sn: Manager
|
||||
uid: pwmanager
|
||||
userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
|
||||
dn: ou=groups,{{ LDAP_BASE_DN }}
|
||||
objectclass: organizationalUnit
|
||||
objectclass: top
|
||||
objectClass: organizationalUnit
|
||||
objectClass: top
|
||||
ou: groups
|
||||
|
||||
dn: ou=users,{{ LDAP_BASE_DN }}
|
||||
objectclass: organizationalUnit
|
||||
objectclass: top
|
||||
objectClass: organizationalUnit
|
||||
objectClass: top
|
||||
ou: users
|
||||
|
||||
dn: cn=dev,ou=groups,{{ LDAP_BASE_DN }}
|
||||
cn: dev
|
||||
member: cn=John Doe (external),ou=users,{{ LDAP_BASE_DN }}
|
||||
member: cn=Bob Dylan,ou=users,{{ LDAP_BASE_DN }}
|
||||
objectclass: groupOfNames
|
||||
objectclass: top
|
||||
objectClass: groupOfNames
|
||||
objectClass: top
|
||||
|
||||
dn: cn=admins,ou=groups,{{ LDAP_BASE_DN }}
|
||||
cn: admins
|
||||
member: cn=John Doe (external),ou=users,{{ LDAP_BASE_DN }}
|
||||
objectclass: groupOfNames
|
||||
objectclass: top
|
||||
objectClass: groupOfNames
|
||||
objectClass: top
|
||||
|
||||
dn: cn=John Doe (external),ou=users,{{ LDAP_BASE_DN }}
|
||||
cn: John Doe (external)
|
||||
displayname: John Doe
|
||||
displayName: John Doe
|
||||
givenName: John
|
||||
objectclass: inetOrgPerson
|
||||
objectclass: top
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: top
|
||||
mail: john.doe@authelia.com
|
||||
sn: Doe
|
||||
uid: john
|
||||
userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
|
||||
dn: cn=Harry Potter,ou=users,{{ LDAP_BASE_DN }}
|
||||
cn: Harry Potter
|
||||
displayname: Harry Potter
|
||||
displayName: Harry Potter
|
||||
givenName: Harry
|
||||
objectclass: inetOrgPerson
|
||||
objectclass: top
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: top
|
||||
mail: harry.potter@authelia.com
|
||||
sn: Potter
|
||||
uid: harry
|
||||
userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
|
||||
dn: cn=Bob Dylan,ou=users,{{ LDAP_BASE_DN }}
|
||||
cn: Bob Dylan
|
||||
displayname: Bob Dylan
|
||||
displayName: Bob Dylan
|
||||
givenName: Bob
|
||||
objectclass: inetOrgPerson
|
||||
objectclass: top
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: top
|
||||
mail: bob.dylan@authelia.com
|
||||
sn: Dylan
|
||||
uid: bob
|
||||
userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
|
||||
dn: cn=James Dean,ou=users,{{ LDAP_BASE_DN }}
|
||||
cn: James Dean
|
||||
displayname: James Dean
|
||||
displayName: James Dean
|
||||
givenName: James
|
||||
objectclass: inetOrgPerson
|
||||
objectclass: top
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: top
|
||||
mail: james.dean@authelia.com
|
||||
sn: Dean
|
||||
uid: james
|
||||
userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ authentication_backend:
|
|||
additional_users_dn: ou=users
|
||||
users_filter: (&({username_attribute}={input})(objectClass=person))
|
||||
additional_groups_dn: ou=groups
|
||||
groups_filter: (&(member={dn})(objectclass=groupOfNames))
|
||||
groups_filter: (&(member={dn})(objectClass=groupOfNames))
|
||||
group_name_attribute: cn
|
||||
mail_attribute: mail
|
||||
display_name_attribute: displayName
|
||||
|
|
|
@ -1,67 +1,67 @@
|
|||
dn: ou=groups,dc=example,dc=com
|
||||
objectclass: organizationalUnit
|
||||
objectclass: top
|
||||
objectClass: organizationalUnit
|
||||
objectClass: top
|
||||
ou: groups
|
||||
|
||||
dn: ou=users,dc=example,dc=com
|
||||
objectclass: organizationalUnit
|
||||
objectclass: top
|
||||
objectClass: organizationalUnit
|
||||
objectClass: top
|
||||
ou: users
|
||||
|
||||
dn: cn=dev,ou=groups,dc=example,dc=com
|
||||
cn: dev
|
||||
member: uid=john,ou=users,dc=example,dc=com
|
||||
member: uid=bob,ou=users,dc=example,dc=com
|
||||
objectclass: groupOfNames
|
||||
objectclass: top
|
||||
objectClass: groupOfNames
|
||||
objectClass: top
|
||||
|
||||
dn: cn=admins,ou=groups,dc=example,dc=com
|
||||
cn: admins
|
||||
member: uid=john,ou=users,dc=example,dc=com
|
||||
objectclass: groupOfNames
|
||||
objectclass: top
|
||||
objectClass: groupOfNames
|
||||
objectClass: top
|
||||
|
||||
dn: uid=john,ou=users,dc=example,dc=com
|
||||
uid: john
|
||||
cn: john
|
||||
objectclass: inetOrgPerson
|
||||
objectclass: top
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: top
|
||||
mail: john.doe@authelia.com
|
||||
sn: John Doe
|
||||
userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
|
||||
dn: uid=harry,ou=users,dc=example,dc=com
|
||||
uid: harry
|
||||
cn: harry
|
||||
objectclass: inetOrgPerson
|
||||
objectclass: top
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: top
|
||||
mail: harry.potter@authelia.com
|
||||
sn: Harry Potter
|
||||
userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
|
||||
dn: uid=bob,ou=users,dc=example,dc=com
|
||||
uid: bob
|
||||
cn: bob
|
||||
objectclass: inetOrgPerson
|
||||
objectclass: top
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: top
|
||||
mail: bob.dylan@authelia.com
|
||||
sn: Bob Dylan
|
||||
userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
|
||||
dn: uid=james,ou=users,dc=example,dc=com
|
||||
uid: james
|
||||
cn: james
|
||||
objectclass: inetOrgPerson
|
||||
objectclass: top
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: top
|
||||
mail: james.dean@authelia.com
|
||||
sn: James Dean
|
||||
userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
|
||||
dn: uid=blackhat,ou=users,dc=example,dc=com
|
||||
uid: blackhat
|
||||
cn: blackhat
|
||||
objectclass: inetOrgPerson
|
||||
objectclass: top
|
||||
objectClass: inetOrgPerson
|
||||
objectClass: top
|
||||
mail: billy.blackhat@authelia.com
|
||||
sn: Billy BlackHat
|
||||
userpassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
userPassword: {CRYPT}$6$rounds=500000$jgiCMRyGXzoqpxS3$w2pJeZnnH8bwW3zzvoMWtTRfQYsHbWbD/hquuQ5vUeIyl9gdwBIt6RWk2S6afBA0DPakbeWgD/4SZPiS0hYtU/
|
||||
|
|
|
@ -26,6 +26,12 @@ const (
|
|||
// TLS10 is the textual representation of TLS 1.0.
|
||||
TLS10 = "1.0"
|
||||
|
||||
clean = "clean"
|
||||
tagged = "tagged"
|
||||
unknown = "unknown"
|
||||
)
|
||||
|
||||
const (
|
||||
// Hour is an int based representation of the time unit.
|
||||
Hour = time.Minute * 60
|
||||
|
||||
|
@ -40,11 +46,9 @@ const (
|
|||
|
||||
// Month is an int based representation of the time unit.
|
||||
Month = Year / 12
|
||||
)
|
||||
|
||||
clean = "clean"
|
||||
tagged = "tagged"
|
||||
unknown = "unknown"
|
||||
|
||||
const (
|
||||
errFmtLinuxNotFound = "open %s: no such file or directory"
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user