Bagage is the bridge between our users and garage, it enables them to synchronize files that matter for them from their computer to garage through WebDAV
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

115 lines
2.6 KiB

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 %d", len(sr.Entries)))
}
return sr.Entries[0], nil
}
func (l *ldapConnector) Close() {
if l.conn != nil {
l.conn.Close()
l.conn = nil
}
}