mirror of
https://github.com/matrix-org/dendrite.git
synced 2026-01-17 11:03:11 -06:00
113 lines
3 KiB
Go
113 lines
3 KiB
Go
package auth
|
|
|
|
import (
|
|
"github.com/go-ldap/ldap/v3"
|
|
"github.com/matrix-org/dendrite/clientapi/jsonerror"
|
|
"github.com/matrix-org/dendrite/setup/config"
|
|
"github.com/matrix-org/util"
|
|
"net/http"
|
|
"strings"
|
|
)
|
|
|
|
type LdapAuthenticator struct {
|
|
config config.Ldap
|
|
}
|
|
|
|
func NewLdapAuthenticator(config config.Ldap) *LdapAuthenticator {
|
|
return &LdapAuthenticator{
|
|
config: config,
|
|
}
|
|
}
|
|
|
|
func (l *LdapAuthenticator) Authenticate(username, password string) (bool, *util.JSONResponse) {
|
|
var conn *ldap.Conn
|
|
conn, err := ldap.DialURL(l.config.Uri)
|
|
if err != nil {
|
|
return false, &util.JSONResponse{
|
|
Code: http.StatusInternalServerError,
|
|
JSON: jsonerror.Unknown("unable to connect to ldap: " + err.Error()),
|
|
}
|
|
}
|
|
defer conn.Close()
|
|
|
|
if l.config.AdminBindEnabled {
|
|
err = conn.Bind(l.config.AdminBindDn, l.config.AdminBindPassword)
|
|
if err != nil {
|
|
return false, &util.JSONResponse{
|
|
Code: http.StatusInternalServerError,
|
|
JSON: jsonerror.Unknown("unable to bind to ldap: " + err.Error()),
|
|
}
|
|
}
|
|
filter := strings.ReplaceAll(l.config.SearchFilter, "{username}", username)
|
|
searchRequest := ldap.NewSearchRequest(
|
|
l.config.SearchBaseDn, ldap.ScopeWholeSubtree, ldap.NeverDerefAliases,
|
|
0, 0, false, filter, []string{l.config.SearchAttribute}, nil,
|
|
)
|
|
result, err := conn.Search(searchRequest)
|
|
if err != nil {
|
|
return false, &util.JSONResponse{
|
|
Code: http.StatusInternalServerError,
|
|
JSON: jsonerror.Unknown("unable to bind to search ldap: " + err.Error()),
|
|
}
|
|
}
|
|
if len(result.Entries) > 1 {
|
|
return false, &util.JSONResponse{
|
|
Code: http.StatusUnauthorized,
|
|
JSON: jsonerror.BadJSON("'user' must be duplicated."),
|
|
}
|
|
}
|
|
if len(result.Entries) < 1 {
|
|
return false, &util.JSONResponse{
|
|
Code: http.StatusUnauthorized,
|
|
JSON: jsonerror.BadJSON("'user' not found."),
|
|
}
|
|
}
|
|
|
|
userDN := result.Entries[0].DN
|
|
err = conn.Bind(userDN, password)
|
|
if err != nil {
|
|
return false, &util.JSONResponse{
|
|
Code: http.StatusUnauthorized,
|
|
JSON: jsonerror.InvalidUsername(err.Error()),
|
|
}
|
|
}
|
|
} else {
|
|
bindDn := strings.ReplaceAll(l.config.UserBindDn, "{username}", username)
|
|
err = conn.Bind(bindDn, password)
|
|
if err != nil {
|
|
return false, &util.JSONResponse{
|
|
Code: http.StatusUnauthorized,
|
|
JSON: jsonerror.InvalidUsername(err.Error()),
|
|
}
|
|
}
|
|
}
|
|
|
|
isAdmin, err := l.isLdapAdmin(conn, username)
|
|
if err != nil {
|
|
return false, &util.JSONResponse{
|
|
Code: http.StatusUnauthorized,
|
|
JSON: jsonerror.InvalidUsername(err.Error()),
|
|
}
|
|
}
|
|
return isAdmin, nil
|
|
}
|
|
|
|
func (l *LdapAuthenticator) isLdapAdmin(conn *ldap.Conn, username string) (bool, error) {
|
|
searchRequest := ldap.NewSearchRequest(
|
|
l.config.AdminGroupDn,
|
|
ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, 0, false,
|
|
strings.ReplaceAll(l.config.AdminGroupFilter, "{username}", username),
|
|
[]string{l.config.AdminGroupAttribute},
|
|
nil)
|
|
|
|
sr, err := conn.Search(searchRequest)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
if len(sr.Entries) < 1 {
|
|
return false, nil
|
|
}
|
|
return true, nil
|
|
}
|