diff options
Diffstat (limited to 'auth_ldap.go')
-rw-r--r-- | auth_ldap.go | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/auth_ldap.go b/auth_ldap.go new file mode 100644 index 0000000..9164e93 --- /dev/null +++ b/auth_ldap.go @@ -0,0 +1,115 @@ +package main + +import ( + "errors" + "fmt" + "net/http" + + "github.com/go-ldap/ldap/v3" +) + +/* Check credentials against LDAP */ +type LdapPreAuth struct { + WithConfig *Config + OnWrongPassword ErrorHandler + OnFailure ErrorHandler + OnCreds CredsHandler +} + +func (l LdapPreAuth) WithCreds(username, password string) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + + // 1. Connect to the server + conn, err := ldapConnect(l.WithConfig) + if err != nil { + l.OnFailure.WithError(err).ServeHTTP(w, r) + return + } + defer conn.Close() + + // 2. Authenticate with provided credentials + // @FIXME we should better check the error, it could also be due to an LDAP error + err = conn.auth(username, password) + if err != nil { + l.OnWrongPassword.WithError(err).ServeHTTP(w, r) + return + } + + // 3. Fetch user's profile + profile, err := conn.profile() + if err != nil { + l.OnFailure.WithError(err).ServeHTTP(w, r) + return + } + + // 4. Basic checks upon users' attributes + access_key := profile.GetAttributeValue("garage_s3_access_key") + secret_key := profile.GetAttributeValue("garage_s3_secret_key") + if access_key == "" || secret_key == "" { + err = errors.New(fmt.Sprintf("Either access key or secret key is missing in LDAP for %s", conn.userDn)) + l.OnFailure.WithError(err).ServeHTTP(w, r) + return + } + + // 5. Send fetched credentials to the next middleware + l.OnCreds.WithCreds(access_key, secret_key).ServeHTTP(w, r) + }) +} + +/** + * Private logic + */ + +type ldapConnector struct { + conn *ldap.Conn + config *Config + userDn string +} + +func ldapConnect(c *Config) (ldapConnector, error) { + ldapSock, err := ldap.Dial("tcp", c.LdapServer) + if err != nil { + return ldapConnector{}, err + } + + return ldapConnector{ + conn: ldapSock, + config: c, + }, nil +} + +func (l *ldapConnector) auth(username, password string) error { + l.userDn = fmt.Sprintf("%s=%s,%s", l.config.UserNameAttr, username, l.config.UserBaseDN) + return l.conn.Bind(l.userDn, password) +} + +func (l *ldapConnector) profile() (*ldap.Entry, error) { + searchRequest := ldap.NewSearchRequest( + l.userDn, + ldap.ScopeBaseObject, + ldap.NeverDerefAliases, + 0, + 0, + false, + "(objectClass=*)", + []string{"garage_s3_access_key", "garage_s3_secret_key"}, + nil) + + sr, err := l.conn.Search(searchRequest) + if err != nil { + return nil, err + } + + if len(sr.Entries) != 1 { + return nil, errors.New(fmt.Sprintf("Wrong number of LDAP entries, expected 1, got", len(sr.Entries))) + } + + return sr.Entries[0], nil +} + +func (l *ldapConnector) Close() { + if l.conn != nil { + l.conn.Close() + l.conn = nil + } +} |