mirror of
https://github.com/Luzifer/nginx-sso.git
synced 2025-04-17 12:41:51 +00:00
Fix TLS dialing (#16)
* Add configuration for TLS connections * Take both TLS configurations into account
This commit is contained in:
parent
a272b49cf8
commit
05fe4f2022
3 changed files with 64 additions and 9 deletions
12
README.md
12
README.md
|
@ -182,6 +182,15 @@ providers:
|
|||
# Replace DN as the username with another attribute
|
||||
# Optional, defaults to "dn"
|
||||
username_attribute: "uid"
|
||||
# Configure TLS parameters for LDAPs connections
|
||||
# Optional, defaults to null
|
||||
tls_config:
|
||||
# Set the hostname for certificate validation
|
||||
# Optional, defaults to host from the connection URI
|
||||
validate_hostname: ldap.example.com
|
||||
# Disable certificate validation
|
||||
# Optional, defaults to false
|
||||
allow_insecure: false
|
||||
```
|
||||
|
||||
To use this provider you need to have a LDAP server set up and filled with users. The example (and default) config above assumes each of your users carries an `uid` attribute and groups does contains `member` or `uniqueMember` attributes. Inside the groups full DNs are expected. For the ACL also full DNs are used.
|
||||
|
@ -196,6 +205,9 @@ To use this provider you need to have a LDAP server set up and filled with users
|
|||
- `group_search_base` - optional - Like the `user_search_base` this limits the sub-tree where to search for groups, also defaults to `root_dn`
|
||||
- `group_membership_filter` - optional - The query to issue to list all groups the user is a member of. The DN of each group is used as the group name. If unset the query `(|(member={0})(uniqueMember={0}))` is used (`{0}` is replaced with the users DN, `{1}` is replaced with the content of the `username_attribute`)
|
||||
- `username_attribute` - optional - The attribute containing the username returned to nginx instead of the dn. If unset the `dn` is used
|
||||
- `tls_config` - optional - Configures TLS parameters for LDAPs connections
|
||||
- `validate_hostname` - optional - Set the hostname for certificate validation, when unset the hostname from the `server` URI is used
|
||||
- `allow_insecure` - optional - Disable certificate validation. Setting this is not recommended for production setups
|
||||
|
||||
When using the LDAP provider you need to pay attention when writing your ACL. As DNs are used as names for users and groups you also need to specify those in the ACL:
|
||||
|
||||
|
|
52
auth_ldap.go
52
auth_ldap.go
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
@ -25,6 +26,10 @@ type authLDAP struct {
|
|||
UserSearchBase string `yaml:"user_search_base"`
|
||||
UserSearchFilter string `yaml:"user_search_filter"`
|
||||
UsernameAttribute string `yaml:"username_attribute"`
|
||||
TLSConfig *struct {
|
||||
ValidateHostname string `yaml:"validate_hostname"`
|
||||
AllowInsecure bool `yaml:"allow_insecure"`
|
||||
} `yaml:"tls_config"`
|
||||
}
|
||||
|
||||
// AuthenticatorID needs to return an unique string to identify
|
||||
|
@ -60,6 +65,7 @@ func (a *authLDAP) Configure(yamlSource []byte) error {
|
|||
a.UserSearchBase = envelope.Providers.LDAP.UserSearchBase
|
||||
a.UserSearchFilter = envelope.Providers.LDAP.UserSearchFilter
|
||||
a.UsernameAttribute = envelope.Providers.LDAP.UsernameAttribute
|
||||
a.TLSConfig = envelope.Providers.LDAP.TLSConfig
|
||||
|
||||
// Set defaults
|
||||
if a.UserSearchFilter == "" {
|
||||
|
@ -228,6 +234,21 @@ func (a authLDAP) checkLogin(username, password, aliasAttribute string) (string,
|
|||
return userDN, alias, nil
|
||||
}
|
||||
|
||||
func (a authLDAP) portFromScheme(scheme, override string) string {
|
||||
if override != "" {
|
||||
return override
|
||||
}
|
||||
|
||||
switch scheme {
|
||||
case "ldap":
|
||||
return "389"
|
||||
case "ldaps":
|
||||
return "636"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// dial connects to the LDAP server and authenticates using manager_dn
|
||||
func (a authLDAP) dial() (*ldap.Conn, error) {
|
||||
u, err := url.Parse(a.Server)
|
||||
|
@ -238,18 +259,31 @@ func (a authLDAP) dial() (*ldap.Conn, error) {
|
|||
host := u.Host
|
||||
port := u.Port()
|
||||
|
||||
if port == "" {
|
||||
switch u.Scheme {
|
||||
case "ldap":
|
||||
port = "389"
|
||||
case "ldaps":
|
||||
port = "636"
|
||||
default:
|
||||
return nil, fmt.Errorf("Unsupported scheme %s", u.Scheme)
|
||||
var l *ldap.Conn
|
||||
|
||||
switch u.Scheme {
|
||||
case "ldap":
|
||||
l, err = ldap.Dial("tcp", fmt.Sprintf("%s:%s", host, a.portFromScheme(u.Scheme, port)))
|
||||
|
||||
case "ldaps":
|
||||
tlsConfig := &tls.Config{ServerName: host}
|
||||
|
||||
if a.TLSConfig != nil && (a.TLSConfig.ValidateHostname != "" || a.TLSConfig.AllowInsecure) {
|
||||
tlsConfig = &tls.Config{
|
||||
ServerName: a.TLSConfig.ValidateHostname,
|
||||
InsecureSkipVerify: a.TLSConfig.AllowInsecure,
|
||||
}
|
||||
}
|
||||
|
||||
l, err = ldap.DialTLS(
|
||||
"tcp", fmt.Sprintf("%s:%s", host, a.portFromScheme(u.Scheme, port)),
|
||||
tlsConfig,
|
||||
)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("Unsupported scheme %s", u.Scheme)
|
||||
}
|
||||
|
||||
l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%s", host, port))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Unable to connect to LDAP: %s", err)
|
||||
}
|
||||
|
|
|
@ -55,6 +55,15 @@ providers:
|
|||
# Replace DN as the username with another attribute
|
||||
# Optional, defaults to "dn"
|
||||
username_attribute: "uid"
|
||||
# Configure TLS parameters for LDAPs connections
|
||||
# Optional, defaults to null
|
||||
tls_config:
|
||||
# Set the hostname for certificate validation
|
||||
# Optional, defaults to host from the connection URI
|
||||
validate_hostname: ldap.example.com
|
||||
# Disable certificate validation
|
||||
# Optional, defaults to false
|
||||
allow_insecure: false
|
||||
|
||||
# Authentication against embedded user database
|
||||
# Supports: Users, Groups
|
||||
|
|
Loading…
Add table
Reference in a new issue