feat(authentication): ldap memberof
Signed-off-by: James Elliott <james-d-elliott@users.noreply.github.com>feat-ldap-reset-filter
parent
65ecfe4b9a
commit
92cf5a186d
|
@ -317,7 +317,7 @@ authentication_backend:
|
||||||
## because it allows Authelia to offload the stateful operations
|
## because it allows Authelia to offload the stateful operations
|
||||||
## onto the LDAP service.
|
## onto the LDAP service.
|
||||||
# ldap:
|
# ldap:
|
||||||
## The address of the LDAP server to connect to in the address common syntax.
|
## The address of the directory server to connect to in the address common syntax.
|
||||||
## Format: [<scheme>://]<hostname>[:<port>].
|
## Format: [<scheme>://]<hostname>[:<port>].
|
||||||
## Square brackets indicate optional portions of the format. Scheme must be 'ldap', 'ldaps', or 'ldapi`.
|
## Square brackets indicate optional portions of the format. Scheme must be 'ldap', 'ldaps', or 'ldapi`.
|
||||||
## The default scheme is 'ldapi' if the address is an absolute path otherwise it's 'ldaps'.
|
## The default scheme is 'ldapi' if the address is an absolute path otherwise it's 'ldaps'.
|
||||||
|
@ -403,16 +403,6 @@ authentication_backend:
|
||||||
## See also: additional_users_dn, additional_groups_dn.
|
## See also: additional_users_dn, additional_groups_dn.
|
||||||
# base_dn: 'dc=example,dc=com'
|
# base_dn: 'dc=example,dc=com'
|
||||||
|
|
||||||
## The attribute holding the username of the user. This attribute is used to populate the username in the session
|
|
||||||
## information. For your information, Microsoft Active Directory usually uses 'sAMAccountName' and OpenLDAP usually
|
|
||||||
## uses 'uid'. Beware that this attribute holds the unique identifiers for the users binding the user and the
|
|
||||||
## configuration stored in database. Therefore only single value attributes are allowed and the value must never be
|
|
||||||
## changed once attributed to a user otherwise it would break the configuration for that user. Technically,
|
|
||||||
## non-unique attributes like 'mail' can also be used but we don't recommend using them, we instead advise to use
|
|
||||||
## a filter to perform alternative lookups and the attributes mentioned above (sAMAccountName and uid) to
|
|
||||||
## follow https://datatracker.ietf.org/doc/html/rfc2307.
|
|
||||||
# username_attribute: 'uid'
|
|
||||||
|
|
||||||
## The additional_users_dn is prefixed to base_dn and delimited by a comma when searching for users.
|
## The additional_users_dn is prefixed to base_dn and delimited by a comma when searching for users.
|
||||||
## i.e. with this set to OU=Users and base_dn set to DC=a,DC=com; OU=Users,DC=a,DC=com is searched for users.
|
## i.e. with this set to OU=Users and base_dn set to DC=a,DC=com; OU=Users,DC=a,DC=com is searched for users.
|
||||||
# additional_users_dn: 'ou=users'
|
# additional_users_dn: 'ou=users'
|
||||||
|
@ -443,15 +433,9 @@ authentication_backend:
|
||||||
## (&(uniqueMember={dn})(objectClass=groupOfUniqueNames))
|
## (&(uniqueMember={dn})(objectClass=groupOfUniqueNames))
|
||||||
# groups_filter: '(&(member={dn})(objectClass=groupOfNames))'
|
# groups_filter: '(&(member={dn})(objectClass=groupOfNames))'
|
||||||
|
|
||||||
## The attribute holding the name of the group.
|
## The group search mode to use. Options are 'filter' or 'memberof'. It's essential to read the docs if you wish to
|
||||||
# group_name_attribute: 'cn'
|
## use 'memberof'. Also 'filter' is the best choice for most use cases.
|
||||||
|
# group_search_mode: 'filter'
|
||||||
## The attribute holding the mail address of the user. If multiple email addresses are defined for a user, only the
|
|
||||||
## first one returned by the LDAP server is used.
|
|
||||||
# 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'
|
|
||||||
|
|
||||||
## Follow referrals returned by the server.
|
## Follow referrals returned by the server.
|
||||||
## This is especially useful for environments where read-only servers exist. Only implemented for write operations.
|
## This is especially useful for environments where read-only servers exist. Only implemented for write operations.
|
||||||
|
@ -462,6 +446,37 @@ authentication_backend:
|
||||||
## Password can also be set using a secret: https://www.authelia.com/c/secrets
|
## Password can also be set using a secret: https://www.authelia.com/c/secrets
|
||||||
# password: 'password'
|
# password: 'password'
|
||||||
|
|
||||||
|
## The attributes for users and objects from the directory server.
|
||||||
|
# attributes:
|
||||||
|
|
||||||
|
## The distinguished name attribute if your directory server supports it. Users should read the docs before
|
||||||
|
## configuring. Only used for the 'memberof' group search mode.
|
||||||
|
# distinguished_name: ''
|
||||||
|
|
||||||
|
## The attribute holding the username of the user. This attribute is used to populate the username in the session
|
||||||
|
## information. For your information, Microsoft Active Directory usually uses 'sAMAccountName' and OpenLDAP
|
||||||
|
## usually uses 'uid'. Beware that this attribute holds the unique identifiers for the users binding the user and
|
||||||
|
## the configuration stored in database; therefore only single value attributes are allowed and the value must
|
||||||
|
## never be changed once attributed to a user otherwise it would break the configuration for that user.
|
||||||
|
## Technically non-unique attributes like 'mail' can also be used but we don't recommend using them, we instead
|
||||||
|
## advise to use a filter to perform alternative lookups and the attributes mentioned above
|
||||||
|
## (sAMAccountName and uid) to follow https://datatracker.ietf.org/doc/html/rfc2307.
|
||||||
|
# username: 'uid'
|
||||||
|
|
||||||
|
## The attribute holding the display name of the user. This will be used to greet an authenticated user.
|
||||||
|
# display_name: 'displayName'
|
||||||
|
|
||||||
|
## The attribute holding the mail address of the user. If multiple email addresses are defined for a user, only
|
||||||
|
## the first one returned by the directory server is used.
|
||||||
|
# mail: 'mail'
|
||||||
|
|
||||||
|
## The attribute which provides distinguished names of groups an object is a member of.
|
||||||
|
## Only used for the 'memberof' group search mode.
|
||||||
|
# member_of: 'memberOf'
|
||||||
|
|
||||||
|
## The attribute holding the name of the group.
|
||||||
|
# group_name: 'cn'
|
||||||
|
|
||||||
##
|
##
|
||||||
## File (Authentication Provider)
|
## File (Authentication Provider)
|
||||||
##
|
##
|
||||||
|
|
|
@ -101,16 +101,20 @@ authentication_backend:
|
||||||
base_dn: 'DC=example,DC=com'
|
base_dn: 'DC=example,DC=com'
|
||||||
additional_users_dn: 'OU=users'
|
additional_users_dn: 'OU=users'
|
||||||
users_filter: '(&({username_attribute}={input})(objectClass=person))'
|
users_filter: '(&({username_attribute}={input})(objectClass=person))'
|
||||||
username_attribute: 'uid'
|
|
||||||
mail_attribute: 'mail'
|
|
||||||
display_name_attribute: 'displayName'
|
|
||||||
additional_groups_dn: 'OU=groups'
|
additional_groups_dn: 'OU=groups'
|
||||||
groups_filter: '(&(member={dn})(objectClass=groupOfNames))'
|
groups_filter: '(&(member={dn})(objectClass=groupOfNames))'
|
||||||
group_name_attribute: 'cn'
|
group_search_mode: 'filter'
|
||||||
permit_referrals: false
|
permit_referrals: false
|
||||||
permit_unauthenticated_bind: false
|
permit_unauthenticated_bind: false
|
||||||
user: 'CN=admin,DC=example,DC=com'
|
user: 'CN=admin,DC=example,DC=com'
|
||||||
password: 'password'
|
password: 'password'
|
||||||
|
attributes:
|
||||||
|
distinguished_name: 'distinguishedName'
|
||||||
|
username: 'uid'
|
||||||
|
display_name: 'displayName'
|
||||||
|
mail: 'mail'
|
||||||
|
member_of: 'memberOf'
|
||||||
|
group_name: 'cn'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
@ -209,66 +213,33 @@ The LDAP filter to narrow down which users are valid. This is important to set c
|
||||||
The default value is dependent on the [implementation](#implementation), refer to the
|
The default value is dependent on the [implementation](#implementation), refer to the
|
||||||
[attribute defaults](../../reference/guides/ldap.md#attribute-defaults) for more information.
|
[attribute defaults](../../reference/guides/ldap.md#attribute-defaults) for more information.
|
||||||
|
|
||||||
### username_attribute
|
|
||||||
|
|
||||||
{{< confkey type="string" required="situational" >}}
|
|
||||||
|
|
||||||
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
|
||||||
default negating this requirement. Refer to the [attribute defaults](../../reference/guides/ldap.md#attribute-defaults)
|
|
||||||
for more information.*
|
|
||||||
|
|
||||||
The LDAP attribute that maps to the username in *Authelia*. This must contain the `{username_attribute}`
|
|
||||||
[placeholder](../../reference/guides/ldap.md#users-filter-replacements).
|
|
||||||
|
|
||||||
### mail_attribute
|
|
||||||
|
|
||||||
{{< confkey type="string" required="situational" >}}
|
|
||||||
|
|
||||||
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
|
||||||
default negating this requirement. Refer to the [attribute defaults](../../reference/guides/ldap.md#attribute-defaults)
|
|
||||||
for more information.*
|
|
||||||
|
|
||||||
The attribute to retrieve which contains the users email addresses. This is important for the device registration and
|
|
||||||
password reset processes. The user must have an email address in order for Authelia to perform identity verification
|
|
||||||
when a user attempts to reset their password or register a second factor device.
|
|
||||||
|
|
||||||
### display_name_attribute
|
|
||||||
|
|
||||||
{{< confkey type="string" required="situational" >}}
|
|
||||||
|
|
||||||
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
|
||||||
default negating this requirement. Refer to the [attribute defaults](#attribute-defaults) for more information.*
|
|
||||||
|
|
||||||
The attribute to retrieve which is shown on the Web UI to the user when they log in.
|
|
||||||
|
|
||||||
### additional_groups_dn
|
### additional_groups_dn
|
||||||
|
|
||||||
{{< confkey type="string" required="no" >}}
|
{{< confkey type="string" required="no" >}}
|
||||||
|
|
||||||
Similar to [additional_users_dn](#additional_users_dn) but it applies to group searches.
|
Similar to [additional_users_dn](#additionalusersdn) but it applies to group searches.
|
||||||
|
|
||||||
### groups_filter
|
### groups_filter
|
||||||
|
|
||||||
{{< confkey type="string" required="situational" >}}
|
{{< confkey type="string" required="situational" >}}
|
||||||
|
|
||||||
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
||||||
default negating this requirement. Refer to the [filter defaults](#filter-defaults) for more information.*
|
default negating this requirement. Refer to the [filter defaults](../../reference/guides/ldap.md#filter-defaults) for
|
||||||
|
more information.*
|
||||||
|
|
||||||
Similar to [users_filter](#users_filter) but it applies to group searches. In order to include groups the member is not
|
Similar to [users_filter](#usersfilter) but it applies to group searches. In order to include groups the member is not
|
||||||
a direct member of, but is a member of another group that is a member of those (i.e. recursive groups), you may try
|
a direct member of, but is a member of another group that is a member of those (i.e. recursive groups), you may try
|
||||||
using the following filter which is currently only tested against Microsoft Active Directory:
|
using the following filter which is currently only tested against Microsoft Active Directory:
|
||||||
|
|
||||||
`(&(member:1.2.840.113556.1.4.1941:={dn})(objectClass=group)(objectCategory=group))`
|
`(&(member:1.2.840.113556.1.4.1941:={dn})(objectClass=group)(objectCategory=group))`
|
||||||
|
|
||||||
### group_name_attribute
|
### group_search_mode
|
||||||
|
|
||||||
{{< confkey type="string" required="situational" >}}
|
{{< confkey type="string" default="filter" required="no" >}}
|
||||||
|
|
||||||
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
The group search mode controls how user groups are discovered. The default of `filter` directly uses the filter to
|
||||||
default negating this requirement. Refer to the [attribute defaults](#attribute-defaults) for more
|
determine the result. The `memberof` experimental mode does another special filtered search. See the
|
||||||
information.*
|
[Reference Documentation](../../reference/guides/ldap.md#group-search-modes) for more information.
|
||||||
|
|
||||||
The LDAP attribute that is used by Authelia to determine the group name.
|
|
||||||
|
|
||||||
### permit_referrals
|
### permit_referrals
|
||||||
|
|
||||||
|
@ -313,6 +284,71 @@ It's __strongly recommended__ this is a
|
||||||
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string) with 64 or more
|
[Random Alphanumeric String](../../reference/guides/generating-secure-values.md#generating-a-random-alphanumeric-string) with 64 or more
|
||||||
characters and the user password is changed to this value.
|
characters and the user password is changed to this value.
|
||||||
|
|
||||||
|
### attributes
|
||||||
|
|
||||||
|
The following options configure The directory server attribute mappings.
|
||||||
|
|
||||||
|
#### distinguished_name
|
||||||
|
|
||||||
|
{{< confkey type="string" required="situational" >}}
|
||||||
|
|
||||||
|
*__Note:__ This option is technically not required however it is required when using the group search mode
|
||||||
|
`memberof` replacement `{memberof:dn}`.*
|
||||||
|
|
||||||
|
The directory server attribute which contains the distinguished name, primarily used to perform filtered searches. There
|
||||||
|
is a clear distinction between the actual distinguished name and a distinguished name attribute, all directories have
|
||||||
|
distinguished names for objects, but not all have an attribute representing this that can be searched on.
|
||||||
|
|
||||||
|
The only known support at this time is with Active Directory.
|
||||||
|
|
||||||
|
#### username
|
||||||
|
|
||||||
|
{{< confkey type="string" required="situational" >}}
|
||||||
|
|
||||||
|
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
||||||
|
default negating this requirement. Refer to the [attribute defaults] for more information.*
|
||||||
|
|
||||||
|
The directory server attribute that maps to the username in *Authelia*. This must contain the `{username_attribute}` [placeholder].
|
||||||
|
|
||||||
|
#### display_name
|
||||||
|
|
||||||
|
{{< confkey type="string" required="situational" >}}
|
||||||
|
|
||||||
|
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
||||||
|
default negating this requirement. Refer to the [attribute defaults] for more information.*
|
||||||
|
|
||||||
|
The directory server attribute to retrieve which is shown on the Web UI to the user when they log in.
|
||||||
|
|
||||||
|
#### mail
|
||||||
|
|
||||||
|
{{< confkey type="string" required="situational" >}}
|
||||||
|
|
||||||
|
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
||||||
|
default negating this requirement. Refer to the [attribute defaults] for more information.*
|
||||||
|
|
||||||
|
The directory server attribute to retrieve which contains the users email addresses. This is important for the device
|
||||||
|
registration and password reset processes. The user must have an email address in order for Authelia to perform
|
||||||
|
identity verification when a user attempts to reset their password or register a second factor device.
|
||||||
|
|
||||||
|
#### member_of
|
||||||
|
|
||||||
|
{{< confkey type="string" required="situational" >}}
|
||||||
|
|
||||||
|
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
||||||
|
default negating this requirement. Refer to the [attribute defaults] for more information.*
|
||||||
|
|
||||||
|
The directory server attribute which contains the groups a user is a member of. This is currently only used for the
|
||||||
|
`memberof` group search mode.
|
||||||
|
|
||||||
|
#### group_name
|
||||||
|
|
||||||
|
{{< confkey type="string" required="situational" >}}
|
||||||
|
|
||||||
|
*__Note:__ This option is technically required however the [implementation](#implementation) option can implicitly set a
|
||||||
|
default negating this requirement. Refer to the [attribute defaults] for more information.*
|
||||||
|
|
||||||
|
The directory server attribute that is used by Authelia to determine the group name.
|
||||||
|
|
||||||
## Refresh Interval
|
## Refresh Interval
|
||||||
|
|
||||||
It's recommended you either use the default [refresh interval](introduction.md#refreshinterval) or configure this to
|
It's recommended you either use the default [refresh interval](introduction.md#refreshinterval) or configure this to
|
||||||
|
@ -332,6 +368,8 @@ for your users.
|
||||||
|
|
||||||
- [LDAP Reference Guide](../../reference/guides/ldap.md)
|
- [LDAP Reference Guide](../../reference/guides/ldap.md)
|
||||||
|
|
||||||
[username attribute]: #usernameattribute
|
[username attribute]: #username
|
||||||
[TechNet wiki]: https://social.technet.microsoft.com/wiki/contents/articles/5392.active-directory-ldap-syntax-filters.aspx
|
[TechNet wiki]: https://social.technet.microsoft.com/wiki/contents/articles/5392.active-directory-ldap-syntax-filters.aspx
|
||||||
[RFC2307]: https://datatracker.ietf.org/doc/html/rfc2307
|
[RFC2307]: https://datatracker.ietf.org/doc/html/rfc2307
|
||||||
|
[attribute defaults]: ../../reference/guides/ldap.md#attribute-defaults
|
||||||
|
[placeholder]: ../../reference/guides/ldap.md#users-filter-replacements
|
||||||
|
|
|
@ -24,16 +24,24 @@ server:
|
||||||
authz:
|
authz:
|
||||||
forward-auth:
|
forward-auth:
|
||||||
implementation: 'ForwardAuth'
|
implementation: 'ForwardAuth'
|
||||||
authn_strategies: []
|
authn_strategies:
|
||||||
|
- name: 'HeaderProxyAuthorization'
|
||||||
|
- name: 'CookieSession'
|
||||||
ext-authz:
|
ext-authz:
|
||||||
implementation: 'ExtAuthz'
|
implementation: 'ExtAuthz'
|
||||||
authn_strategies: []
|
authn_strategies:
|
||||||
|
- name: 'HeaderProxyAuthorization'
|
||||||
|
- name: 'CookieSession'
|
||||||
auth-request:
|
auth-request:
|
||||||
implementation: 'AuthRequest'
|
implementation: 'AuthRequest'
|
||||||
authn_strategies: []
|
authn_strategies:
|
||||||
|
- name: 'HeaderAuthRequestProxyAuthorization'
|
||||||
|
- name: 'CookieSession'
|
||||||
legacy:
|
legacy:
|
||||||
implementation: 'Legacy'
|
implementation: 'Legacy'
|
||||||
authn_strategies: []
|
authn_strategies:
|
||||||
|
- name: 'HeaderLegacy'
|
||||||
|
- name: 'CookieSession'
|
||||||
```
|
```
|
||||||
|
|
||||||
## Name
|
## Name
|
||||||
|
|
|
@ -92,35 +92,35 @@ Use this [Standalone Example](#standalone-example) if you want to use
|
||||||
version: "3.8"
|
version: "3.8"
|
||||||
secrets:
|
secrets:
|
||||||
JWT_SECRET:
|
JWT_SECRET:
|
||||||
file: ${PWD}/data/authelia/secrets/JWT_SECRET
|
file: '${PWD}/data/authelia/secrets/JWT_SECRET'
|
||||||
SESSION_SECRET:
|
SESSION_SECRET:
|
||||||
file: ${PWD}/data/authelia/secrets/SESSION_SECRET
|
file: '${PWD}/data/authelia/secrets/SESSION_SECRET'
|
||||||
STORAGE_PASSWORD:
|
STORAGE_PASSWORD:
|
||||||
file: ${PWD}/data/authelia/secrets/STORAGE_PASSWORD
|
file: '${PWD}/data/authelia/secrets/STORAGE_PASSWORD'
|
||||||
STORAGE_ENCRYPTION_KEY:
|
STORAGE_ENCRYPTION_KEY:
|
||||||
file: ${PWD}/data/authelia/secrets/STORAGE_ENCRYPTION_KEY
|
file: '${PWD}/data/authelia/secrets/STORAGE_ENCRYPTION_KEY'
|
||||||
services:
|
services:
|
||||||
authelia:
|
authelia:
|
||||||
container_name: authelia
|
container_name: 'authelia'
|
||||||
image: docker.io/authelia/authelia:latest
|
image: 'docker.io/authelia/authelia:latest'
|
||||||
restart: unless-stopped
|
restart: 'unless-stopped'
|
||||||
networks:
|
networks:
|
||||||
net:
|
net:
|
||||||
aliases: []
|
aliases: []
|
||||||
expose:
|
expose:
|
||||||
- 9091
|
- 9091
|
||||||
secrets: [JWT_SECRET, SESSION_SECRET, STORAGE_PASSWORD, STORAGE_ENCRYPTION_KEY]
|
secrets: ['JWT_SECRET', 'SESSION_SECRET', 'STORAGE_PASSWORD', 'STORAGE_ENCRYPTION_KEY']
|
||||||
environment:
|
environment:
|
||||||
AUTHELIA_JWT_SECRET_FILE: /run/secrets/JWT_SECRET
|
AUTHELIA_JWT_SECRET_FILE: '/run/secrets/JWT_SECRET'
|
||||||
AUTHELIA_SESSION_SECRET_FILE: /run/secrets/SESSION_SECRET
|
AUTHELIA_SESSION_SECRET_FILE: '/run/secrets/SESSION_SECRET'
|
||||||
AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE: /run/secrets/STORAGE_PASSWORD
|
AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE: '/run/secrets/STORAGE_PASSWORD'
|
||||||
AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE: /run/secrets/STORAGE_ENCRYPTION_KEY
|
AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE: '/run/secrets/STORAGE_ENCRYPTION_KEY'
|
||||||
volumes:
|
volumes:
|
||||||
- ${PWD}/data/authelia/config:/config
|
- '${PWD}/data/authelia/config:/config'
|
||||||
networks:
|
networks:
|
||||||
net:
|
net:
|
||||||
external: true
|
external: true
|
||||||
name: net
|
name: 'net'
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
{{< /details >}}
|
{{< /details >}}
|
||||||
|
@ -136,26 +136,26 @@ Use this [Standalone Example](#standalone-example) if you want to use a standard
|
||||||
version: "3.8"
|
version: "3.8"
|
||||||
services:
|
services:
|
||||||
authelia:
|
authelia:
|
||||||
container_name: authelia
|
container_name: 'authelia'
|
||||||
image: docker.io/authelia/authelia:latest
|
image: 'docker.io/authelia/authelia:latest'
|
||||||
restart: unless-stopped
|
restart: 'unless-stopped'
|
||||||
networks:
|
networks:
|
||||||
net:
|
net:
|
||||||
aliases: []
|
aliases: []
|
||||||
expose:
|
expose:
|
||||||
- 9091
|
- 9091
|
||||||
environment:
|
environment:
|
||||||
AUTHELIA_JWT_SECRET_FILE: /secrets/JWT_SECRET
|
AUTHELIA_JWT_SECRET_FILE: '/secrets/JWT_SECRET'
|
||||||
AUTHELIA_SESSION_SECRET_FILE: /secrets/SESSION_SECRET
|
AUTHELIA_SESSION_SECRET_FILE: '/secrets/SESSION_SECRET'
|
||||||
AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE: /secrets/STORAGE_PASSWORD
|
AUTHELIA_STORAGE_POSTGRES_PASSWORD_FILE: '/secrets/STORAGE_PASSWORD'
|
||||||
AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE: /secrets/STORAGE_ENCRYPTION_KEY
|
AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE: '/secrets/STORAGE_ENCRYPTION_KEY'
|
||||||
volumes:
|
volumes:
|
||||||
- ${PWD}/data/authelia/config:/config
|
- '${PWD}/data/authelia/config:/config'
|
||||||
- ${PWD}/data/authelia/secrets:/secrets
|
- '${PWD}/data/authelia/secrets:/secrets'
|
||||||
networks:
|
networks:
|
||||||
net:
|
net:
|
||||||
external: true
|
external: true
|
||||||
name: net
|
name: 'net'
|
||||||
```
|
```
|
||||||
...
|
...
|
||||||
{{< /details >}}
|
{{< /details >}}
|
||||||
|
|
|
@ -55,14 +55,16 @@ In your Authelia configuration you will need to enter and update the following v
|
||||||
base_dn: DC=example,DC=com
|
base_dn: DC=example,DC=com
|
||||||
additional_users_dn: OU=users
|
additional_users_dn: OU=users
|
||||||
users_filter: (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))
|
users_filter: (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))
|
||||||
username_attribute: uid
|
|
||||||
mail_attribute: mail
|
|
||||||
display_name_attribute: displayName
|
|
||||||
additional_groups_dn: OU=groups
|
additional_groups_dn: OU=groups
|
||||||
groups_filter: (&(member=UID={input},OU=users,DC=example,DC=com)(objectClass=groupOfNames))
|
groups_filter: (&(member=UID={input},OU=users,DC=example,DC=com)(objectClass=groupOfNames))
|
||||||
group_name_attribute: cn
|
|
||||||
user: UID=authelia,OU=service accounts,DC=example,DC=com
|
user: UID=authelia,OU=service accounts,DC=example,DC=com
|
||||||
password: "SUPER_COMPLEX_PASSWORD"
|
password: "SUPER_COMPLEX_PASSWORD"
|
||||||
|
attributes:
|
||||||
|
distinguished_name: 'distinguishedName'
|
||||||
|
username: 'uid'
|
||||||
|
mail: 'mail'
|
||||||
|
member_of: 'memberOf'
|
||||||
|
group_name: 'cn'
|
||||||
```
|
```
|
||||||
Following this, restart Authelia, and you should be able to begin using LDAP integration for your user logins, with
|
Following this, restart Authelia, and you should be able to begin using LDAP integration for your user logins, with
|
||||||
Authelia taking the email attribute for users straight from the 'mail' attribute within the LDAP object.
|
Authelia taking the email attribute for users straight from the 'mail' attribute within the LDAP object.
|
||||||
|
@ -100,16 +102,18 @@ In your Authelia configuration you will need to enter and update the following v
|
||||||
skip_verify: true
|
skip_verify: true
|
||||||
minimum_version: TLS1.2
|
minimum_version: TLS1.2
|
||||||
base_dn: dc=example,DC=com
|
base_dn: dc=example,DC=com
|
||||||
username_attribute: uid
|
|
||||||
additional_users_dn: CN=users,CN=accounts
|
additional_users_dn: CN=users,CN=accounts
|
||||||
users_filter: (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))
|
users_filter: (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))
|
||||||
additional_groups_dn: OU=groups
|
additional_groups_dn: OU=groups
|
||||||
groups_filter: (&(member=UID={input},CN=users,CN=accounts,DC=example,DC=com)(objectClass=groupOfNames))
|
groups_filter: (&(member=UID={input},CN=users,CN=accounts,DC=example,DC=com)(objectClass=groupOfNames))
|
||||||
group_name_attribute: cn
|
|
||||||
mail_attribute: mail
|
|
||||||
display_name_attribute: displayName
|
|
||||||
user: UID=authelia,CN=users,CN=accounts,DC=example,DC=com
|
user: UID=authelia,CN=users,CN=accounts,DC=example,DC=com
|
||||||
password: "SUPER_COMPLEX_PASSWORD"
|
password: "SUPER_COMPLEX_PASSWORD"
|
||||||
|
attributes:
|
||||||
|
distinguished_name: 'distinguishedName'
|
||||||
|
username: 'uid'
|
||||||
|
mail: 'mail'
|
||||||
|
member_of: 'memberOf'
|
||||||
|
group_name: 'cn'
|
||||||
```
|
```
|
||||||
Following this, restart Authelia, and you should be able to begin using LDAP integration for your user logins, with
|
Following this, restart Authelia, and you should be able to begin using LDAP integration for your user logins, with
|
||||||
Authelia taking the email attribute for users straight from the 'mail' attribute within the LDAP object.
|
Authelia taking the email attribute for users straight from the 'mail' attribute within the LDAP object.
|
||||||
|
@ -139,19 +143,21 @@ ldap:
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
start_tls: false
|
start_tls: false
|
||||||
base_dn: dc=example,DC=com
|
base_dn: dc=example,DC=com
|
||||||
username_attribute: uid
|
|
||||||
additional_users_dn: OU=people
|
additional_users_dn: OU=people
|
||||||
# To allow sign in both with username and email, one can use a filter like
|
# To allow sign in both with username and email, one can use a filter like
|
||||||
# (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))
|
# (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))
|
||||||
users_filter: (&({username_attribute}={input})(objectClass=person))
|
users_filter: (&({username_attribute}={input})(objectClass=person))
|
||||||
additional_groups_dn: OU=groups
|
additional_groups_dn: OU=groups
|
||||||
groups_filter: (member={dn})
|
groups_filter: (member={dn})
|
||||||
group_name_attribute: cn
|
|
||||||
mail_attribute: mail
|
|
||||||
display_name_attribute: displayName
|
|
||||||
# The username and password of the admin or service user.
|
# The username and password of the admin or service user.
|
||||||
user: UID=authelia,OU=people,DC=example,DC=com
|
user: UID=authelia,OU=people,DC=example,DC=com
|
||||||
password: "SUPER_COMPLEX_PASSWORD"
|
password: "SUPER_COMPLEX_PASSWORD"
|
||||||
|
attributes:
|
||||||
|
distinguished_name: 'distinguishedName'
|
||||||
|
username: 'uid'
|
||||||
|
mail: 'mail'
|
||||||
|
member_of: 'memberOf'
|
||||||
|
group_name: 'cn'
|
||||||
```
|
```
|
||||||
Following this, restart Authelia, and you should be able to begin using lldap integration for your user logins, with
|
Following this, restart Authelia, and you should be able to begin using lldap integration for your user logins, with
|
||||||
Authelia taking the email attribute for users straight from the 'mail' attribute within the LDAP object.
|
Authelia taking the email attribute for users straight from the 'mail' attribute within the LDAP object.
|
||||||
|
|
|
@ -75,6 +75,32 @@ The following implementations exist:
|
||||||
[GLAuth]: https://glauth.github.io/
|
[GLAuth]: https://glauth.github.io/
|
||||||
[RFC2307bis]: https://datatracker.ietf.org/doc/html/draft-howard-rfc2307bis-02
|
[RFC2307bis]: https://datatracker.ietf.org/doc/html/draft-howard-rfc2307bis-02
|
||||||
|
|
||||||
|
### Group Search Modes
|
||||||
|
|
||||||
|
There are currently two group search modes that exist.
|
||||||
|
|
||||||
|
#### Search Mode: filter
|
||||||
|
|
||||||
|
The `filter` search mode is the default search mode. Generally this is recommended.
|
||||||
|
|
||||||
|
#### Search Mode: memberof
|
||||||
|
|
||||||
|
The `memberof` search mode is a special search mode. Generally this is discouraged and is currently experimental.
|
||||||
|
|
||||||
|
Some systems provide a `memberOf` attribute which may include additional groups that the user is a member of. This
|
||||||
|
search mode allows using this attribute as a method to determine their groups. How it works is the search is performed
|
||||||
|
against the base with the subtree scope and the groups filter must include one of the `{memberof:*}` replacements, and
|
||||||
|
the distinguished names of the results from the search are compared (case-insensitive) against the users `memberOf`
|
||||||
|
attribute to determine if they are members.
|
||||||
|
|
||||||
|
This means:
|
||||||
|
|
||||||
|
1. The groups still must be in the search base that you have configured.
|
||||||
|
2. The `memberOf` attribute *__MUST__* include the distinguished name of the group.
|
||||||
|
3. If the `{memberof:dn}` replacement is used:
|
||||||
|
1. The distinguished name *__MUST__* be searchable by your directory server.
|
||||||
|
3. The first relative distinguished name of the distinguished name *__MUST__* be search
|
||||||
|
|
||||||
### Filter replacements
|
### Filter replacements
|
||||||
|
|
||||||
Various replacements occur in the user and groups filter. The replacements either occur at startup or upon an LDAP
|
Various replacements occur in the user and groups filter. The replacements either occur at startup or upon an LDAP
|
||||||
|
@ -85,25 +111,65 @@ is ever established. In addition to this, during the startup phase we purposeful
|
||||||
phase replacements exist so we only have to check if the replacement is necessary once, and we don't needlessly perform
|
phase replacements exist so we only have to check if the replacement is necessary once, and we don't needlessly perform
|
||||||
every possible replacement on every search regardless of if it's needed or not.
|
every possible replacement on every search regardless of if it's needed or not.
|
||||||
|
|
||||||
|
#### General filter replacements
|
||||||
|
|
||||||
|
| Placeholder | Phase | Replacement |
|
||||||
|
|:------------------------------:|:-------:|:-------------------------------------------:|
|
||||||
|
| {distinguished_name_attribute} | startup | The configured distinguished name attribute |
|
||||||
|
| {username_attribute} | startup | The configured username attribute |
|
||||||
|
| {mail_attribute} | startup | The configured mail attribute |
|
||||||
|
| {display_name_attribute} | startup | The configured display name attribute |
|
||||||
|
| {member_of_attribute} | startup | The configured member of attribute |
|
||||||
|
| {input} | search | The input into the username field |
|
||||||
|
|
||||||
#### Users filter replacements
|
#### Users filter replacements
|
||||||
|
|
||||||
| Placeholder | Phase | Replacement |
|
| Placeholder | Phase | Replacement |
|
||||||
|:------------------------:|:-------:|:----------------------------------------------------------------------------------------------------------------:|
|
|:------------------------------:|:-------:|:----------------------------------------------------------------------------------------------------------------:|
|
||||||
| {username_attribute} | startup | The configured username attribute |
|
| {date-time:generalized} | search | The current UTC time formatted as a LDAP generalized time in the format of `20060102150405.0Z` |
|
||||||
| {mail_attribute} | startup | The configured mail attribute |
|
| {date-time:unix} | search | The current time formatted as a Unix epoch |
|
||||||
| {display_name_attribute} | startup | The configured display name attribute |
|
| {date-time:microsoft-nt} | search | The current time formatted as a Microsoft NT epoch which is used by some Microsoft [Active Directory] attributes |
|
||||||
| {input} | search | The input into the username field |
|
|
||||||
| {date-time:generalized} | search | The current UTC time formatted as a LDAP generalized time in the format of `20060102150405.0Z` |
|
|
||||||
| {date-time:unix} | search | The current time formatted as a Unix epoch |
|
|
||||||
| {date-time:microsoft-nt} | search | The current time formatted as a Microsoft NT epoch which is used by some Microsoft [Active Directory] attributes |
|
|
||||||
|
|
||||||
#### Groups filter replacements
|
#### Groups filter replacements
|
||||||
|
|
||||||
| Placeholder | Phase | Replacement |
|
| Placeholder | Phase | Replacement |
|
||||||
|:-----------:|:------:|:-------------------------------------------------------------------------:|
|
|:--------------:|:------:|:----------------------------------------------------------------------------------------------------------------------------------------------------:|
|
||||||
| {input} | search | The input into the username field |
|
| {username} | search | The username from the profile lookup obtained from the username attribute |
|
||||||
| {username} | search | The username from the profile lookup obtained from the username attribute |
|
| {dn} | search | The distinguished name from the profile lookup |
|
||||||
| {dn} | search | The distinguished name from the profile lookup |
|
| {memberof:dn} | search | See the detailed section below |
|
||||||
|
| {memberof:rdn} | search | Only allowed with the `memberof` search method and contains the first relative distinguished name of every `memberOf` entry a use has in parenthesis |
|
||||||
|
|
||||||
|
##### memberof:dn
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
1. Must be using the `memberof` search mode.
|
||||||
|
2. Must have the distinguished name attribute configured in Authelia.
|
||||||
|
3. Directory server must support searching by the distinguished name attribute (many directory services *__DO NOT__*
|
||||||
|
have a distinguished name attribute).
|
||||||
|
|
||||||
|
##### memberof:rdn
|
||||||
|
|
||||||
|
Requirements:
|
||||||
|
|
||||||
|
1. Must be using the `memberof` search mode.
|
||||||
|
2. Directory server must support searching by the first relative distinguished name as an attribute.
|
||||||
|
|
||||||
|
Splits every `memberOf` value to obtain th e first relative distinguished name and joins all of those after surrounding
|
||||||
|
them in parenthesis. This makes the general suggested filter pattern for this particular replacement
|
||||||
|
`(|{memberof:rdn})`. The format of this value is as follows:
|
||||||
|
|
||||||
|
```text
|
||||||
|
(<RDN>)
|
||||||
|
```
|
||||||
|
|
||||||
|
For example if the user has the following distinguished names in their object:
|
||||||
|
|
||||||
|
- CN=abc,OU=groups,DC=example,DC=com
|
||||||
|
- CN=xyz,OU=groups,DC=example,DC=com
|
||||||
|
|
||||||
|
The value will be replaced with `(CN=abc)(CN=xyz)` which using the suggested pattern for the filter becomes
|
||||||
|
`(|(CN=abc)(CN=xyz))` which will then return any user that as a `CN` of `abc` or `xyz`.
|
||||||
|
|
||||||
### Defaults
|
### Defaults
|
||||||
|
|
||||||
|
@ -122,14 +188,14 @@ The following set defaults for the `additional_users_dn` and `additional_groups_
|
||||||
This table describes the attribute defaults for each implementation. i.e. the username_attribute is described by the
|
This table describes the attribute defaults for each implementation. i.e. the username_attribute is described by the
|
||||||
Username column.
|
Username column.
|
||||||
|
|
||||||
| Implementation | Username | Display Name | Mail | Group Name |
|
| Implementation | Username | Display Name | Mail | Group Name | Distinguished Name | Member Of |
|
||||||
|:---------------:|:--------------:|:------------:|:----:|:----------:|
|
|:---------------:|:--------------:|:------------:|:----:|:----------:|:------------------:|:---------:|
|
||||||
| custom | N/A | displayName | mail | cn |
|
| custom | N/A | displayName | mail | cn | N/A | N/A |
|
||||||
| activedirectory | sAMAccountName | displayName | mail | cn |
|
| activedirectory | sAMAccountName | displayName | mail | cn | distinguishedName | memberOf |
|
||||||
| rfc2307bis | uid | displayName | mail | cn |
|
| rfc2307bis | uid | displayName | mail | cn | N/A | memberOf |
|
||||||
| freeipa | uid | displayName | mail | cn |
|
| freeipa | uid | displayName | mail | cn | N/A | memberOf |
|
||||||
| lldap | uid | cn | mail | cn |
|
| lldap | uid | cn | mail | cn | N/A | N/A |
|
||||||
| glauth | cn | description | mail | cn |
|
| glauth | cn | description | mail | cn | N/A | N/A |
|
||||||
|
|
||||||
#### Filter defaults
|
#### Filter defaults
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -72,12 +72,19 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ldapPlaceholderInput = "{input}"
|
ldapPlaceholderInput = "{input}"
|
||||||
ldapPlaceholderDistinguishedName = "{dn}"
|
ldapPlaceholderDistinguishedName = "{dn}"
|
||||||
ldapPlaceholderUsername = "{username}"
|
ldapPlaceholderMemberOfDistinguishedName = "{memberof:dn}"
|
||||||
ldapPlaceholderDateTimeGeneralized = "{date-time:generalized}"
|
ldapPlaceholderMemberOfRelativeDistinguishedName = "{memberof:rdn}"
|
||||||
ldapPlaceholderDateTimeMicrosoftNTTimeEpoch = "{date-time:microsoft-nt}"
|
ldapPlaceholderUsername = "{username}"
|
||||||
ldapPlaceholderDateTimeUnixEpoch = "{date-time:unix}"
|
ldapPlaceholderDateTimeGeneralized = "{date-time:generalized}"
|
||||||
|
ldapPlaceholderDateTimeMicrosoftNTTimeEpoch = "{date-time:microsoft-nt}"
|
||||||
|
ldapPlaceholderDateTimeUnixEpoch = "{date-time:unix}"
|
||||||
|
ldapPlaceholderDistinguishedNameAttribute = "{distinguished_name_attribute}"
|
||||||
|
ldapPlaceholderUsernameAttribute = "{username_attribute}"
|
||||||
|
ldapPlaceholderDisplayNameAttribute = "{display_name_attribute}"
|
||||||
|
ldapPlaceholderMailAttribute = "{mail_attribute}"
|
||||||
|
ldapPlaceholderMemberOfAttribute = "{member_of_attribute}"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -8,7 +8,7 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/go-ldap/ldap/v3"
|
ldap "github.com/go-ldap/ldap/v3"
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
|
||||||
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
"github.com/authelia/authelia/v4/internal/configuration/schema"
|
||||||
|
@ -40,11 +40,13 @@ type LDAPUserProvider struct {
|
||||||
usersFilterReplacementDateTimeMicrosoftNTTimeEpoch bool
|
usersFilterReplacementDateTimeMicrosoftNTTimeEpoch bool
|
||||||
|
|
||||||
// Dynamically generated groups values.
|
// Dynamically generated groups values.
|
||||||
groupsBaseDN string
|
groupsBaseDN string
|
||||||
groupsAttributes []string
|
groupsAttributes []string
|
||||||
groupsFilterReplacementInput bool
|
groupsFilterReplacementInput bool
|
||||||
groupsFilterReplacementUsername bool
|
groupsFilterReplacementUsername bool
|
||||||
groupsFilterReplacementDN bool
|
groupsFilterReplacementDN bool
|
||||||
|
groupsFilterReplacementsMemberOfDN bool
|
||||||
|
groupsFilterReplacementsMemberOfRDN bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewLDAPUserProvider creates a new instance of LDAPUserProvider with the ProductionLDAPClientFactory.
|
// NewLDAPUserProvider creates a new instance of LDAPUserProvider with the ProductionLDAPClientFactory.
|
||||||
|
@ -86,6 +88,7 @@ func NewLDAPUserProviderWithFactory(config schema.LDAPAuthenticationBackend, dis
|
||||||
|
|
||||||
provider.parseDynamicUsersConfiguration()
|
provider.parseDynamicUsersConfiguration()
|
||||||
provider.parseDynamicGroupsConfiguration()
|
provider.parseDynamicGroupsConfiguration()
|
||||||
|
provider.parseDynamicConfiguration()
|
||||||
|
|
||||||
return provider
|
return provider
|
||||||
}
|
}
|
||||||
|
@ -134,38 +137,11 @@ func (p *LDAPUserProvider) GetDetails(username string) (details *UserDetails, er
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
request *ldap.SearchRequest
|
groups []string
|
||||||
result *ldap.SearchResult
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Search for the users groups.
|
if groups, err = p.getUserGroups(client, username, profile); err != nil {
|
||||||
request = ldap.NewSearchRequest(
|
return nil, err
|
||||||
p.groupsBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
|
|
||||||
0, 0, false, p.resolveGroupsFilter(username, profile), p.groupsAttributes, nil,
|
|
||||||
)
|
|
||||||
|
|
||||||
p.log.
|
|
||||||
WithField("base_dn", request.BaseDN).
|
|
||||||
WithField("filter", request.Filter).
|
|
||||||
WithField("attr", request.Attributes).
|
|
||||||
WithField("scope", request.Scope).
|
|
||||||
WithField("deref", request.DerefAliases).
|
|
||||||
Trace("Performing group search")
|
|
||||||
|
|
||||||
if result, err = p.search(client, request); err != nil {
|
|
||||||
return nil, fmt.Errorf("unable to retrieve groups of user '%s'. Cause: %w", username, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
groups := make([]string, 0)
|
|
||||||
|
|
||||||
for _, res := range result.Entries {
|
|
||||||
if len(res.Attributes) == 0 {
|
|
||||||
p.log.Warningf("No groups retrieved from LDAP for user %s", username)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
// Append all values of the document. Normally there should be only one per document.
|
|
||||||
groups = append(groups, res.Attributes[0].Values...)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &UserDetails{
|
return &UserDetails{
|
||||||
|
@ -275,6 +251,8 @@ func (p *LDAPUserProvider) search(client LDAPClient, request *ldap.SearchRequest
|
||||||
} else {
|
} else {
|
||||||
result.Referrals = append(result.Referrals, referral)
|
result.Referrals = append(result.Referrals, referral)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,6 +335,11 @@ func (p *LDAPUserProvider) getUserProfile(client LDAPClient, username string) (p
|
||||||
return nil, fmt.Errorf("there were %d users found when searching for '%s' but there should only be 1", len(result.Entries), username)
|
return nil, fmt.Errorf("there were %d users found when searching for '%s' but there should only be 1", len(result.Entries), username)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return p.getUserProfileResultToProfile(username, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:gocyclo // Not overly complex.
|
||||||
|
func (p *LDAPUserProvider) getUserProfileResultToProfile(username string, result *ldap.SearchResult) (profile *ldapUserProfile, err error) {
|
||||||
userProfile := ldapUserProfile{
|
userProfile := ldapUserProfile{
|
||||||
DN: result.Entries[0].DN,
|
DN: result.Entries[0].DN,
|
||||||
}
|
}
|
||||||
|
@ -364,35 +347,50 @@ func (p *LDAPUserProvider) getUserProfile(client LDAPClient, username string) (p
|
||||||
for _, attr := range result.Entries[0].Attributes {
|
for _, attr := range result.Entries[0].Attributes {
|
||||||
attrs := len(attr.Values)
|
attrs := len(attr.Values)
|
||||||
|
|
||||||
if attr.Name == p.config.UsernameAttribute {
|
switch attr.Name {
|
||||||
|
case p.config.Attributes.Username:
|
||||||
switch attrs {
|
switch attrs {
|
||||||
case 1:
|
case 1:
|
||||||
userProfile.Username = attr.Values[0]
|
userProfile.Username = attr.Values[0]
|
||||||
|
|
||||||
|
if attr.Name == p.config.Attributes.DisplayName && userProfile.DisplayName == "" {
|
||||||
|
userProfile.DisplayName = attr.Values[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
if attr.Name == p.config.Attributes.Mail && len(userProfile.Emails) == 0 {
|
||||||
|
userProfile.Emails = []string{attr.Values[0]}
|
||||||
|
}
|
||||||
case 0:
|
case 0:
|
||||||
return nil, fmt.Errorf("user '%s' must have value for attribute '%s'",
|
return nil, fmt.Errorf("user '%s' must have value for attribute '%s'",
|
||||||
username, p.config.UsernameAttribute)
|
username, p.config.Attributes.Username)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("user '%s' has %d values for for attribute '%s' but the attribute must be a single value attribute",
|
return nil, fmt.Errorf("user '%s' has %d values for for attribute '%s' but the attribute must be a single value attribute",
|
||||||
username, attrs, p.config.UsernameAttribute)
|
username, attrs, p.config.Attributes.Username)
|
||||||
|
}
|
||||||
|
case p.config.Attributes.Mail:
|
||||||
|
if attrs == 0 {
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if attrs == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if attr.Name == p.config.MailAttribute {
|
|
||||||
userProfile.Emails = attr.Values
|
userProfile.Emails = attr.Values
|
||||||
}
|
case p.config.Attributes.DisplayName:
|
||||||
|
if attrs == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if attr.Name == p.config.DisplayNameAttribute {
|
|
||||||
userProfile.DisplayName = attr.Values[0]
|
userProfile.DisplayName = attr.Values[0]
|
||||||
|
case p.config.Attributes.MemberOf:
|
||||||
|
if attrs == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
userProfile.MemberOf = attr.Values
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if userProfile.Username == "" {
|
if userProfile.Username == "" {
|
||||||
return nil, fmt.Errorf("user '%s' must have value for attribute '%s'",
|
return nil, fmt.Errorf("user '%s' must have value for attribute '%s'",
|
||||||
username, p.config.UsernameAttribute)
|
username, p.config.Attributes.Username)
|
||||||
}
|
}
|
||||||
|
|
||||||
if userProfile.DN == "" {
|
if userProfile.DN == "" {
|
||||||
|
@ -402,6 +400,124 @@ func (p *LDAPUserProvider) getUserProfile(client LDAPClient, username string) (p
|
||||||
return &userProfile, nil
|
return &userProfile, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *LDAPUserProvider) getUserGroups(client LDAPClient, username string, profile *ldapUserProfile) (groups []string, err error) {
|
||||||
|
request := ldap.NewSearchRequest(
|
||||||
|
p.groupsBaseDN, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
|
||||||
|
0, 0, false, p.resolveGroupsFilter(username, profile), p.groupsAttributes, nil,
|
||||||
|
)
|
||||||
|
|
||||||
|
p.log.
|
||||||
|
WithField("base_dn", request.BaseDN).
|
||||||
|
WithField("filter", request.Filter).
|
||||||
|
WithField("attributes", request.Attributes).
|
||||||
|
WithField("scope", request.Scope).
|
||||||
|
WithField("deref", request.DerefAliases).
|
||||||
|
WithField("mode", p.config.GroupSearchMode).
|
||||||
|
Trace("Performing group search")
|
||||||
|
|
||||||
|
switch p.config.GroupSearchMode {
|
||||||
|
case "", "filter":
|
||||||
|
return p.getUserGroupsRequestFilter(client, username, profile, request)
|
||||||
|
case "memberof":
|
||||||
|
return p.getUserGroupsRequestMemberOf(client, username, profile, request)
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("could not perform group search with mode '%s' as it's unknown", p.config.GroupSearchMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *LDAPUserProvider) getUserGroupsRequestFilter(client LDAPClient, username string, _ *ldapUserProfile, request *ldap.SearchRequest) (groups []string, err error) {
|
||||||
|
var result *ldap.SearchResult
|
||||||
|
|
||||||
|
if result, err = p.search(client, request); err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to retrieve groups of user '%s'. Cause: %w", username, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range result.Entries {
|
||||||
|
attributes:
|
||||||
|
for _, attr := range entry.Attributes {
|
||||||
|
switch attr.Name {
|
||||||
|
case p.config.Attributes.GroupName:
|
||||||
|
switch n := len(attr.Values); n {
|
||||||
|
case 0:
|
||||||
|
continue
|
||||||
|
case 1:
|
||||||
|
groups = append(groups, attr.Values[0])
|
||||||
|
default:
|
||||||
|
fmt.Println(attr.Name, n, attr.Values)
|
||||||
|
return nil, fmt.Errorf("unable to retrieve groups of user '%s': Cause: the group '%s' attribute '%s' (group name attribute) has more than one value", username, entry.DN, p.config.Attributes.GroupName)
|
||||||
|
}
|
||||||
|
|
||||||
|
break attributes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *LDAPUserProvider) getUserGroupsRequestMemberOf(client LDAPClient, username string, profile *ldapUserProfile, request *ldap.SearchRequest) (groups []string, err error) {
|
||||||
|
var result *ldap.SearchResult
|
||||||
|
|
||||||
|
if result, err = p.search(client, request); err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to retrieve groups of user '%s'. Cause: %w", username, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range result.Entries {
|
||||||
|
if len(entry.Attributes) == 0 {
|
||||||
|
p.log.
|
||||||
|
WithField("dn", entry.DN).
|
||||||
|
WithField("attributes", request.Attributes).
|
||||||
|
WithField("mode", "memberof").
|
||||||
|
Trace("Skipping Group as the server did not return any requested attributes")
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if !utils.IsStringInSliceFold(entry.DN, profile.MemberOf) {
|
||||||
|
p.log.
|
||||||
|
WithField("dn", entry.DN).
|
||||||
|
WithField("mode", "memberof").
|
||||||
|
Trace("Skipping Group as it doesn't match the users memberof entries")
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
attributes:
|
||||||
|
for _, attr := range entry.Attributes {
|
||||||
|
switch attr.Name {
|
||||||
|
case p.config.Attributes.GroupName:
|
||||||
|
switch len(attr.Values) {
|
||||||
|
case 0:
|
||||||
|
p.log.
|
||||||
|
WithField("dn", entry.DN).
|
||||||
|
WithField("attribute", attr.Name).
|
||||||
|
Trace("Group skipped as the server returned a null attribute")
|
||||||
|
case 1:
|
||||||
|
switch len(attr.Values[0]) {
|
||||||
|
case 0:
|
||||||
|
p.log.
|
||||||
|
WithField("dn", entry.DN).
|
||||||
|
WithField("attribute", attr.Name).
|
||||||
|
Trace("Skipping group as the configured group name attribute had no value")
|
||||||
|
|
||||||
|
default:
|
||||||
|
groups = append(groups, attr.Values[0])
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
p.log.
|
||||||
|
WithField("dn", entry.DN).
|
||||||
|
WithField("attribute", attr.Name).
|
||||||
|
Trace("Group skipped as the server returned a multi-valued attribute but it should be a single-valued attribute")
|
||||||
|
}
|
||||||
|
|
||||||
|
break attributes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return groups, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (p *LDAPUserProvider) resolveUsersFilter(input string) (filter string) {
|
func (p *LDAPUserProvider) resolveUsersFilter(input string) (filter string) {
|
||||||
filter = p.config.UsersFilter
|
filter = p.config.UsersFilter
|
||||||
|
|
||||||
|
@ -445,6 +561,27 @@ func (p *LDAPUserProvider) resolveGroupsFilter(input string, profile *ldapUserPr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.groupsFilterReplacementsMemberOfDN {
|
||||||
|
sep := fmt.Sprintf(")(%s=", p.config.Attributes.DistinguishedName)
|
||||||
|
values := make([]string, len(profile.MemberOf))
|
||||||
|
|
||||||
|
for i, memberof := range profile.MemberOf {
|
||||||
|
values[i] = ldap.EscapeFilter(memberof)
|
||||||
|
}
|
||||||
|
|
||||||
|
filter = strings.ReplaceAll(filter, ldapPlaceholderMemberOfDistinguishedName, fmt.Sprintf("(%s=%s)", p.config.Attributes.DistinguishedName, strings.Join(values, sep)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.groupsFilterReplacementsMemberOfRDN {
|
||||||
|
values := make([]string, len(profile.MemberOf))
|
||||||
|
|
||||||
|
for i, memberof := range profile.MemberOf {
|
||||||
|
values[i] = ldap.EscapeFilter(strings.SplitN(memberof, ",", 2)[0])
|
||||||
|
}
|
||||||
|
|
||||||
|
filter = strings.ReplaceAll(filter, ldapPlaceholderMemberOfRelativeDistinguishedName, fmt.Sprintf("(%s)", strings.Join(values, ")(")))
|
||||||
|
}
|
||||||
|
|
||||||
p.log.Tracef("Computed groups filter is %s", filter)
|
p.log.Tracef("Computed groups filter is %s", filter)
|
||||||
|
|
||||||
return filter
|
return filter
|
||||||
|
|
|
@ -37,11 +37,6 @@ func (p *LDAPUserProvider) StartupCheck() (err error) {
|
||||||
"LDAP Server.")
|
"LDAP Server.")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !p.features.Extensions.TLS && p.config.StartTLS {
|
|
||||||
p.log.Info("Your LDAP Server does not appear to support TLS but you enabled StartTLS which may result " +
|
|
||||||
"in an error.")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,22 +85,24 @@ func (p *LDAPUserProvider) getServerSupportedFeatures(client LDAPClient) (featur
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *LDAPUserProvider) parseDynamicUsersConfiguration() {
|
func (p *LDAPUserProvider) parseDynamicUsersConfiguration() {
|
||||||
p.config.UsersFilter = strings.ReplaceAll(p.config.UsersFilter, "{username_attribute}", p.config.UsernameAttribute)
|
p.config.UsersFilter = strings.ReplaceAll(p.config.UsersFilter, ldapPlaceholderDistinguishedNameAttribute, p.config.Attributes.DistinguishedName)
|
||||||
p.config.UsersFilter = strings.ReplaceAll(p.config.UsersFilter, "{mail_attribute}", p.config.MailAttribute)
|
p.config.UsersFilter = strings.ReplaceAll(p.config.UsersFilter, ldapPlaceholderUsernameAttribute, p.config.Attributes.Username)
|
||||||
p.config.UsersFilter = strings.ReplaceAll(p.config.UsersFilter, "{display_name_attribute}", p.config.DisplayNameAttribute)
|
p.config.UsersFilter = strings.ReplaceAll(p.config.UsersFilter, ldapPlaceholderDisplayNameAttribute, p.config.Attributes.DisplayName)
|
||||||
|
p.config.UsersFilter = strings.ReplaceAll(p.config.UsersFilter, ldapPlaceholderMailAttribute, p.config.Attributes.Mail)
|
||||||
|
p.config.UsersFilter = strings.ReplaceAll(p.config.UsersFilter, ldapPlaceholderMemberOfAttribute, p.config.Attributes.MemberOf)
|
||||||
|
|
||||||
p.log.Tracef("Dynamically generated users filter is %s", p.config.UsersFilter)
|
p.log.Tracef("Dynamically generated users filter is %s", p.config.UsersFilter)
|
||||||
|
|
||||||
if !utils.IsStringInSlice(p.config.UsernameAttribute, p.usersAttributes) {
|
if len(p.config.Attributes.Username) != 0 && !utils.IsStringInSlice(p.config.Attributes.Username, p.usersAttributes) {
|
||||||
p.usersAttributes = append(p.usersAttributes, p.config.UsernameAttribute)
|
p.usersAttributes = append(p.usersAttributes, p.config.Attributes.Username)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !utils.IsStringInSlice(p.config.MailAttribute, p.usersAttributes) {
|
if len(p.config.Attributes.Mail) != 0 && !utils.IsStringInSlice(p.config.Attributes.Mail, p.usersAttributes) {
|
||||||
p.usersAttributes = append(p.usersAttributes, p.config.MailAttribute)
|
p.usersAttributes = append(p.usersAttributes, p.config.Attributes.Mail)
|
||||||
}
|
}
|
||||||
|
|
||||||
if !utils.IsStringInSlice(p.config.DisplayNameAttribute, p.usersAttributes) {
|
if len(p.config.Attributes.DisplayName) != 0 && !utils.IsStringInSlice(p.config.Attributes.DisplayName, p.usersAttributes) {
|
||||||
p.usersAttributes = append(p.usersAttributes, p.config.DisplayNameAttribute)
|
p.usersAttributes = append(p.usersAttributes, p.config.Attributes.DisplayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.config.AdditionalUsersDN != "" {
|
if p.config.AdditionalUsersDN != "" {
|
||||||
|
@ -137,8 +134,14 @@ func (p *LDAPUserProvider) parseDynamicUsersConfiguration() {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *LDAPUserProvider) parseDynamicGroupsConfiguration() {
|
func (p *LDAPUserProvider) parseDynamicGroupsConfiguration() {
|
||||||
p.groupsAttributes = []string{
|
p.config.GroupsFilter = strings.ReplaceAll(p.config.GroupsFilter, ldapPlaceholderDistinguishedNameAttribute, p.config.Attributes.DistinguishedName)
|
||||||
p.config.GroupNameAttribute,
|
p.config.GroupsFilter = strings.ReplaceAll(p.config.GroupsFilter, ldapPlaceholderUsernameAttribute, p.config.Attributes.Username)
|
||||||
|
p.config.GroupsFilter = strings.ReplaceAll(p.config.GroupsFilter, ldapPlaceholderDisplayNameAttribute, p.config.Attributes.DisplayName)
|
||||||
|
p.config.GroupsFilter = strings.ReplaceAll(p.config.GroupsFilter, ldapPlaceholderMailAttribute, p.config.Attributes.Mail)
|
||||||
|
p.config.GroupsFilter = strings.ReplaceAll(p.config.GroupsFilter, ldapPlaceholderMemberOfAttribute, p.config.Attributes.MemberOf)
|
||||||
|
|
||||||
|
if len(p.config.Attributes.GroupName) != 0 && !utils.IsStringInSlice(p.config.Attributes.GroupName, p.groupsAttributes) {
|
||||||
|
p.groupsAttributes = append(p.groupsAttributes, p.config.Attributes.GroupName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.config.AdditionalGroupsDN != "" {
|
if p.config.AdditionalGroupsDN != "" {
|
||||||
|
@ -161,5 +164,25 @@ func (p *LDAPUserProvider) parseDynamicGroupsConfiguration() {
|
||||||
p.groupsFilterReplacementDN = true
|
p.groupsFilterReplacementDN = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.Contains(p.config.GroupsFilter, ldapPlaceholderMemberOfDistinguishedName) {
|
||||||
|
p.groupsFilterReplacementsMemberOfDN = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Contains(p.config.GroupsFilter, ldapPlaceholderMemberOfRelativeDistinguishedName) {
|
||||||
|
p.groupsFilterReplacementsMemberOfRDN = true
|
||||||
|
}
|
||||||
|
|
||||||
p.log.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)
|
p.log.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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *LDAPUserProvider) parseDynamicConfiguration() {
|
||||||
|
if len(p.config.Attributes.MemberOf) != 0 {
|
||||||
|
if !utils.IsStringInSlice(p.config.Attributes.MemberOf, p.usersAttributes) {
|
||||||
|
p.usersAttributes = append(p.usersAttributes, p.config.Attributes.MemberOf)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !utils.IsStringInSlice(p.config.Attributes.MemberOf, p.groupsAttributes) {
|
||||||
|
p.groupsAttributes = append(p.groupsAttributes, p.config.Attributes.MemberOf)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -83,6 +83,7 @@ type ldapUserProfile struct {
|
||||||
Emails []string
|
Emails []string
|
||||||
DisplayName string
|
DisplayName string
|
||||||
Username string
|
Username string
|
||||||
|
MemberOf []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// LDAPSupportedFeatures represents features which a server may support which are implemented in code.
|
// LDAPSupportedFeatures represents features which a server may support which are implemented in code.
|
||||||
|
|
|
@ -317,7 +317,7 @@ authentication_backend:
|
||||||
## because it allows Authelia to offload the stateful operations
|
## because it allows Authelia to offload the stateful operations
|
||||||
## onto the LDAP service.
|
## onto the LDAP service.
|
||||||
# ldap:
|
# ldap:
|
||||||
## The address of the LDAP server to connect to in the address common syntax.
|
## The address of the directory server to connect to in the address common syntax.
|
||||||
## Format: [<scheme>://]<hostname>[:<port>].
|
## Format: [<scheme>://]<hostname>[:<port>].
|
||||||
## Square brackets indicate optional portions of the format. Scheme must be 'ldap', 'ldaps', or 'ldapi`.
|
## Square brackets indicate optional portions of the format. Scheme must be 'ldap', 'ldaps', or 'ldapi`.
|
||||||
## The default scheme is 'ldapi' if the address is an absolute path otherwise it's 'ldaps'.
|
## The default scheme is 'ldapi' if the address is an absolute path otherwise it's 'ldaps'.
|
||||||
|
@ -403,16 +403,6 @@ authentication_backend:
|
||||||
## See also: additional_users_dn, additional_groups_dn.
|
## See also: additional_users_dn, additional_groups_dn.
|
||||||
# base_dn: 'dc=example,dc=com'
|
# base_dn: 'dc=example,dc=com'
|
||||||
|
|
||||||
## The attribute holding the username of the user. This attribute is used to populate the username in the session
|
|
||||||
## information. For your information, Microsoft Active Directory usually uses 'sAMAccountName' and OpenLDAP usually
|
|
||||||
## uses 'uid'. Beware that this attribute holds the unique identifiers for the users binding the user and the
|
|
||||||
## configuration stored in database. Therefore only single value attributes are allowed and the value must never be
|
|
||||||
## changed once attributed to a user otherwise it would break the configuration for that user. Technically,
|
|
||||||
## non-unique attributes like 'mail' can also be used but we don't recommend using them, we instead advise to use
|
|
||||||
## a filter to perform alternative lookups and the attributes mentioned above (sAMAccountName and uid) to
|
|
||||||
## follow https://datatracker.ietf.org/doc/html/rfc2307.
|
|
||||||
# username_attribute: 'uid'
|
|
||||||
|
|
||||||
## The additional_users_dn is prefixed to base_dn and delimited by a comma when searching for users.
|
## The additional_users_dn is prefixed to base_dn and delimited by a comma when searching for users.
|
||||||
## i.e. with this set to OU=Users and base_dn set to DC=a,DC=com; OU=Users,DC=a,DC=com is searched for users.
|
## i.e. with this set to OU=Users and base_dn set to DC=a,DC=com; OU=Users,DC=a,DC=com is searched for users.
|
||||||
# additional_users_dn: 'ou=users'
|
# additional_users_dn: 'ou=users'
|
||||||
|
@ -443,15 +433,9 @@ authentication_backend:
|
||||||
## (&(uniqueMember={dn})(objectClass=groupOfUniqueNames))
|
## (&(uniqueMember={dn})(objectClass=groupOfUniqueNames))
|
||||||
# groups_filter: '(&(member={dn})(objectClass=groupOfNames))'
|
# groups_filter: '(&(member={dn})(objectClass=groupOfNames))'
|
||||||
|
|
||||||
## The attribute holding the name of the group.
|
## The group search mode to use. Options are 'filter' or 'memberof'. It's essential to read the docs if you wish to
|
||||||
# group_name_attribute: 'cn'
|
## use 'memberof'. Also 'filter' is the best choice for most use cases.
|
||||||
|
# group_search_mode: 'filter'
|
||||||
## The attribute holding the mail address of the user. If multiple email addresses are defined for a user, only the
|
|
||||||
## first one returned by the LDAP server is used.
|
|
||||||
# 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'
|
|
||||||
|
|
||||||
## Follow referrals returned by the server.
|
## Follow referrals returned by the server.
|
||||||
## This is especially useful for environments where read-only servers exist. Only implemented for write operations.
|
## This is especially useful for environments where read-only servers exist. Only implemented for write operations.
|
||||||
|
@ -462,6 +446,37 @@ authentication_backend:
|
||||||
## Password can also be set using a secret: https://www.authelia.com/c/secrets
|
## Password can also be set using a secret: https://www.authelia.com/c/secrets
|
||||||
# password: 'password'
|
# password: 'password'
|
||||||
|
|
||||||
|
## The attributes for users and objects from the directory server.
|
||||||
|
# attributes:
|
||||||
|
|
||||||
|
## The distinguished name attribute if your directory server supports it. Users should read the docs before
|
||||||
|
## configuring. Only used for the 'memberof' group search mode.
|
||||||
|
# distinguished_name: ''
|
||||||
|
|
||||||
|
## The attribute holding the username of the user. This attribute is used to populate the username in the session
|
||||||
|
## information. For your information, Microsoft Active Directory usually uses 'sAMAccountName' and OpenLDAP
|
||||||
|
## usually uses 'uid'. Beware that this attribute holds the unique identifiers for the users binding the user and
|
||||||
|
## the configuration stored in database; therefore only single value attributes are allowed and the value must
|
||||||
|
## never be changed once attributed to a user otherwise it would break the configuration for that user.
|
||||||
|
## Technically non-unique attributes like 'mail' can also be used but we don't recommend using them, we instead
|
||||||
|
## advise to use a filter to perform alternative lookups and the attributes mentioned above
|
||||||
|
## (sAMAccountName and uid) to follow https://datatracker.ietf.org/doc/html/rfc2307.
|
||||||
|
# username: 'uid'
|
||||||
|
|
||||||
|
## The attribute holding the display name of the user. This will be used to greet an authenticated user.
|
||||||
|
# display_name: 'displayName'
|
||||||
|
|
||||||
|
## The attribute holding the mail address of the user. If multiple email addresses are defined for a user, only
|
||||||
|
## the first one returned by the directory server is used.
|
||||||
|
# mail: 'mail'
|
||||||
|
|
||||||
|
## The attribute which provides distinguished names of groups an object is a member of.
|
||||||
|
## Only used for the 'memberof' group search mode.
|
||||||
|
# member_of: 'memberOf'
|
||||||
|
|
||||||
|
## The attribute holding the name of the group.
|
||||||
|
# group_name: 'cn'
|
||||||
|
|
||||||
##
|
##
|
||||||
## File (Authentication Provider)
|
## File (Authentication Provider)
|
||||||
##
|
##
|
||||||
|
|
|
@ -261,4 +261,36 @@ var deprecations = map[string]Deprecation{
|
||||||
MapFunc: nil,
|
MapFunc: nil,
|
||||||
ErrFunc: nil,
|
ErrFunc: nil,
|
||||||
},
|
},
|
||||||
|
"authentication_backend.ldap.username_attribute": {
|
||||||
|
Version: model.SemanticVersion{Major: 4, Minor: 38},
|
||||||
|
Key: "authentication_backend.ldap.username_attribute",
|
||||||
|
NewKey: "authentication_backend.ldap.attributes.username",
|
||||||
|
AutoMap: true,
|
||||||
|
MapFunc: nil,
|
||||||
|
ErrFunc: nil,
|
||||||
|
},
|
||||||
|
"authentication_backend.ldap.mail_attribute": {
|
||||||
|
Version: model.SemanticVersion{Major: 4, Minor: 38},
|
||||||
|
Key: "authentication_backend.ldap.mail_attribute",
|
||||||
|
NewKey: "authentication_backend.ldap.attributes.mail",
|
||||||
|
AutoMap: true,
|
||||||
|
MapFunc: nil,
|
||||||
|
ErrFunc: nil,
|
||||||
|
},
|
||||||
|
"authentication_backend.ldap.display_name_attribute": {
|
||||||
|
Version: model.SemanticVersion{Major: 4, Minor: 38},
|
||||||
|
Key: "authentication_backend.ldap.display_name_attribute",
|
||||||
|
NewKey: "authentication_backend.ldap.attributes.display_name",
|
||||||
|
AutoMap: true,
|
||||||
|
MapFunc: nil,
|
||||||
|
ErrFunc: nil,
|
||||||
|
},
|
||||||
|
"authentication_backend.ldap.group_name_attribute": {
|
||||||
|
Version: model.SemanticVersion{Major: 4, Minor: 38},
|
||||||
|
Key: "authentication_backend.ldap.group_name_attribute",
|
||||||
|
NewKey: "authentication_backend.ldap.attributes.group_name",
|
||||||
|
AutoMap: true,
|
||||||
|
MapFunc: nil,
|
||||||
|
ErrFunc: nil,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,11 +108,9 @@ type LDAPAuthenticationBackend struct {
|
||||||
|
|
||||||
AdditionalGroupsDN string `koanf:"additional_groups_dn"`
|
AdditionalGroupsDN string `koanf:"additional_groups_dn"`
|
||||||
GroupsFilter string `koanf:"groups_filter"`
|
GroupsFilter string `koanf:"groups_filter"`
|
||||||
|
GroupSearchMode string `koanf:"group_search_mode"`
|
||||||
|
|
||||||
GroupNameAttribute string `koanf:"group_name_attribute"`
|
Attributes LDAPAuthenticationAttributes `koanf:"attributes"`
|
||||||
UsernameAttribute string `koanf:"username_attribute"`
|
|
||||||
MailAttribute string `koanf:"mail_attribute"`
|
|
||||||
DisplayNameAttribute string `koanf:"display_name_attribute"`
|
|
||||||
|
|
||||||
PermitReferrals bool `koanf:"permit_referrals"`
|
PermitReferrals bool `koanf:"permit_referrals"`
|
||||||
PermitUnauthenticatedBind bool `koanf:"permit_unauthenticated_bind"`
|
PermitUnauthenticatedBind bool `koanf:"permit_unauthenticated_bind"`
|
||||||
|
@ -122,6 +120,16 @@ type LDAPAuthenticationBackend struct {
|
||||||
Password string `koanf:"password"`
|
Password string `koanf:"password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LDAPAuthenticationAttributes represents the configuration related to LDAP server attributes.
|
||||||
|
type LDAPAuthenticationAttributes struct {
|
||||||
|
DistinguishedName string `koanf:"distinguished_name"`
|
||||||
|
Username string `koanf:"username"`
|
||||||
|
DisplayName string `koanf:"display_name"`
|
||||||
|
Mail string `koanf:"mail"`
|
||||||
|
MemberOf string `koanf:"member_of"`
|
||||||
|
GroupName string `koanf:"group_name"`
|
||||||
|
}
|
||||||
|
|
||||||
// DefaultPasswordConfig represents the default configuration related to Argon2id hashing.
|
// DefaultPasswordConfig represents the default configuration related to Argon2id hashing.
|
||||||
var DefaultPasswordConfig = Password{
|
var DefaultPasswordConfig = Password{
|
||||||
Algorithm: argon2,
|
Algorithm: argon2,
|
||||||
|
@ -175,11 +183,14 @@ var DefaultCIPasswordConfig = Password{
|
||||||
|
|
||||||
// DefaultLDAPAuthenticationBackendConfigurationImplementationCustom represents the default LDAP config.
|
// DefaultLDAPAuthenticationBackendConfigurationImplementationCustom represents the default LDAP config.
|
||||||
var DefaultLDAPAuthenticationBackendConfigurationImplementationCustom = LDAPAuthenticationBackend{
|
var DefaultLDAPAuthenticationBackendConfigurationImplementationCustom = LDAPAuthenticationBackend{
|
||||||
UsernameAttribute: ldapAttrUserID,
|
GroupSearchMode: ldapGroupSearchModeFilter,
|
||||||
MailAttribute: ldapAttrMail,
|
Attributes: LDAPAuthenticationAttributes{
|
||||||
DisplayNameAttribute: ldapAttrDisplayName,
|
Username: ldapAttrUserID,
|
||||||
GroupNameAttribute: ldapAttrCommonName,
|
DisplayName: ldapAttrDisplayName,
|
||||||
Timeout: time.Second * 5,
|
Mail: ldapAttrMail,
|
||||||
|
GroupName: ldapAttrCommonName,
|
||||||
|
},
|
||||||
|
Timeout: time.Second * 5,
|
||||||
TLS: &TLSConfig{
|
TLS: &TLSConfig{
|
||||||
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
||||||
},
|
},
|
||||||
|
@ -187,13 +198,18 @@ var DefaultLDAPAuthenticationBackendConfigurationImplementationCustom = LDAPAuth
|
||||||
|
|
||||||
// DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory represents the default LDAP config for the LDAPImplementationActiveDirectory Implementation.
|
// DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory represents the default LDAP config for the LDAPImplementationActiveDirectory Implementation.
|
||||||
var DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory = LDAPAuthenticationBackend{
|
var DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory = LDAPAuthenticationBackend{
|
||||||
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))(|(!(accountExpires=*))(accountExpires=0)(accountExpires>={date-time:microsoft-nt})))",
|
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(sAMAccountType=805306368)(!(userAccountControl:1.2.840.113556.1.4.803:=2))(!(pwdLastSet=0))(|(!(accountExpires=*))(accountExpires=0)(accountExpires>={date-time:microsoft-nt})))",
|
||||||
UsernameAttribute: "sAMAccountName",
|
GroupsFilter: "(&(member={dn})(|(sAMAccountType=268435456)(sAMAccountType=536870912)))",
|
||||||
MailAttribute: ldapAttrMail,
|
GroupSearchMode: ldapGroupSearchModeFilter,
|
||||||
DisplayNameAttribute: ldapAttrDisplayName,
|
Attributes: LDAPAuthenticationAttributes{
|
||||||
GroupsFilter: "(&(member={dn})(|(sAMAccountType=268435456)(sAMAccountType=536870912)))",
|
DistinguishedName: ldapAttrDistinguishedName,
|
||||||
GroupNameAttribute: ldapAttrCommonName,
|
Username: ldapAttrSAMAccountName,
|
||||||
Timeout: time.Second * 5,
|
DisplayName: ldapAttrDisplayName,
|
||||||
|
Mail: ldapAttrMail,
|
||||||
|
MemberOf: ldapAttrMemberOf,
|
||||||
|
GroupName: ldapAttrCommonName,
|
||||||
|
},
|
||||||
|
Timeout: time.Second * 5,
|
||||||
TLS: &TLSConfig{
|
TLS: &TLSConfig{
|
||||||
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
||||||
},
|
},
|
||||||
|
@ -201,13 +217,17 @@ var DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory =
|
||||||
|
|
||||||
// DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis represents the default LDAP config for the LDAPImplementationRFC2307bis Implementation.
|
// DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis represents the default LDAP config for the LDAPImplementationRFC2307bis Implementation.
|
||||||
var DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis = LDAPAuthenticationBackend{
|
var DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis = LDAPAuthenticationBackend{
|
||||||
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(|(objectClass=inetOrgPerson)(objectClass=organizationalPerson)))",
|
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(|(objectClass=inetOrgPerson)(objectClass=organizationalPerson)))",
|
||||||
UsernameAttribute: ldapAttrUserID,
|
GroupsFilter: "(&(|(member={dn})(uniqueMember={dn}))(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=groupOfMembers)))",
|
||||||
MailAttribute: ldapAttrMail,
|
GroupSearchMode: ldapGroupSearchModeFilter,
|
||||||
DisplayNameAttribute: ldapAttrDisplayName,
|
Attributes: LDAPAuthenticationAttributes{
|
||||||
GroupsFilter: "(&(|(member={dn})(uniqueMember={dn}))(|(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=groupOfMembers)))",
|
Username: ldapAttrUserID,
|
||||||
GroupNameAttribute: ldapAttrCommonName,
|
DisplayName: ldapAttrDisplayName,
|
||||||
Timeout: time.Second * 5,
|
Mail: ldapAttrMail,
|
||||||
|
MemberOf: ldapAttrMemberOf,
|
||||||
|
GroupName: ldapAttrCommonName,
|
||||||
|
},
|
||||||
|
Timeout: time.Second * 5,
|
||||||
TLS: &TLSConfig{
|
TLS: &TLSConfig{
|
||||||
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
||||||
},
|
},
|
||||||
|
@ -215,13 +235,17 @@ var DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis = LDAP
|
||||||
|
|
||||||
// DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA represents the default LDAP config for the LDAPImplementationFreeIPA Implementation.
|
// DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA represents the default LDAP config for the LDAPImplementationFreeIPA Implementation.
|
||||||
var DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA = LDAPAuthenticationBackend{
|
var DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA = LDAPAuthenticationBackend{
|
||||||
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person)(!(nsAccountLock=TRUE))(krbPasswordExpiration>={date-time:generalized})(|(!(krbPrincipalExpiration=*))(krbPrincipalExpiration>={date-time:generalized})))",
|
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person)(!(nsAccountLock=TRUE))(krbPasswordExpiration>={date-time:generalized})(|(!(krbPrincipalExpiration=*))(krbPrincipalExpiration>={date-time:generalized})))",
|
||||||
UsernameAttribute: ldapAttrUserID,
|
GroupsFilter: "(&(member={dn})(objectClass=groupOfNames))",
|
||||||
MailAttribute: ldapAttrMail,
|
GroupSearchMode: ldapGroupSearchModeFilter,
|
||||||
DisplayNameAttribute: ldapAttrDisplayName,
|
Attributes: LDAPAuthenticationAttributes{
|
||||||
GroupsFilter: "(&(member={dn})(objectClass=groupOfNames))",
|
Username: ldapAttrUserID,
|
||||||
GroupNameAttribute: ldapAttrCommonName,
|
DisplayName: ldapAttrDisplayName,
|
||||||
Timeout: time.Second * 5,
|
Mail: ldapAttrMail,
|
||||||
|
MemberOf: ldapAttrMemberOf,
|
||||||
|
GroupName: ldapAttrCommonName,
|
||||||
|
},
|
||||||
|
Timeout: time.Second * 5,
|
||||||
TLS: &TLSConfig{
|
TLS: &TLSConfig{
|
||||||
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
||||||
},
|
},
|
||||||
|
@ -229,15 +253,18 @@ var DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA = LDAPAut
|
||||||
|
|
||||||
// DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP represents the default LDAP config for the LDAPImplementationLLDAP Implementation.
|
// DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP represents the default LDAP config for the LDAPImplementationLLDAP Implementation.
|
||||||
var DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP = LDAPAuthenticationBackend{
|
var DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP = LDAPAuthenticationBackend{
|
||||||
AdditionalUsersDN: "OU=people",
|
AdditionalUsersDN: "OU=people",
|
||||||
AdditionalGroupsDN: "OU=groups",
|
AdditionalGroupsDN: "OU=groups",
|
||||||
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))",
|
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person))",
|
||||||
UsernameAttribute: ldapAttrUserID,
|
GroupsFilter: "(&(member={dn})(objectClass=groupOfUniqueNames))",
|
||||||
MailAttribute: ldapAttrMail,
|
GroupSearchMode: ldapGroupSearchModeFilter,
|
||||||
DisplayNameAttribute: ldapAttrCommonName,
|
Attributes: LDAPAuthenticationAttributes{
|
||||||
GroupsFilter: "(&(member={dn})(objectClass=groupOfUniqueNames))",
|
Username: ldapAttrUserID,
|
||||||
GroupNameAttribute: ldapAttrCommonName,
|
DisplayName: ldapAttrCommonName,
|
||||||
Timeout: time.Second * 5,
|
Mail: ldapAttrMail,
|
||||||
|
GroupName: ldapAttrCommonName,
|
||||||
|
},
|
||||||
|
Timeout: time.Second * 5,
|
||||||
TLS: &TLSConfig{
|
TLS: &TLSConfig{
|
||||||
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
||||||
},
|
},
|
||||||
|
@ -245,13 +272,16 @@ var DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP = LDAPAuthe
|
||||||
|
|
||||||
// DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth represents the default LDAP config for the LDAPImplementationGLAuth Implementation.
|
// DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth represents the default LDAP config for the LDAPImplementationGLAuth Implementation.
|
||||||
var DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth = LDAPAuthenticationBackend{
|
var DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth = LDAPAuthenticationBackend{
|
||||||
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=posixAccount)(!(accountStatus=inactive)))",
|
UsersFilter: "(&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=posixAccount)(!(accountStatus=inactive)))",
|
||||||
UsernameAttribute: ldapAttrCommonName,
|
GroupsFilter: "(&(uniqueMember={dn})(objectClass=posixGroup))",
|
||||||
MailAttribute: ldapAttrMail,
|
GroupSearchMode: ldapGroupSearchModeFilter,
|
||||||
DisplayNameAttribute: ldapAttrDescription,
|
Attributes: LDAPAuthenticationAttributes{
|
||||||
GroupsFilter: "(&(uniqueMember={dn})(objectClass=posixGroup))",
|
Username: ldapAttrCommonName,
|
||||||
GroupNameAttribute: ldapAttrCommonName,
|
DisplayName: ldapAttrDescription,
|
||||||
Timeout: time.Second * 5,
|
Mail: ldapAttrMail,
|
||||||
|
GroupName: ldapAttrCommonName,
|
||||||
|
},
|
||||||
|
Timeout: time.Second * 5,
|
||||||
TLS: &TLSConfig{
|
TLS: &TLSConfig{
|
||||||
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
MinimumVersion: TLSVersion{tls.VersionTLS12},
|
||||||
},
|
},
|
||||||
|
|
|
@ -78,6 +78,14 @@ const (
|
||||||
LDAPImplementationGLAuth = "glauth"
|
LDAPImplementationGLAuth = "glauth"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// LDAPGroupSearchModeFilter is the string for the filter group search mode.
|
||||||
|
LDAPGroupSearchModeFilter = "filter"
|
||||||
|
|
||||||
|
// LDAPGroupSearchModeMemberOf is the string for the memberOf group search mode.
|
||||||
|
LDAPGroupSearchModeMemberOf = "memberof"
|
||||||
|
)
|
||||||
|
|
||||||
// TOTP Algorithm.
|
// TOTP Algorithm.
|
||||||
const (
|
const (
|
||||||
TOTPAlgorithmSHA1 = "SHA1"
|
TOTPAlgorithmSHA1 = "SHA1"
|
||||||
|
@ -121,11 +129,18 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ldapAttrMail = "mail"
|
ldapGroupSearchModeFilter = "filter"
|
||||||
ldapAttrUserID = "uid"
|
)
|
||||||
ldapAttrDisplayName = "displayName"
|
|
||||||
ldapAttrDescription = "description"
|
const (
|
||||||
ldapAttrCommonName = "cn"
|
ldapAttrDistinguishedName = "distinguishedName"
|
||||||
|
ldapAttrMail = "mail"
|
||||||
|
ldapAttrUserID = "uid"
|
||||||
|
ldapAttrSAMAccountName = "sAMAccountName"
|
||||||
|
ldapAttrDisplayName = "displayName"
|
||||||
|
ldapAttrDescription = "description"
|
||||||
|
ldapAttrCommonName = "cn"
|
||||||
|
ldapAttrMemberOf = "memberOf"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Address Schemes.
|
// Address Schemes.
|
||||||
|
|
|
@ -118,10 +118,13 @@ var Keys = []string{
|
||||||
"authentication_backend.ldap.users_filter",
|
"authentication_backend.ldap.users_filter",
|
||||||
"authentication_backend.ldap.additional_groups_dn",
|
"authentication_backend.ldap.additional_groups_dn",
|
||||||
"authentication_backend.ldap.groups_filter",
|
"authentication_backend.ldap.groups_filter",
|
||||||
"authentication_backend.ldap.group_name_attribute",
|
"authentication_backend.ldap.group_search_mode",
|
||||||
"authentication_backend.ldap.username_attribute",
|
"authentication_backend.ldap.attributes.distinguished_name",
|
||||||
"authentication_backend.ldap.mail_attribute",
|
"authentication_backend.ldap.attributes.username",
|
||||||
"authentication_backend.ldap.display_name_attribute",
|
"authentication_backend.ldap.attributes.display_name",
|
||||||
|
"authentication_backend.ldap.attributes.mail",
|
||||||
|
"authentication_backend.ldap.attributes.member_of",
|
||||||
|
"authentication_backend.ldap.attributes.group_name",
|
||||||
"authentication_backend.ldap.permit_referrals",
|
"authentication_backend.ldap.permit_referrals",
|
||||||
"authentication_backend.ldap.permit_unauthenticated_bind",
|
"authentication_backend.ldap.permit_unauthenticated_bind",
|
||||||
"authentication_backend.ldap.permit_feature_detection_failure",
|
"authentication_backend.ldap.permit_feature_detection_failure",
|
||||||
|
|
|
@ -66,14 +66,15 @@ authentication_backend:
|
||||||
1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw==
|
1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw==
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
base_dn: dc=example,dc=com
|
base_dn: dc=example,dc=com
|
||||||
username_attribute: uid
|
|
||||||
additional_users_dn: ou=users
|
additional_users_dn: ou=users
|
||||||
users_filter: (&({username_attribute}={input})(objectCategory=person)(objectClass=user))
|
users_filter: (&({username_attribute}={input})(objectCategory=person)(objectClass=user))
|
||||||
additional_groups_dn: ou=groups
|
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
|
user: cn=admin,dc=example,dc=com
|
||||||
|
attributes:
|
||||||
|
username: 'uid'
|
||||||
|
group_name: 'cn'
|
||||||
|
mail: 'mail'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: deny
|
default_policy: deny
|
||||||
|
|
|
@ -66,14 +66,15 @@ authentication_backend:
|
||||||
1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw==
|
1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw==
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
base_dn: dc=example,dc=com
|
base_dn: dc=example,dc=com
|
||||||
username_attribute: uid
|
|
||||||
additional_users_dn: ou=users
|
additional_users_dn: ou=users
|
||||||
users_filter: (&({username_attribute}={input})(objectCategory=person)(objectClass=user))
|
users_filter: (&({username_attribute}={input})(objectCategory=person)(objectClass=user))
|
||||||
additional_groups_dn: ou=groups
|
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
|
user: cn=admin,dc=example,dc=com
|
||||||
|
attributes:
|
||||||
|
username: 'uid'
|
||||||
|
group_name: 'cn'
|
||||||
|
mail: 'mail'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: deny
|
default_policy: deny
|
||||||
|
|
|
@ -66,14 +66,15 @@ authentication_backend:
|
||||||
1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw==
|
1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw==
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
base_dn: 'dc=example,dc=com'
|
base_dn: 'dc=example,dc=com'
|
||||||
username_attribute: 'uid'
|
|
||||||
additional_users_dn: 'ou=users'
|
additional_users_dn: 'ou=users'
|
||||||
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
||||||
additional_groups_dn: 'ou=groups'
|
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'
|
user: 'cn=admin,dc=example,dc=com'
|
||||||
|
attributes:
|
||||||
|
username: 'uid'
|
||||||
|
group_name: 'cn'
|
||||||
|
mail: 'mail'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: 'deny'
|
default_policy: 'deny'
|
||||||
|
|
|
@ -47,14 +47,15 @@ authentication_backend:
|
||||||
1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw==
|
1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw==
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
base_dn: dc=example,dc=com
|
base_dn: dc=example,dc=com
|
||||||
username_attribute: uid
|
|
||||||
additional_users_dn: ou=users
|
additional_users_dn: ou=users
|
||||||
users_filter: (&({username_attribute}={input})(objectCategory=person)(objectClass=user))
|
users_filter: (&({username_attribute}={input})(objectCategory=person)(objectClass=user))
|
||||||
additional_groups_dn: ou=groups
|
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
|
user: cn=admin,dc=example,dc=com
|
||||||
|
attributes:
|
||||||
|
username: 'uid'
|
||||||
|
group_name: 'cn'
|
||||||
|
mail: 'mail'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: deny
|
default_policy: deny
|
||||||
|
|
|
@ -66,14 +66,15 @@ authentication_backend:
|
||||||
1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw==
|
1YjCJ36UpTsLre2f8nOSLtNmRfDPtbOE2mkOoO9dD9UU0XZwnvn9xw==
|
||||||
-----END RSA PRIVATE KEY-----
|
-----END RSA PRIVATE KEY-----
|
||||||
base_dn: 'dc=example,dc=com'
|
base_dn: 'dc=example,dc=com'
|
||||||
username_attribute: 'uid'
|
|
||||||
additional_users_dn: 'ou=users'
|
additional_users_dn: 'ou=users'
|
||||||
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
||||||
additional_groups_dn: 'ou=groups'
|
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'
|
user: 'cn=admin,dc=example,dc=com'
|
||||||
|
attributes:
|
||||||
|
username: 'uid'
|
||||||
|
group_name: 'cn'
|
||||||
|
mail: 'mail'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: 'deny'
|
default_policy: 'deny'
|
||||||
|
|
|
@ -18,14 +18,16 @@ authentication_backend:
|
||||||
ldap:
|
ldap:
|
||||||
address: 'ldap://127.0.0.1'
|
address: 'ldap://127.0.0.1'
|
||||||
base_dn: 'dc=example,dc=com'
|
base_dn: 'dc=example,dc=com'
|
||||||
username_attribute: 'uid'
|
|
||||||
additional_users_dn: 'ou=users'
|
additional_users_dn: 'ou=users'
|
||||||
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
||||||
additional_groups_dn: 'ou=groups'
|
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'
|
user: 'cn=admin,dc=example,dc=com'
|
||||||
|
attributes:
|
||||||
|
mail: 'mail'
|
||||||
|
group_name: 'cn'
|
||||||
|
username: 'uid'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: 'deny'
|
default_policy: 'deny'
|
||||||
|
|
|
@ -19,14 +19,15 @@ authentication_backend:
|
||||||
ldap:
|
ldap:
|
||||||
address: 'ldap://127.0.0.1'
|
address: 'ldap://127.0.0.1'
|
||||||
base_dn: 'dc=example,dc=com'
|
base_dn: 'dc=example,dc=com'
|
||||||
username_attribute: 'uid'
|
|
||||||
additional_users_dn: 'ou=users'
|
additional_users_dn: 'ou=users'
|
||||||
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
||||||
additional_groups_dn: 'ou=groups'
|
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'
|
user: 'cn=admin,dc=example,dc=com'
|
||||||
|
attributes:
|
||||||
|
username: 'uid'
|
||||||
|
group_name: 'cn'
|
||||||
|
mail: 'mail'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: 'deny'
|
default_policy: 'deny'
|
||||||
|
|
|
@ -18,14 +18,15 @@ authentication_backend:
|
||||||
ldap:
|
ldap:
|
||||||
address: 'ldap://127.0.0.1'
|
address: 'ldap://127.0.0.1'
|
||||||
base_dn: 'dc=example,dc=com'
|
base_dn: 'dc=example,dc=com'
|
||||||
username_attribute: 'uid'
|
|
||||||
additional_users_dn: 'ou=users'
|
additional_users_dn: 'ou=users'
|
||||||
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
||||||
additional_groups_dn: 'ou=groups'
|
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'
|
user: 'cn=admin,dc=example,dc=com'
|
||||||
|
attributes:
|
||||||
|
username: 'uid'
|
||||||
|
group_name: 'cn'
|
||||||
|
mail: 'mail'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: 'deny'
|
default_policy: 'deny'
|
||||||
|
|
|
@ -18,13 +18,15 @@ authentication_backend:
|
||||||
ldap:
|
ldap:
|
||||||
address: 'ldap://127.0.0.1'
|
address: 'ldap://127.0.0.1'
|
||||||
base_dn: 'dc=example,dc=com'
|
base_dn: 'dc=example,dc=com'
|
||||||
username_attribute: 'uid'
|
|
||||||
additional_users_dn: 'ou=users'
|
additional_users_dn: 'ou=users'
|
||||||
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
||||||
additional_groups_dn: 'ou=groups'
|
additional_groups_dn: 'ou=groups'
|
||||||
groups_filter: '(&(member={dn})(objectClass=groupOfNames))'
|
groups_filter: '(&(member={dn})(objectClass=groupOfNames))'
|
||||||
group_name_attribute: 'cn'
|
attributes:
|
||||||
mail_attribute: 'mail'
|
group_name: 'cn'
|
||||||
|
mail: 'mail'
|
||||||
|
username: 'uid'
|
||||||
|
|
||||||
user: 'cn=admin,dc=example,dc=com'
|
user: 'cn=admin,dc=example,dc=com'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
|
|
|
@ -18,14 +18,15 @@ authentication_backend:
|
||||||
ldap:
|
ldap:
|
||||||
address: 'ldap://127.0.0.1'
|
address: 'ldap://127.0.0.1'
|
||||||
base_dn: 'dc=example,dc=com'
|
base_dn: 'dc=example,dc=com'
|
||||||
username_attribute: 'uid'
|
|
||||||
additional_users_dn: 'ou=users'
|
additional_users_dn: 'ou=users'
|
||||||
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
||||||
additional_groups_dn: 'ou=groups'
|
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'
|
user: 'cn=admin,dc=example,dc=com'
|
||||||
|
attributes:
|
||||||
|
username: 'uid'
|
||||||
|
group_name: 'cn'
|
||||||
|
mail: 'mail'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: 'deny'
|
default_policy: 'deny'
|
||||||
|
|
|
@ -18,14 +18,15 @@ authentication_backend:
|
||||||
ldap:
|
ldap:
|
||||||
address: 'ldap://127.0.0.1'
|
address: 'ldap://127.0.0.1'
|
||||||
base_dn: 'dc=example,dc=com'
|
base_dn: 'dc=example,dc=com'
|
||||||
username_attribute: 'uid'
|
|
||||||
additional_users_dn: 'ou=users'
|
additional_users_dn: 'ou=users'
|
||||||
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
||||||
additional_groups_dn: 'ou=groups'
|
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'
|
user: 'cn=admin,dc=example,dc=com'
|
||||||
|
attributes:
|
||||||
|
username: 'uid'
|
||||||
|
group_name: 'cn'
|
||||||
|
mail: 'mail'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: 'deny'
|
default_policy: 'deny'
|
||||||
|
|
|
@ -18,14 +18,15 @@ authentication_backend:
|
||||||
ldap:
|
ldap:
|
||||||
address: 'ldap://127.0.0.1'
|
address: 'ldap://127.0.0.1'
|
||||||
base_dn: 'dc=example,dc=com'
|
base_dn: 'dc=example,dc=com'
|
||||||
username_attribute: 'uid'
|
|
||||||
additional_users_dn: 'ou=users'
|
additional_users_dn: 'ou=users'
|
||||||
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
||||||
additional_groups_dn: 'ou=groups'
|
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'
|
user: 'cn=admin,dc=example,dc=com'
|
||||||
|
attributes:
|
||||||
|
username: 'uid'
|
||||||
|
group_name: 'cn'
|
||||||
|
mail: 'mail'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: 'deny'
|
default_policy: 'deny'
|
||||||
|
|
|
@ -20,14 +20,16 @@ authentication_backend:
|
||||||
ldap:
|
ldap:
|
||||||
address: 'ldap://127.0.0.1'
|
address: 'ldap://127.0.0.1'
|
||||||
base_dn: 'dc=example,dc=com'
|
base_dn: 'dc=example,dc=com'
|
||||||
username_attribute: 'uid'
|
|
||||||
additional_users_dn: 'ou=users'
|
additional_users_dn: 'ou=users'
|
||||||
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
users_filter: '(&({username_attribute}={input})(objectCategory=person)(objectClass=user))'
|
||||||
additional_groups_dn: 'ou=groups'
|
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'
|
user: 'cn=admin,dc=example,dc=com'
|
||||||
|
attributes:
|
||||||
|
username: 'uid'
|
||||||
|
group_name: 'cn'
|
||||||
|
mail: 'mail'
|
||||||
|
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: 'deny'
|
default_policy: 'deny'
|
||||||
|
|
|
@ -364,7 +364,7 @@ func validateLDAPAuthenticationBackendImplementation(config *schema.Authenticati
|
||||||
case schema.LDAPImplementationGLAuth:
|
case schema.LDAPImplementationGLAuth:
|
||||||
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth
|
implementation = &schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth
|
||||||
default:
|
default:
|
||||||
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendImplementation, strJoinOr(validLDAPImplementations), config.LDAP.Implementation))
|
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendOptionMustBeOneOf, "implementation", strJoinOr(validLDAPImplementations), config.LDAP.Implementation))
|
||||||
}
|
}
|
||||||
|
|
||||||
tlsconfig := &schema.TLSConfig{}
|
tlsconfig := &schema.TLSConfig{}
|
||||||
|
@ -394,32 +394,44 @@ func setDefaultImplementationLDAPAuthenticationBackendProfileAttributes(config *
|
||||||
config.AdditionalUsersDN = implementation.AdditionalUsersDN
|
config.AdditionalUsersDN = implementation.AdditionalUsersDN
|
||||||
}
|
}
|
||||||
|
|
||||||
if ldapImplementationShouldSetStr(config.AdditionalGroupsDN, implementation.AdditionalGroupsDN) {
|
|
||||||
config.AdditionalGroupsDN = implementation.AdditionalGroupsDN
|
|
||||||
}
|
|
||||||
|
|
||||||
if ldapImplementationShouldSetStr(config.UsersFilter, implementation.UsersFilter) {
|
if ldapImplementationShouldSetStr(config.UsersFilter, implementation.UsersFilter) {
|
||||||
config.UsersFilter = implementation.UsersFilter
|
config.UsersFilter = implementation.UsersFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
if ldapImplementationShouldSetStr(config.UsernameAttribute, implementation.UsernameAttribute) {
|
if ldapImplementationShouldSetStr(config.AdditionalGroupsDN, implementation.AdditionalGroupsDN) {
|
||||||
config.UsernameAttribute = implementation.UsernameAttribute
|
config.AdditionalGroupsDN = implementation.AdditionalGroupsDN
|
||||||
}
|
|
||||||
|
|
||||||
if ldapImplementationShouldSetStr(config.DisplayNameAttribute, implementation.DisplayNameAttribute) {
|
|
||||||
config.DisplayNameAttribute = implementation.DisplayNameAttribute
|
|
||||||
}
|
|
||||||
|
|
||||||
if ldapImplementationShouldSetStr(config.MailAttribute, implementation.MailAttribute) {
|
|
||||||
config.MailAttribute = implementation.MailAttribute
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ldapImplementationShouldSetStr(config.GroupsFilter, implementation.GroupsFilter) {
|
if ldapImplementationShouldSetStr(config.GroupsFilter, implementation.GroupsFilter) {
|
||||||
config.GroupsFilter = implementation.GroupsFilter
|
config.GroupsFilter = implementation.GroupsFilter
|
||||||
}
|
}
|
||||||
|
|
||||||
if ldapImplementationShouldSetStr(config.GroupNameAttribute, implementation.GroupNameAttribute) {
|
if ldapImplementationShouldSetStr(config.GroupSearchMode, implementation.GroupSearchMode) {
|
||||||
config.GroupNameAttribute = implementation.GroupNameAttribute
|
config.GroupSearchMode = implementation.GroupSearchMode
|
||||||
|
}
|
||||||
|
|
||||||
|
if ldapImplementationShouldSetStr(config.Attributes.DistinguishedName, implementation.Attributes.DistinguishedName) {
|
||||||
|
config.Attributes.DistinguishedName = implementation.Attributes.DistinguishedName
|
||||||
|
}
|
||||||
|
|
||||||
|
if ldapImplementationShouldSetStr(config.Attributes.Username, implementation.Attributes.Username) {
|
||||||
|
config.Attributes.Username = implementation.Attributes.Username
|
||||||
|
}
|
||||||
|
|
||||||
|
if ldapImplementationShouldSetStr(config.Attributes.DisplayName, implementation.Attributes.DisplayName) {
|
||||||
|
config.Attributes.DisplayName = implementation.Attributes.DisplayName
|
||||||
|
}
|
||||||
|
|
||||||
|
if ldapImplementationShouldSetStr(config.Attributes.Mail, implementation.Attributes.Mail) {
|
||||||
|
config.Attributes.Mail = implementation.Attributes.Mail
|
||||||
|
}
|
||||||
|
|
||||||
|
if ldapImplementationShouldSetStr(config.Attributes.MemberOf, implementation.Attributes.MemberOf) {
|
||||||
|
config.Attributes.MemberOf = implementation.Attributes.MemberOf
|
||||||
|
}
|
||||||
|
|
||||||
|
if ldapImplementationShouldSetStr(config.Attributes.GroupName, implementation.Attributes.GroupName) {
|
||||||
|
config.Attributes.GroupName = implementation.Attributes.GroupName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -486,4 +498,32 @@ func validateLDAPRequiredParameters(config *schema.AuthenticationBackend, valida
|
||||||
} else if !strings.HasPrefix(config.LDAP.GroupsFilter, "(") || !strings.HasSuffix(config.LDAP.GroupsFilter, ")") {
|
} else if !strings.HasPrefix(config.LDAP.GroupsFilter, "(") || !strings.HasSuffix(config.LDAP.GroupsFilter, ")") {
|
||||||
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendFilterEnclosingParenthesis, "groups_filter", config.LDAP.GroupsFilter, config.LDAP.GroupsFilter))
|
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendFilterEnclosingParenthesis, "groups_filter", config.LDAP.GroupsFilter, config.LDAP.GroupsFilter))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
validateLDAPGroupFilter(config, validator)
|
||||||
|
}
|
||||||
|
|
||||||
|
func validateLDAPGroupFilter(config *schema.AuthenticationBackend, validator *schema.StructValidator) {
|
||||||
|
if config.LDAP.GroupSearchMode == "" {
|
||||||
|
config.LDAP.GroupSearchMode = schema.LDAPGroupSearchModeFilter
|
||||||
|
}
|
||||||
|
|
||||||
|
if !utils.IsStringInSlice(config.LDAP.GroupSearchMode, validLDAPGroupSearchModes) {
|
||||||
|
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendOptionMustBeOneOf, "group_search_mode", strJoinOr(validLDAPGroupSearchModes), config.LDAP.GroupSearchMode))
|
||||||
|
}
|
||||||
|
|
||||||
|
pMemberOfDN, pMemberOfRDN := strings.Contains(config.LDAP.GroupsFilter, "{memberof:dn}"), strings.Contains(config.LDAP.GroupsFilter, "{memberof:rdn}")
|
||||||
|
|
||||||
|
if config.LDAP.GroupSearchMode == schema.LDAPGroupSearchModeMemberOf {
|
||||||
|
if !pMemberOfDN && !pMemberOfRDN {
|
||||||
|
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendFilterMissingPlaceholderGroupSearchMode, "groups_filter", strJoinOr([]string{"{memberof:rdn}", "{memberof:dn}"}), config.LDAP.GroupSearchMode))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if pMemberOfDN && config.LDAP.Attributes.DistinguishedName == "" {
|
||||||
|
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendFilterMissingAttribute, "distinguished_name", strJoinOr([]string{"{memberof:dn}"})))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pMemberOfDN || pMemberOfRDN) && config.LDAP.Attributes.MemberOf == "" {
|
||||||
|
validator.Push(fmt.Errorf(errFmtLDAPAuthBackendFilterMissingAttribute, "member_of", strJoinOr([]string{"{memberof:rdn}", "{memberof:dn}"})))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -577,7 +577,7 @@ func (suite *LDAPAuthenticationBackendSuite) SetupTest() {
|
||||||
suite.config.LDAP.User = testLDAPUser
|
suite.config.LDAP.User = testLDAPUser
|
||||||
suite.config.LDAP.Password = testLDAPPassword
|
suite.config.LDAP.Password = testLDAPPassword
|
||||||
suite.config.LDAP.BaseDN = testLDAPBaseDN
|
suite.config.LDAP.BaseDN = testLDAPBaseDN
|
||||||
suite.config.LDAP.UsernameAttribute = "uid"
|
suite.config.LDAP.Attributes.Username = "uid"
|
||||||
suite.config.LDAP.UsersFilter = "({username_attribute}={input})"
|
suite.config.LDAP.UsersFilter = "({username_attribute}={input})"
|
||||||
suite.config.LDAP.GroupsFilter = "(cn={input})"
|
suite.config.LDAP.GroupsFilter = "(cn={input})"
|
||||||
}
|
}
|
||||||
|
@ -591,12 +591,12 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldValidateCompleteConfigura
|
||||||
|
|
||||||
func (suite *LDAPAuthenticationBackendSuite) TestShouldValidateDefaultImplementationAndUsernameAttribute() {
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldValidateDefaultImplementationAndUsernameAttribute() {
|
||||||
suite.config.LDAP.Implementation = ""
|
suite.config.LDAP.Implementation = ""
|
||||||
suite.config.LDAP.UsernameAttribute = ""
|
suite.config.LDAP.Attributes.Username = ""
|
||||||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
suite.Equal(schema.LDAPImplementationCustom, suite.config.LDAP.Implementation)
|
suite.Equal(schema.LDAPImplementationCustom, suite.config.LDAP.Implementation)
|
||||||
|
|
||||||
suite.Equal(suite.config.LDAP.UsernameAttribute, schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom.UsernameAttribute)
|
suite.Equal(suite.config.LDAP.Attributes.Username, schema.DefaultLDAPAuthenticationBackendConfigurationImplementationCustom.Attributes.Username)
|
||||||
suite.Len(suite.validator.Warnings(), 0)
|
suite.Len(suite.validator.Warnings(), 0)
|
||||||
suite.Len(suite.validator.Errors(), 0)
|
suite.Len(suite.validator.Errors(), 0)
|
||||||
}
|
}
|
||||||
|
@ -743,7 +743,7 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldRaiseOnEmptyUsersFilter()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *LDAPAuthenticationBackendSuite) TestShouldNotRaiseOnEmptyUsernameAttribute() {
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldNotRaiseOnEmptyUsernameAttribute() {
|
||||||
suite.config.LDAP.UsernameAttribute = ""
|
suite.config.LDAP.Attributes.Username = ""
|
||||||
|
|
||||||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
@ -793,7 +793,7 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldSetDefaultGroupNameAttrib
|
||||||
suite.Len(suite.validator.Warnings(), 0)
|
suite.Len(suite.validator.Warnings(), 0)
|
||||||
suite.Len(suite.validator.Errors(), 0)
|
suite.Len(suite.validator.Errors(), 0)
|
||||||
|
|
||||||
suite.Equal("cn", suite.config.LDAP.GroupNameAttribute)
|
suite.Equal("cn", suite.config.LDAP.Attributes.GroupName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *LDAPAuthenticationBackendSuite) TestShouldSetDefaultMailAttribute() {
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldSetDefaultMailAttribute() {
|
||||||
|
@ -802,7 +802,7 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldSetDefaultMailAttribute()
|
||||||
suite.Len(suite.validator.Warnings(), 0)
|
suite.Len(suite.validator.Warnings(), 0)
|
||||||
suite.Len(suite.validator.Errors(), 0)
|
suite.Len(suite.validator.Errors(), 0)
|
||||||
|
|
||||||
suite.Equal("mail", suite.config.LDAP.MailAttribute)
|
suite.Equal("mail", suite.config.LDAP.Attributes.Mail)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *LDAPAuthenticationBackendSuite) TestShouldSetDefaultDisplayNameAttribute() {
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldSetDefaultDisplayNameAttribute() {
|
||||||
|
@ -811,7 +811,7 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldSetDefaultDisplayNameAttr
|
||||||
suite.Len(suite.validator.Warnings(), 0)
|
suite.Len(suite.validator.Warnings(), 0)
|
||||||
suite.Len(suite.validator.Errors(), 0)
|
suite.Len(suite.validator.Errors(), 0)
|
||||||
|
|
||||||
suite.Equal("displayName", suite.config.LDAP.DisplayNameAttribute)
|
suite.Equal("displayName", suite.config.LDAP.Attributes.DisplayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *LDAPAuthenticationBackendSuite) TestShouldSetDefaultRefreshInterval() {
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldSetDefaultRefreshInterval() {
|
||||||
|
@ -890,6 +890,64 @@ func (suite *LDAPAuthenticationBackendSuite) TestShouldNotAllowSSL30() {
|
||||||
suite.EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: tls: option 'minimum_version' is invalid: minimum version is TLS1.0 but SSL3.0 was configured")
|
suite.EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: tls: option 'minimum_version' is invalid: minimum version is TLS1.0 but SSL3.0 was configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldErrorOnBadSearchMode() {
|
||||||
|
suite.config.LDAP.GroupSearchMode = "memberOF"
|
||||||
|
|
||||||
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
suite.Len(suite.validator.Warnings(), 0)
|
||||||
|
suite.Require().Len(suite.validator.Errors(), 1)
|
||||||
|
|
||||||
|
suite.EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: option 'group_search_mode' must be one of 'filter' or 'memberof' but it's configured as 'memberOF'")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldNoErrorOnPlaceholderSearchMode() {
|
||||||
|
suite.config.LDAP.GroupSearchMode = memberof
|
||||||
|
suite.config.LDAP.GroupsFilter = filterMemberOfRDN
|
||||||
|
suite.config.LDAP.Attributes.MemberOf = memberOf
|
||||||
|
|
||||||
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
suite.Len(suite.validator.Warnings(), 0)
|
||||||
|
suite.Len(suite.validator.Errors(), 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldErrorOnMissingPlaceholderSearchMode() {
|
||||||
|
suite.config.LDAP.GroupSearchMode = memberof
|
||||||
|
|
||||||
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
suite.Len(suite.validator.Warnings(), 0)
|
||||||
|
suite.Require().Len(suite.validator.Errors(), 1)
|
||||||
|
|
||||||
|
suite.EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: option 'groups_filter' must contain one of the '{memberof:rdn}' or '{memberof:dn}' placeholders when using a group_search_mode of 'memberof' but they're absent")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldErrorOnMissingDistinguishedNameDN() {
|
||||||
|
suite.config.LDAP.Attributes.DistinguishedName = ""
|
||||||
|
suite.config.LDAP.GroupsFilter = "(|({memberof:dn}))"
|
||||||
|
|
||||||
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
suite.Len(suite.validator.Warnings(), 0)
|
||||||
|
suite.Require().Len(suite.validator.Errors(), 2)
|
||||||
|
|
||||||
|
suite.EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: attributes: option 'distinguished_name' must be provided when using the '{memberof:dn}' placeholder but it's absent")
|
||||||
|
suite.EqualError(suite.validator.Errors()[1], "authentication_backend: ldap: attributes: option 'member_of' must be provided when using the '{memberof:rdn}' or '{memberof:dn}' placeholder but it's absent")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldErrorOnMissingMemberOfRDN() {
|
||||||
|
suite.config.LDAP.Attributes.DistinguishedName = ""
|
||||||
|
suite.config.LDAP.GroupsFilter = filterMemberOfRDN
|
||||||
|
|
||||||
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
suite.Len(suite.validator.Warnings(), 0)
|
||||||
|
suite.Require().Len(suite.validator.Errors(), 1)
|
||||||
|
|
||||||
|
suite.EqualError(suite.validator.Errors()[0], "authentication_backend: ldap: attributes: option 'member_of' must be provided when using the '{memberof:rdn}' or '{memberof:dn}' placeholder but it's absent")
|
||||||
|
}
|
||||||
|
|
||||||
func (suite *LDAPAuthenticationBackendSuite) TestShouldNotAllowTLSVerMinGreaterThanVerMax() {
|
func (suite *LDAPAuthenticationBackendSuite) TestShouldNotAllowTLSVerMinGreaterThanVerMax() {
|
||||||
suite.config.LDAP.TLS = &schema.TLSConfig{
|
suite.config.LDAP.TLS = &schema.TLSConfig{
|
||||||
MinimumVersion: schema.TLSVersion{Value: tls.VersionTLS13},
|
MinimumVersion: schema.TLSVersion{Value: tls.VersionTLS13},
|
||||||
|
@ -951,32 +1009,39 @@ func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldSetActiveDirec
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.UsersFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.UsersFilter,
|
||||||
suite.config.LDAP.UsersFilter)
|
suite.config.LDAP.UsersFilter)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.UsernameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.Attributes.Username,
|
||||||
suite.config.LDAP.UsernameAttribute)
|
suite.config.LDAP.Attributes.Username)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.DisplayNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.Attributes.DisplayName,
|
||||||
suite.config.LDAP.DisplayNameAttribute)
|
suite.config.LDAP.Attributes.DisplayName)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.MailAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.Attributes.Mail,
|
||||||
suite.config.LDAP.MailAttribute)
|
suite.config.LDAP.Attributes.Mail)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.GroupsFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.GroupsFilter,
|
||||||
suite.config.LDAP.GroupsFilter)
|
suite.config.LDAP.GroupsFilter)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.GroupNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.Attributes.GroupName,
|
||||||
suite.config.LDAP.GroupNameAttribute)
|
suite.config.LDAP.Attributes.GroupName)
|
||||||
|
|
||||||
|
suite.Equal(memberOf, suite.config.LDAP.Attributes.MemberOf)
|
||||||
|
suite.Equal("distinguishedName", suite.config.LDAP.Attributes.DistinguishedName)
|
||||||
|
suite.Equal(schema.LDAPGroupSearchModeFilter, suite.config.LDAP.GroupSearchMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
|
func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
|
||||||
suite.config.LDAP.Timeout = time.Second * 2
|
suite.config.LDAP.Timeout = time.Second * 2
|
||||||
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2))"
|
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectCategory=person)(objectClass=user)(!userAccountControl:1.2.840.113556.1.4.803:=2))"
|
||||||
suite.config.LDAP.UsernameAttribute = "cn"
|
suite.config.LDAP.Attributes.Username = "cn"
|
||||||
suite.config.LDAP.MailAttribute = "userPrincipalName"
|
suite.config.LDAP.Attributes.Mail = "userPrincipalName"
|
||||||
suite.config.LDAP.DisplayNameAttribute = "name"
|
suite.config.LDAP.Attributes.DisplayName = "name"
|
||||||
suite.config.LDAP.GroupsFilter = "(&(member={dn})(objectClass=group)(objectCategory=group))"
|
suite.config.LDAP.GroupsFilter = "(&(member={dn})(objectClass=group)(objectCategory=group))"
|
||||||
suite.config.LDAP.GroupNameAttribute = "distinguishedName"
|
suite.config.LDAP.Attributes.GroupName = "distinguishedName"
|
||||||
suite.config.LDAP.AdditionalUsersDN = "OU=test"
|
suite.config.LDAP.AdditionalUsersDN = "OU=test"
|
||||||
suite.config.LDAP.AdditionalGroupsDN = "OU=grps"
|
suite.config.LDAP.AdditionalGroupsDN = "OU=grps"
|
||||||
|
suite.config.LDAP.Attributes.MemberOf = member
|
||||||
|
suite.config.LDAP.GroupSearchMode = memberof
|
||||||
|
suite.config.LDAP.Attributes.DistinguishedName = "objectGUID"
|
||||||
|
|
||||||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
@ -993,20 +1058,24 @@ func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldOnlySetDefault
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.UsersFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.UsersFilter,
|
||||||
suite.config.LDAP.UsersFilter)
|
suite.config.LDAP.UsersFilter)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.UsernameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.Attributes.Username,
|
||||||
suite.config.LDAP.UsernameAttribute)
|
suite.config.LDAP.Attributes.Username)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.DisplayNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.Attributes.DisplayName,
|
||||||
suite.config.LDAP.DisplayNameAttribute)
|
suite.config.LDAP.Attributes.DisplayName)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.MailAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.Attributes.Mail,
|
||||||
suite.config.LDAP.MailAttribute)
|
suite.config.LDAP.Attributes.Mail)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.GroupsFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.GroupsFilter,
|
||||||
suite.config.LDAP.GroupsFilter)
|
suite.config.LDAP.GroupsFilter)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.GroupNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationActiveDirectory.Attributes.GroupName,
|
||||||
suite.config.LDAP.GroupNameAttribute)
|
suite.config.LDAP.Attributes.GroupName)
|
||||||
|
|
||||||
|
suite.Equal(member, suite.config.LDAP.Attributes.MemberOf)
|
||||||
|
suite.Equal("objectGUID", suite.config.LDAP.Attributes.DistinguishedName)
|
||||||
|
suite.Equal(memberof, suite.config.LDAP.GroupSearchMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldRaiseErrorOnInvalidURLWithHTTP() {
|
func (suite *ActiveDirectoryAuthenticationBackendSuite) TestShouldRaiseErrorOnInvalidURLWithHTTP() {
|
||||||
|
@ -1059,32 +1128,38 @@ func (suite *RFC2307bisAuthenticationBackendSuite) TestShouldSetDefaults() {
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsersFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsersFilter,
|
||||||
suite.config.LDAP.UsersFilter)
|
suite.config.LDAP.UsersFilter)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsernameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Attributes.Username,
|
||||||
suite.config.LDAP.UsernameAttribute)
|
suite.config.LDAP.Attributes.Username)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.DisplayNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Attributes.DisplayName,
|
||||||
suite.config.LDAP.DisplayNameAttribute)
|
suite.config.LDAP.Attributes.DisplayName)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.MailAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Attributes.Mail,
|
||||||
suite.config.LDAP.MailAttribute)
|
suite.config.LDAP.Attributes.Mail)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupsFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupsFilter,
|
||||||
suite.config.LDAP.GroupsFilter)
|
suite.config.LDAP.GroupsFilter)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Attributes.GroupName,
|
||||||
suite.config.LDAP.GroupNameAttribute)
|
suite.config.LDAP.Attributes.GroupName)
|
||||||
|
|
||||||
|
suite.Equal(memberOf, suite.config.LDAP.Attributes.MemberOf)
|
||||||
|
suite.Equal("", suite.config.LDAP.Attributes.DistinguishedName)
|
||||||
|
suite.Equal(schema.LDAPGroupSearchModeFilter, suite.config.LDAP.GroupSearchMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *RFC2307bisAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
|
func (suite *RFC2307bisAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
|
||||||
suite.config.LDAP.Timeout = time.Second * 2
|
suite.config.LDAP.Timeout = time.Second * 2
|
||||||
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectClass=Person))"
|
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectClass=Person))"
|
||||||
suite.config.LDAP.UsernameAttribute = "o"
|
suite.config.LDAP.Attributes.Username = "o"
|
||||||
suite.config.LDAP.MailAttribute = "Email"
|
suite.config.LDAP.Attributes.Mail = "Email"
|
||||||
suite.config.LDAP.DisplayNameAttribute = "Given"
|
suite.config.LDAP.Attributes.DisplayName = "Given"
|
||||||
suite.config.LDAP.GroupsFilter = "(&(member={dn})(objectClass=posixGroup)(objectClass=top))"
|
suite.config.LDAP.GroupsFilter = "(&(member={dn})(objectClass=posixGroup)(objectClass=top))"
|
||||||
suite.config.LDAP.GroupNameAttribute = "gid"
|
suite.config.LDAP.Attributes.GroupName = "gid"
|
||||||
|
suite.config.LDAP.Attributes.MemberOf = member
|
||||||
suite.config.LDAP.AdditionalUsersDN = "OU=users,OU=OpenLDAP"
|
suite.config.LDAP.AdditionalUsersDN = "OU=users,OU=OpenLDAP"
|
||||||
suite.config.LDAP.AdditionalGroupsDN = "OU=groups,OU=OpenLDAP"
|
suite.config.LDAP.AdditionalGroupsDN = "OU=groups,OU=OpenLDAP"
|
||||||
|
suite.config.LDAP.GroupSearchMode = memberof
|
||||||
|
|
||||||
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
ValidateAuthenticationBackend(&suite.config, suite.validator)
|
||||||
|
|
||||||
|
@ -1104,20 +1179,24 @@ func (suite *RFC2307bisAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNo
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsersFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsersFilter,
|
||||||
suite.config.LDAP.UsersFilter)
|
suite.config.LDAP.UsersFilter)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.UsernameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Attributes.Username,
|
||||||
suite.config.LDAP.UsernameAttribute)
|
suite.config.LDAP.Attributes.Username)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.DisplayNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Attributes.DisplayName,
|
||||||
suite.config.LDAP.DisplayNameAttribute)
|
suite.config.LDAP.Attributes.DisplayName)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.MailAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Attributes.Mail,
|
||||||
suite.config.LDAP.MailAttribute)
|
suite.config.LDAP.Attributes.Mail)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupsFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupsFilter,
|
||||||
suite.config.LDAP.GroupsFilter)
|
suite.config.LDAP.GroupsFilter)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.GroupNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationRFC2307bis.Attributes.GroupName,
|
||||||
suite.config.LDAP.GroupNameAttribute)
|
suite.config.LDAP.Attributes.GroupName)
|
||||||
|
|
||||||
|
suite.Equal(member, suite.config.LDAP.Attributes.MemberOf)
|
||||||
|
suite.Equal("", suite.config.LDAP.Attributes.DistinguishedName)
|
||||||
|
suite.Equal(memberof, suite.config.LDAP.GroupSearchMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRFC2307bisAuthenticationBackend(t *testing.T) {
|
func TestRFC2307bisAuthenticationBackend(t *testing.T) {
|
||||||
|
@ -1161,30 +1240,35 @@ func (suite *FreeIPAAuthenticationBackendSuite) TestShouldSetDefaults() {
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.UsersFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.UsersFilter,
|
||||||
suite.config.LDAP.UsersFilter)
|
suite.config.LDAP.UsersFilter)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.UsernameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.Attributes.Username,
|
||||||
suite.config.LDAP.UsernameAttribute)
|
suite.config.LDAP.Attributes.Username)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.DisplayNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.Attributes.DisplayName,
|
||||||
suite.config.LDAP.DisplayNameAttribute)
|
suite.config.LDAP.Attributes.DisplayName)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.MailAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.Attributes.Mail,
|
||||||
suite.config.LDAP.MailAttribute)
|
suite.config.LDAP.Attributes.Mail)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.GroupsFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.GroupsFilter,
|
||||||
suite.config.LDAP.GroupsFilter)
|
suite.config.LDAP.GroupsFilter)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.GroupNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.Attributes.GroupName,
|
||||||
suite.config.LDAP.GroupNameAttribute)
|
suite.config.LDAP.Attributes.GroupName)
|
||||||
|
|
||||||
|
suite.Equal(memberOf, suite.config.LDAP.Attributes.MemberOf)
|
||||||
|
suite.Equal("", suite.config.LDAP.Attributes.DistinguishedName)
|
||||||
|
suite.Equal(schema.LDAPGroupSearchModeFilter, suite.config.LDAP.GroupSearchMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *FreeIPAAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
|
func (suite *FreeIPAAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
|
||||||
suite.config.LDAP.Timeout = time.Second * 2
|
suite.config.LDAP.Timeout = time.Second * 2
|
||||||
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectClass=person)(!(nsAccountLock=TRUE)))"
|
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectClass=person)(!(nsAccountLock=TRUE)))"
|
||||||
suite.config.LDAP.UsernameAttribute = "dn"
|
suite.config.LDAP.Attributes.Username = "dn"
|
||||||
suite.config.LDAP.MailAttribute = "email"
|
suite.config.LDAP.Attributes.Mail = "email"
|
||||||
suite.config.LDAP.DisplayNameAttribute = "gecos"
|
suite.config.LDAP.Attributes.DisplayName = "gecos"
|
||||||
suite.config.LDAP.GroupsFilter = "(&(member={dn})(objectClass=posixgroup))"
|
suite.config.LDAP.GroupsFilter = "(&(member={dn})(objectClass=posixgroup))"
|
||||||
suite.config.LDAP.GroupNameAttribute = "groupName"
|
suite.config.LDAP.Attributes.GroupName = "groupName"
|
||||||
|
suite.config.LDAP.Attributes.MemberOf = member
|
||||||
suite.config.LDAP.AdditionalUsersDN = "OU=people"
|
suite.config.LDAP.AdditionalUsersDN = "OU=people"
|
||||||
suite.config.LDAP.AdditionalGroupsDN = "OU=grp"
|
suite.config.LDAP.AdditionalGroupsDN = "OU=grp"
|
||||||
|
|
||||||
|
@ -1203,20 +1287,24 @@ func (suite *FreeIPAAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotMa
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.UsersFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.UsersFilter,
|
||||||
suite.config.LDAP.UsersFilter)
|
suite.config.LDAP.UsersFilter)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.UsernameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.Attributes.Username,
|
||||||
suite.config.LDAP.UsernameAttribute)
|
suite.config.LDAP.Attributes.Username)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.DisplayNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.Attributes.DisplayName,
|
||||||
suite.config.LDAP.DisplayNameAttribute)
|
suite.config.LDAP.Attributes.DisplayName)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.MailAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.Attributes.Mail,
|
||||||
suite.config.LDAP.MailAttribute)
|
suite.config.LDAP.Attributes.Mail)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.GroupsFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.GroupsFilter,
|
||||||
suite.config.LDAP.GroupsFilter)
|
suite.config.LDAP.GroupsFilter)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.GroupNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationFreeIPA.Attributes.GroupName,
|
||||||
suite.config.LDAP.GroupNameAttribute)
|
suite.config.LDAP.Attributes.GroupName)
|
||||||
|
|
||||||
|
suite.Equal(member, suite.config.LDAP.Attributes.MemberOf)
|
||||||
|
suite.Equal("", suite.config.LDAP.Attributes.DistinguishedName)
|
||||||
|
suite.Equal(schema.LDAPGroupSearchModeFilter, suite.config.LDAP.GroupSearchMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFreeIPAAuthenticationBackend(t *testing.T) {
|
func TestFreeIPAAuthenticationBackend(t *testing.T) {
|
||||||
|
@ -1260,30 +1348,34 @@ func (suite *LLDAPAuthenticationBackendSuite) TestShouldSetDefaults() {
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.UsersFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.UsersFilter,
|
||||||
suite.config.LDAP.UsersFilter)
|
suite.config.LDAP.UsersFilter)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.UsernameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.Attributes.Username,
|
||||||
suite.config.LDAP.UsernameAttribute)
|
suite.config.LDAP.Attributes.Username)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.DisplayNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.Attributes.DisplayName,
|
||||||
suite.config.LDAP.DisplayNameAttribute)
|
suite.config.LDAP.Attributes.DisplayName)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.MailAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.Attributes.Mail,
|
||||||
suite.config.LDAP.MailAttribute)
|
suite.config.LDAP.Attributes.Mail)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.GroupsFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.GroupsFilter,
|
||||||
suite.config.LDAP.GroupsFilter)
|
suite.config.LDAP.GroupsFilter)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.GroupNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.Attributes.GroupName,
|
||||||
suite.config.LDAP.GroupNameAttribute)
|
suite.config.LDAP.Attributes.GroupName)
|
||||||
|
|
||||||
|
suite.Equal("", suite.config.LDAP.Attributes.MemberOf)
|
||||||
|
suite.Equal("", suite.config.LDAP.Attributes.DistinguishedName)
|
||||||
|
suite.Equal(schema.LDAPGroupSearchModeFilter, suite.config.LDAP.GroupSearchMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *LLDAPAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
|
func (suite *LLDAPAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
|
||||||
suite.config.LDAP.Timeout = time.Second * 2
|
suite.config.LDAP.Timeout = time.Second * 2
|
||||||
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectClass=Person)(!(nsAccountLock=TRUE)))"
|
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectClass=Person)(!(nsAccountLock=TRUE)))"
|
||||||
suite.config.LDAP.UsernameAttribute = "username"
|
suite.config.LDAP.Attributes.Username = "username"
|
||||||
suite.config.LDAP.MailAttribute = "m"
|
suite.config.LDAP.Attributes.Mail = "m"
|
||||||
suite.config.LDAP.DisplayNameAttribute = "fn"
|
suite.config.LDAP.Attributes.DisplayName = "fn"
|
||||||
suite.config.LDAP.GroupsFilter = "(&(member={dn})(!(objectClass=posixGroup)))"
|
suite.config.LDAP.GroupsFilter = "(&(member={dn})(!(objectClass=posixGroup)))"
|
||||||
suite.config.LDAP.GroupNameAttribute = "grpz"
|
suite.config.LDAP.Attributes.GroupName = "grpz"
|
||||||
suite.config.LDAP.AdditionalUsersDN = "OU=no"
|
suite.config.LDAP.AdditionalUsersDN = "OU=no"
|
||||||
suite.config.LDAP.AdditionalGroupsDN = "OU=yes"
|
suite.config.LDAP.AdditionalGroupsDN = "OU=yes"
|
||||||
|
|
||||||
|
@ -1305,20 +1397,24 @@ func (suite *LLDAPAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManu
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.UsersFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.UsersFilter,
|
||||||
suite.config.LDAP.UsersFilter)
|
suite.config.LDAP.UsersFilter)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.UsernameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.Attributes.Username,
|
||||||
suite.config.LDAP.UsernameAttribute)
|
suite.config.LDAP.Attributes.Username)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.DisplayNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.Attributes.DisplayName,
|
||||||
suite.config.LDAP.DisplayNameAttribute)
|
suite.config.LDAP.Attributes.DisplayName)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.MailAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.Attributes.Mail,
|
||||||
suite.config.LDAP.MailAttribute)
|
suite.config.LDAP.Attributes.Mail)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.GroupsFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.GroupsFilter,
|
||||||
suite.config.LDAP.GroupsFilter)
|
suite.config.LDAP.GroupsFilter)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.GroupNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationLLDAP.Attributes.GroupName,
|
||||||
suite.config.LDAP.GroupNameAttribute)
|
suite.config.LDAP.Attributes.GroupName)
|
||||||
|
|
||||||
|
suite.Equal("", suite.config.LDAP.Attributes.MemberOf)
|
||||||
|
suite.Equal("", suite.config.LDAP.Attributes.DistinguishedName)
|
||||||
|
suite.Equal(schema.LDAPGroupSearchModeFilter, suite.config.LDAP.GroupSearchMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLLDAPAuthenticationBackend(t *testing.T) {
|
func TestLLDAPAuthenticationBackend(t *testing.T) {
|
||||||
|
@ -1362,30 +1458,34 @@ func (suite *GLAuthAuthenticationBackendSuite) TestShouldSetDefaults() {
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.UsersFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.UsersFilter,
|
||||||
suite.config.LDAP.UsersFilter)
|
suite.config.LDAP.UsersFilter)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.UsernameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.Attributes.Username,
|
||||||
suite.config.LDAP.UsernameAttribute)
|
suite.config.LDAP.Attributes.Username)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.DisplayNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.Attributes.DisplayName,
|
||||||
suite.config.LDAP.DisplayNameAttribute)
|
suite.config.LDAP.Attributes.DisplayName)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.MailAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.Attributes.Mail,
|
||||||
suite.config.LDAP.MailAttribute)
|
suite.config.LDAP.Attributes.Mail)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.GroupsFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.GroupsFilter,
|
||||||
suite.config.LDAP.GroupsFilter)
|
suite.config.LDAP.GroupsFilter)
|
||||||
suite.Equal(
|
suite.Equal(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.GroupNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.Attributes.GroupName,
|
||||||
suite.config.LDAP.GroupNameAttribute)
|
suite.config.LDAP.Attributes.GroupName)
|
||||||
|
|
||||||
|
suite.Equal("", suite.config.LDAP.Attributes.MemberOf)
|
||||||
|
suite.Equal("", suite.config.LDAP.Attributes.DistinguishedName)
|
||||||
|
suite.Equal(schema.LDAPGroupSearchModeFilter, suite.config.LDAP.GroupSearchMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *GLAuthAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
|
func (suite *GLAuthAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotManuallyConfigured() {
|
||||||
suite.config.LDAP.Timeout = time.Second * 2
|
suite.config.LDAP.Timeout = time.Second * 2
|
||||||
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectClass=Person)(!(accountStatus=inactive)))"
|
suite.config.LDAP.UsersFilter = "(&({username_attribute}={input})(objectClass=Person)(!(accountStatus=inactive)))"
|
||||||
suite.config.LDAP.UsernameAttribute = "description"
|
suite.config.LDAP.Attributes.Username = "description"
|
||||||
suite.config.LDAP.MailAttribute = "sender"
|
suite.config.LDAP.Attributes.Mail = "sender"
|
||||||
suite.config.LDAP.DisplayNameAttribute = "given"
|
suite.config.LDAP.Attributes.DisplayName = "given"
|
||||||
suite.config.LDAP.GroupsFilter = "(&(member={dn})(objectClass=posixGroup))"
|
suite.config.LDAP.GroupsFilter = "(&(member={dn})(objectClass=posixGroup))"
|
||||||
suite.config.LDAP.GroupNameAttribute = "grp"
|
suite.config.LDAP.Attributes.GroupName = "grp"
|
||||||
suite.config.LDAP.AdditionalUsersDN = "OU=users,OU=GlAuth"
|
suite.config.LDAP.AdditionalUsersDN = "OU=users,OU=GlAuth"
|
||||||
suite.config.LDAP.AdditionalGroupsDN = "OU=groups,OU=GLAuth"
|
suite.config.LDAP.AdditionalGroupsDN = "OU=groups,OU=GLAuth"
|
||||||
|
|
||||||
|
@ -1407,20 +1507,24 @@ func (suite *GLAuthAuthenticationBackendSuite) TestShouldOnlySetDefaultsIfNotMan
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.UsersFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.UsersFilter,
|
||||||
suite.config.LDAP.UsersFilter)
|
suite.config.LDAP.UsersFilter)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.UsernameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.Attributes.Username,
|
||||||
suite.config.LDAP.UsernameAttribute)
|
suite.config.LDAP.Attributes.Username)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.DisplayNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.Attributes.DisplayName,
|
||||||
suite.config.LDAP.DisplayNameAttribute)
|
suite.config.LDAP.Attributes.DisplayName)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.MailAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.Attributes.Mail,
|
||||||
suite.config.LDAP.MailAttribute)
|
suite.config.LDAP.Attributes.Mail)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.GroupsFilter,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.GroupsFilter,
|
||||||
suite.config.LDAP.GroupsFilter)
|
suite.config.LDAP.GroupsFilter)
|
||||||
suite.NotEqual(
|
suite.NotEqual(
|
||||||
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.GroupNameAttribute,
|
schema.DefaultLDAPAuthenticationBackendConfigurationImplementationGLAuth.Attributes.GroupName,
|
||||||
suite.config.LDAP.GroupNameAttribute)
|
suite.config.LDAP.Attributes.GroupName)
|
||||||
|
|
||||||
|
suite.Equal("", suite.config.LDAP.Attributes.MemberOf)
|
||||||
|
suite.Equal("", suite.config.LDAP.Attributes.DistinguishedName)
|
||||||
|
suite.Equal(schema.LDAPGroupSearchModeFilter, suite.config.LDAP.GroupSearchMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGLAuthAuthenticationBackend(t *testing.T) {
|
func TestGLAuthAuthenticationBackend(t *testing.T) {
|
||||||
|
|
|
@ -98,9 +98,9 @@ const (
|
||||||
errFmtLDAPAuthBackendUnauthenticatedBindWithPassword = "authentication_backend: ldap: option 'permit_unauthenticated_bind' can't be enabled when a password is specified"
|
errFmtLDAPAuthBackendUnauthenticatedBindWithPassword = "authentication_backend: ldap: option 'permit_unauthenticated_bind' can't be enabled when a password is specified"
|
||||||
errFmtLDAPAuthBackendUnauthenticatedBindWithResetEnabled = "authentication_backend: ldap: option 'permit_unauthenticated_bind' can't be enabled when password reset is enabled"
|
errFmtLDAPAuthBackendUnauthenticatedBindWithResetEnabled = "authentication_backend: ldap: option 'permit_unauthenticated_bind' can't be enabled when password reset is enabled"
|
||||||
|
|
||||||
errFmtLDAPAuthBackendMissingOption = "authentication_backend: ldap: option '%s' is required"
|
errFmtLDAPAuthBackendMissingOption = "authentication_backend: ldap: option '%s' is required"
|
||||||
errFmtLDAPAuthBackendTLSConfigInvalid = "authentication_backend: ldap: tls: %w"
|
errFmtLDAPAuthBackendTLSConfigInvalid = "authentication_backend: ldap: tls: %w"
|
||||||
errFmtLDAPAuthBackendImplementation = "authentication_backend: ldap: option 'implementation' " +
|
errFmtLDAPAuthBackendOptionMustBeOneOf = "authentication_backend: ldap: option '%s' " +
|
||||||
errSuffixMustBeOneOf
|
errSuffixMustBeOneOf
|
||||||
errFmtLDAPAuthBackendFilterReplacedPlaceholders = "authentication_backend: ldap: option " +
|
errFmtLDAPAuthBackendFilterReplacedPlaceholders = "authentication_backend: ldap: option " +
|
||||||
"'%s' has an invalid placeholder: '%s' has been removed, please use '%s' instead"
|
"'%s' has an invalid placeholder: '%s' has been removed, please use '%s' instead"
|
||||||
|
@ -109,6 +109,10 @@ const (
|
||||||
"'%s' must contain enclosing parenthesis: '%s' should probably be '(%s)'"
|
"'%s' must contain enclosing parenthesis: '%s' should probably be '(%s)'"
|
||||||
errFmtLDAPAuthBackendFilterMissingPlaceholder = "authentication_backend: ldap: option " +
|
errFmtLDAPAuthBackendFilterMissingPlaceholder = "authentication_backend: ldap: option " +
|
||||||
"'%s' must contain the placeholder '{%s}' but it's absent"
|
"'%s' must contain the placeholder '{%s}' but it's absent"
|
||||||
|
errFmtLDAPAuthBackendFilterMissingPlaceholderGroupSearchMode = "authentication_backend: ldap: option " +
|
||||||
|
"'%s' must contain one of the %s placeholders when using a group_search_mode of '%s' but they're absent"
|
||||||
|
errFmtLDAPAuthBackendFilterMissingAttribute = "authentication_backend: ldap: attributes: option " +
|
||||||
|
"'%s' must be provided when using the %s placeholder but it's absent"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TOTP Error constants.
|
// TOTP Error constants.
|
||||||
|
@ -371,17 +375,6 @@ const (
|
||||||
operatorNotPattern = "not pattern"
|
operatorNotPattern = "not pattern"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
|
||||||
validLDAPImplementations = []string{
|
|
||||||
schema.LDAPImplementationCustom,
|
|
||||||
schema.LDAPImplementationActiveDirectory,
|
|
||||||
schema.LDAPImplementationRFC2307bis,
|
|
||||||
schema.LDAPImplementationFreeIPA,
|
|
||||||
schema.LDAPImplementationLLDAP,
|
|
||||||
schema.LDAPImplementationGLAuth,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
legacy = "legacy"
|
legacy = "legacy"
|
||||||
authzImplementationLegacy = "Legacy"
|
authzImplementationLegacy = "Legacy"
|
||||||
|
@ -397,6 +390,22 @@ var (
|
||||||
validAuthzAuthnStrategies = []string{"CookieSession", "HeaderAuthorization", "HeaderProxyAuthorization", "HeaderAuthRequestProxyAuthorization", "HeaderLegacy"}
|
validAuthzAuthnStrategies = []string{"CookieSession", "HeaderAuthorization", "HeaderProxyAuthorization", "HeaderAuthRequestProxyAuthorization", "HeaderLegacy"}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
validLDAPImplementations = []string{
|
||||||
|
schema.LDAPImplementationCustom,
|
||||||
|
schema.LDAPImplementationActiveDirectory,
|
||||||
|
schema.LDAPImplementationRFC2307bis,
|
||||||
|
schema.LDAPImplementationFreeIPA,
|
||||||
|
schema.LDAPImplementationLLDAP,
|
||||||
|
schema.LDAPImplementationGLAuth,
|
||||||
|
}
|
||||||
|
|
||||||
|
validLDAPGroupSearchModes = []string{
|
||||||
|
schema.LDAPGroupSearchModeFilter,
|
||||||
|
schema.LDAPGroupSearchModeMemberOf,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
validArgon2Variants = []string{"argon2id", "id", "argon2i", "i", "argon2d", "d"}
|
validArgon2Variants = []string{"argon2id", "id", "argon2i", "i", "argon2d", "d"}
|
||||||
validSHA2CryptVariants = []string{digestSHA256, digestSHA512}
|
validSHA2CryptVariants = []string{digestSHA256, digestSHA512}
|
||||||
|
|
|
@ -13,6 +13,11 @@ const (
|
||||||
testLDAPURL = "ldap://ldap"
|
testLDAPURL = "ldap://ldap"
|
||||||
testLDAPUser = "user"
|
testLDAPUser = "user"
|
||||||
testEncryptionKey = "a_not_so_secure_encryption_key"
|
testEncryptionKey = "a_not_so_secure_encryption_key"
|
||||||
|
|
||||||
|
member = "member"
|
||||||
|
memberof = "memberof"
|
||||||
|
memberOf = "memberOf"
|
||||||
|
filterMemberOfRDN = "(|({memberof:rdn}))"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
|
@ -21,16 +21,19 @@ authentication_backend:
|
||||||
ldap:
|
ldap:
|
||||||
address: 'ldap://openldap'
|
address: 'ldap://openldap'
|
||||||
base_dn: dc=example,dc=com
|
base_dn: dc=example,dc=com
|
||||||
username_attribute: uid
|
|
||||||
additional_users_dn: ou=users
|
additional_users_dn: ou=users
|
||||||
users_filter: (&({username_attribute}={input})(objectClass=person))
|
users_filter: (&({username_attribute}={input})(objectClass=person))
|
||||||
additional_groups_dn: ou=groups
|
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
|
|
||||||
user: cn=admin,dc=example,dc=com
|
user: cn=admin,dc=example,dc=com
|
||||||
password: password
|
password: password
|
||||||
|
attributes:
|
||||||
|
distinguished_name: 'distinguishedName'
|
||||||
|
username: 'uid'
|
||||||
|
display_name: 'displayName'
|
||||||
|
mail: 'mail'
|
||||||
|
member_of: 'memberOf'
|
||||||
|
group_name: 'cn'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: deny
|
default_policy: deny
|
||||||
|
|
|
@ -22,16 +22,19 @@ authentication_backend:
|
||||||
tls:
|
tls:
|
||||||
skip_verify: true
|
skip_verify: true
|
||||||
base_dn: dc=example,dc=com
|
base_dn: dc=example,dc=com
|
||||||
username_attribute: uid
|
|
||||||
additional_users_dn: ou=users
|
additional_users_dn: ou=users
|
||||||
users_filter: (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person)(objectClass=inetOrgPerson)) # yamllint disable-line rule:line-length
|
users_filter: (&(|({username_attribute}={input})({mail_attribute}={input}))(objectClass=person)(objectClass=inetOrgPerson)) # yamllint disable-line rule:line-length
|
||||||
additional_groups_dn: ou=groups
|
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
|
|
||||||
user: cn=pwmanager,dc=example,dc=com
|
user: cn=pwmanager,dc=example,dc=com
|
||||||
password: password
|
password: password
|
||||||
|
attributes:
|
||||||
|
distinguished_name: ''
|
||||||
|
username: 'uid'
|
||||||
|
display_name: 'displayName'
|
||||||
|
mail: 'mail'
|
||||||
|
member_of: 'memberOf'
|
||||||
|
group_name: 'cn'
|
||||||
|
|
||||||
session:
|
session:
|
||||||
secret: unsecure_session_secret
|
secret: unsecure_session_secret
|
||||||
|
|
|
@ -20,15 +20,18 @@ authentication_backend:
|
||||||
tls:
|
tls:
|
||||||
skip_verify: true
|
skip_verify: true
|
||||||
base_dn: dc=example,dc=com
|
base_dn: dc=example,dc=com
|
||||||
username_attribute: uid
|
|
||||||
additional_users_dn: ou=users
|
additional_users_dn: ou=users
|
||||||
users_filter: (&({username_attribute}={input})(objectClass=person))
|
users_filter: (&({username_attribute}={input})(objectClass=person))
|
||||||
additional_groups_dn: ou=groups
|
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
|
|
||||||
user: cn=admin,dc=example,dc=com
|
user: cn=admin,dc=example,dc=com
|
||||||
|
attributes:
|
||||||
|
distinguished_name: ''
|
||||||
|
username: 'uid'
|
||||||
|
display_name: 'displayName'
|
||||||
|
mail: 'mail'
|
||||||
|
member_of: 'memberOf'
|
||||||
|
group_name: 'cn'
|
||||||
|
|
||||||
access_control:
|
access_control:
|
||||||
default_policy: deny
|
default_policy: deny
|
||||||
|
|
Loading…
Reference in New Issue