mirror of
https://github.com/casdoor/casdoor.git
synced 2025-05-23 02:35:49 +08:00
feat: revert PR: "feat: more RFC like LDAP server behaviour" (#2611)
This commit is contained in:
parent
1161310f81
commit
d92b072ed0
149
ldap/server.go
149
ldap/server.go
@ -18,7 +18,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"hash/fnv"
|
"hash/fnv"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/conf"
|
"github.com/casdoor/casdoor/conf"
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
@ -50,17 +49,7 @@ func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
|
|||||||
res := ldap.NewBindResponse(ldap.LDAPResultSuccess)
|
res := ldap.NewBindResponse(ldap.LDAPResultSuccess)
|
||||||
|
|
||||||
if r.AuthenticationChoice() == "simple" {
|
if r.AuthenticationChoice() == "simple" {
|
||||||
bindDN := string(r.Name())
|
bindUsername, bindOrg, err := getNameAndOrgFromDN(string(r.Name()))
|
||||||
bindPassword := string(r.AuthenticationSimple())
|
|
||||||
|
|
||||||
if bindDN == "" && bindPassword == "" {
|
|
||||||
res.SetResultCode(ldap.LDAPResultInappropriateAuthentication)
|
|
||||||
res.SetDiagnosticMessage("Anonymous bind disallowed")
|
|
||||||
w.Write(res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
bindUsername, bindOrg, err := getNameAndOrgFromDN(bindDN)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("getNameAndOrgFromDN() error: %s", err.Error())
|
log.Printf("getNameAndOrgFromDN() error: %s", err.Error())
|
||||||
res.SetResultCode(ldap.LDAPResultInvalidDNSyntax)
|
res.SetResultCode(ldap.LDAPResultInvalidDNSyntax)
|
||||||
@ -69,6 +58,7 @@ func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bindPassword := string(r.AuthenticationSimple())
|
||||||
bindUser, err := object.CheckUserPassword(bindOrg, bindUsername, bindPassword, "en")
|
bindUser, err := object.CheckUserPassword(bindOrg, bindUsername, bindPassword, "en")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("Bind failed User=%s, Pass=%#v, ErrMsg=%s", string(r.Name()), r.Authentication(), err)
|
log.Printf("Bind failed User=%s, Pass=%#v, ErrMsg=%s", string(r.Name()), r.Authentication(), err)
|
||||||
@ -103,46 +93,7 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
r := m.GetSearchRequest()
|
r := m.GetSearchRequest()
|
||||||
|
if r.FilterString() == "(objectClass=*)" {
|
||||||
// case insensitive match
|
|
||||||
if strings.EqualFold(r.FilterString(), "(objectClass=*)") {
|
|
||||||
if len(r.Attributes()) == 0 {
|
|
||||||
w.Write(res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
first_attr := string(r.Attributes()[0])
|
|
||||||
|
|
||||||
if string(r.BaseObject()) == "" {
|
|
||||||
// handle special search requests
|
|
||||||
|
|
||||||
if first_attr == "namingContexts" {
|
|
||||||
orgs, code := GetFilteredOrganizations(m)
|
|
||||||
if code != ldap.LDAPResultSuccess {
|
|
||||||
res.SetResultCode(code)
|
|
||||||
w.Write(res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
e := ldap.NewSearchResultEntry(string(r.BaseObject()))
|
|
||||||
dnlist := make([]message.AttributeValue, len(orgs))
|
|
||||||
for i, org := range orgs {
|
|
||||||
dnlist[i] = message.AttributeValue(fmt.Sprintf("ou=%s", org.Name))
|
|
||||||
}
|
|
||||||
e.AddAttribute("namingContexts", dnlist...)
|
|
||||||
w.Write(e)
|
|
||||||
} else if first_attr == "subschemaSubentry" {
|
|
||||||
e := ldap.NewSearchResultEntry(string(r.BaseObject()))
|
|
||||||
e.AddAttribute("subschemaSubentry", message.AttributeValue("cn=Subschema"))
|
|
||||||
w.Write(e)
|
|
||||||
}
|
|
||||||
} else if strings.EqualFold(first_attr, "objectclasses") && string(r.BaseObject()) == "cn=Subschema" {
|
|
||||||
e := ldap.NewSearchResultEntry(string(r.BaseObject()))
|
|
||||||
e.AddAttribute("objectClasses", []message.AttributeValue{
|
|
||||||
"( 1.3.6.1.1.1.2.0 NAME 'posixAccount' DESC 'Abstraction of an account with POSIX attributes' SUP top AUXILIARY MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ gecos $ description ) )",
|
|
||||||
"( 1.3.6.1.1.1.2.2 NAME 'posixGroup' DESC 'Abstraction of a group of accounts' SUP top STRUCTURAL MUST ( cn $ gidNumber ) MAY ( userPassword $ memberUid $ description ) )",
|
|
||||||
}...)
|
|
||||||
w.Write(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
w.Write(res)
|
w.Write(res)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -155,72 +106,38 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
objectClass := searchFilterForEquality(r.Filter(), "objectClass", "posixAccount", "posixGroup")
|
users, code := GetFilteredUsers(m)
|
||||||
switch objectClass {
|
if code != ldap.LDAPResultSuccess {
|
||||||
case "posixAccount":
|
res.SetResultCode(code)
|
||||||
users, code := GetFilteredUsers(m)
|
w.Write(res)
|
||||||
if code != ldap.LDAPResultSuccess {
|
return
|
||||||
res.SetResultCode(code)
|
|
||||||
w.Write(res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// log.Printf("Handling posixAccount filter=%s", r.FilterString())
|
|
||||||
for _, user := range users {
|
|
||||||
dn := fmt.Sprintf("uid=%s,cn=users,%s", user.Name, string(r.BaseObject()))
|
|
||||||
e := ldap.NewSearchResultEntry(dn)
|
|
||||||
attrs := r.Attributes()
|
|
||||||
for _, attr := range attrs {
|
|
||||||
if string(attr) == "*" {
|
|
||||||
attrs = AdditionalLdapUserAttributes
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, attr := range attrs {
|
|
||||||
if strings.HasSuffix(string(attr), ";binary") {
|
|
||||||
// unsupported: userCertificate;binary
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
field, ok := ldapUserAttributesMapping.CaseInsensitiveGet(string(attr))
|
|
||||||
if ok {
|
|
||||||
e.AddAttribute(message.AttributeDescription(attr), field.GetAttributeValues(user)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.Write(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
case "posixGroup":
|
|
||||||
// log.Printf("Handling posixGroup filter=%s", r.FilterString())
|
|
||||||
groups, code := GetFilteredGroups(m)
|
|
||||||
if code != ldap.LDAPResultSuccess {
|
|
||||||
res.SetResultCode(code)
|
|
||||||
w.Write(res)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, group := range groups {
|
|
||||||
dn := fmt.Sprintf("cn=%s,cn=groups,%s", group.Name, string(r.BaseObject()))
|
|
||||||
e := ldap.NewSearchResultEntry(dn)
|
|
||||||
attrs := r.Attributes()
|
|
||||||
for _, attr := range attrs {
|
|
||||||
if string(attr) == "*" {
|
|
||||||
attrs = AdditionalLdapGroupAttributes
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, attr := range attrs {
|
|
||||||
field, ok := ldapGroupAttributesMapping.CaseInsensitiveGet(string(attr))
|
|
||||||
if ok {
|
|
||||||
e.AddAttribute(message.AttributeDescription(attr), field.GetAttributeValues(group)...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.Write(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
case "":
|
|
||||||
log.Printf("Unmatched search request. filter=%s", r.FilterString())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, user := range users {
|
||||||
|
dn := fmt.Sprintf("uid=%s,cn=%s,%s", user.Id, user.Name, string(r.BaseObject()))
|
||||||
|
e := ldap.NewSearchResultEntry(dn)
|
||||||
|
uidNumberStr := fmt.Sprintf("%v", hash(user.Name))
|
||||||
|
e.AddAttribute("uidNumber", message.AttributeValue(uidNumberStr))
|
||||||
|
e.AddAttribute("gidNumber", message.AttributeValue(uidNumberStr))
|
||||||
|
e.AddAttribute("homeDirectory", message.AttributeValue("/home/"+user.Name))
|
||||||
|
e.AddAttribute("cn", message.AttributeValue(user.Name))
|
||||||
|
e.AddAttribute("uid", message.AttributeValue(user.Id))
|
||||||
|
attrs := r.Attributes()
|
||||||
|
for _, attr := range attrs {
|
||||||
|
if string(attr) == "*" {
|
||||||
|
attrs = AdditionalLdapAttributes
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, attr := range attrs {
|
||||||
|
e.AddAttribute(message.AttributeDescription(attr), getAttribute(string(attr), user))
|
||||||
|
if string(attr) == "cn" {
|
||||||
|
e.AddAttribute(message.AttributeDescription(attr), getAttribute("title", user))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
w.Write(e)
|
||||||
|
}
|
||||||
w.Write(res)
|
w.Write(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
342
ldap/util.go
342
ldap/util.go
@ -18,7 +18,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/casdoor/casdoor/object"
|
"github.com/casdoor/casdoor/object"
|
||||||
"github.com/casdoor/casdoor/util"
|
"github.com/casdoor/casdoor/util"
|
||||||
@ -29,259 +28,65 @@ import (
|
|||||||
"github.com/xorm-io/builder"
|
"github.com/xorm-io/builder"
|
||||||
)
|
)
|
||||||
|
|
||||||
type V = message.AttributeValue
|
type AttributeMapper func(user *object.User) message.AttributeValue
|
||||||
|
|
||||||
type UserAttributeMapper func(user *object.User) []V
|
type FieldRelation struct {
|
||||||
|
|
||||||
type UserFieldRelation struct {
|
|
||||||
userField string
|
userField string
|
||||||
ldapField string
|
|
||||||
notSearchable bool
|
notSearchable bool
|
||||||
hideOnStarOp bool
|
hideOnStarOp bool
|
||||||
fieldMapper UserAttributeMapper
|
fieldMapper AttributeMapper
|
||||||
constantValue []V
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rel UserFieldRelation) GetField() (string, error) {
|
func (rel FieldRelation) GetField() (string, error) {
|
||||||
if rel.notSearchable {
|
if rel.notSearchable {
|
||||||
return "", fmt.Errorf("attribute %s not supported", rel.userField)
|
return "", fmt.Errorf("attribute %s not supported", rel.userField)
|
||||||
}
|
}
|
||||||
return rel.userField, nil
|
return rel.userField, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rel UserFieldRelation) GetAttributeValues(user *object.User) []V {
|
func (rel FieldRelation) GetAttributeValue(user *object.User) message.AttributeValue {
|
||||||
if rel.constantValue != nil && rel.fieldMapper == nil {
|
|
||||||
return rel.constantValue
|
|
||||||
}
|
|
||||||
return rel.fieldMapper(user)
|
return rel.fieldMapper(user)
|
||||||
}
|
}
|
||||||
|
|
||||||
type UserFieldRelationMap map[string]UserFieldRelation
|
var ldapAttributesMapping = map[string]FieldRelation{
|
||||||
|
"cn": {userField: "name", hideOnStarOp: true, fieldMapper: func(user *object.User) message.AttributeValue {
|
||||||
func (m UserFieldRelationMap) CaseInsensitiveGet(key string) (UserFieldRelation, bool) {
|
return message.AttributeValue(user.Name)
|
||||||
lowerKey := strings.ToLower(key)
|
|
||||||
ret, ok := m[lowerKey]
|
|
||||||
return ret, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
type GroupAttributeMapper func(group *object.Group) []V
|
|
||||||
|
|
||||||
type GroupFieldRelation struct {
|
|
||||||
groupField string
|
|
||||||
ldapField string
|
|
||||||
notSearchable bool
|
|
||||||
hideOnStarOp bool
|
|
||||||
fieldMapper GroupAttributeMapper
|
|
||||||
constantValue []V
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rel GroupFieldRelation) GetField() (string, error) {
|
|
||||||
if rel.notSearchable {
|
|
||||||
return "", fmt.Errorf("attribute %s not supported", rel.groupField)
|
|
||||||
}
|
|
||||||
return rel.groupField, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rel GroupFieldRelation) GetAttributeValues(group *object.Group) []V {
|
|
||||||
if rel.constantValue != nil && rel.fieldMapper == nil {
|
|
||||||
return rel.constantValue
|
|
||||||
}
|
|
||||||
return rel.fieldMapper(group)
|
|
||||||
}
|
|
||||||
|
|
||||||
type GroupFieldRelationMap map[string]GroupFieldRelation
|
|
||||||
|
|
||||||
func (m GroupFieldRelationMap) CaseInsensitiveGet(key string) (GroupFieldRelation, bool) {
|
|
||||||
lowerKey := strings.ToLower(key)
|
|
||||||
ret, ok := m[lowerKey]
|
|
||||||
return ret, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
var ldapUserAttributesMapping = UserFieldRelationMap{
|
|
||||||
"cn": {ldapField: "cn", userField: "name", hideOnStarOp: true, fieldMapper: func(user *object.User) []V {
|
|
||||||
return []V{V(user.Name)}
|
|
||||||
}},
|
}},
|
||||||
"uid": {ldapField: "uid", userField: "name", hideOnStarOp: true, fieldMapper: func(user *object.User) []V {
|
"uid": {userField: "name", hideOnStarOp: true, fieldMapper: func(user *object.User) message.AttributeValue {
|
||||||
return []V{V(user.Name)}
|
return message.AttributeValue(user.Name)
|
||||||
}},
|
}},
|
||||||
"displayname": {ldapField: "displayName", userField: "displayName", fieldMapper: func(user *object.User) []V {
|
"displayname": {userField: "displayName", fieldMapper: func(user *object.User) message.AttributeValue {
|
||||||
return []V{V(user.DisplayName)}
|
return message.AttributeValue(user.DisplayName)
|
||||||
}},
|
}},
|
||||||
"email": {ldapField: "email", userField: "email", fieldMapper: func(user *object.User) []V {
|
"email": {userField: "email", fieldMapper: func(user *object.User) message.AttributeValue {
|
||||||
return []V{V(user.Email)}
|
return message.AttributeValue(user.Email)
|
||||||
}},
|
}},
|
||||||
"mail": {ldapField: "mail", userField: "email", fieldMapper: func(user *object.User) []V {
|
"mail": {userField: "email", fieldMapper: func(user *object.User) message.AttributeValue {
|
||||||
return []V{V(user.Email)}
|
return message.AttributeValue(user.Email)
|
||||||
}},
|
}},
|
||||||
"mobile": {ldapField: "mobile", userField: "phone", fieldMapper: func(user *object.User) []V {
|
"mobile": {userField: "phone", fieldMapper: func(user *object.User) message.AttributeValue {
|
||||||
return []V{V(user.Phone)}
|
return message.AttributeValue(user.Phone)
|
||||||
}},
|
}},
|
||||||
"telephonenumber": {ldapField: "telephoneNumber", userField: "phone", fieldMapper: func(user *object.User) []V {
|
"title": {userField: "tag", fieldMapper: func(user *object.User) message.AttributeValue {
|
||||||
return []V{V(user.Phone)}
|
return message.AttributeValue(user.Tag)
|
||||||
}},
|
}},
|
||||||
"postaladdress": {ldapField: "postalAddress", userField: "address", fieldMapper: func(user *object.User) []V {
|
"userPassword": {
|
||||||
return []V{V(strings.Join(user.Address, " "))}
|
|
||||||
}},
|
|
||||||
"title": {ldapField: "title", userField: "title", fieldMapper: func(user *object.User) []V {
|
|
||||||
return []V{V(user.Title)}
|
|
||||||
}},
|
|
||||||
"gecos": {ldapField: "gecos", userField: "displayName", fieldMapper: func(user *object.User) []V {
|
|
||||||
return []V{V(user.DisplayName)}
|
|
||||||
}},
|
|
||||||
"description": {ldapField: "description", userField: "displayName", fieldMapper: func(user *object.User) []V {
|
|
||||||
return []V{V(user.DisplayName)}
|
|
||||||
}},
|
|
||||||
"logindisabled": {ldapField: "loginDisabled", userField: "isForbidden", fieldMapper: func(user *object.User) []V {
|
|
||||||
if user.IsForbidden {
|
|
||||||
return []V{V("1")}
|
|
||||||
} else {
|
|
||||||
return []V{V("0")}
|
|
||||||
}
|
|
||||||
}},
|
|
||||||
"userpassword": {
|
|
||||||
ldapField: "userPassword",
|
|
||||||
userField: "userPassword",
|
userField: "userPassword",
|
||||||
notSearchable: true,
|
notSearchable: true,
|
||||||
fieldMapper: func(user *object.User) []V {
|
fieldMapper: func(user *object.User) message.AttributeValue {
|
||||||
return []V{V(getUserPasswordWithType(user))}
|
return message.AttributeValue(getUserPasswordWithType(user))
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"uidnumber": {ldapField: "uidNumber", notSearchable: true, fieldMapper: func(user *object.User) []V {
|
|
||||||
return []V{V(fmt.Sprintf("%v", hash(user.Name)))}
|
|
||||||
}},
|
|
||||||
"gidnumber": {ldapField: "gidNumber", notSearchable: true, fieldMapper: func(user *object.User) []V {
|
|
||||||
if len(user.Groups) == 0 {
|
|
||||||
return []V{V("")}
|
|
||||||
}
|
|
||||||
group, err := object.GetGroup(user.Groups[0])
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("gidnumber object.GetGroup error: %s", err)
|
|
||||||
return []V{V("")}
|
|
||||||
}
|
|
||||||
return []V{V(fmt.Sprintf("%v", hash(group.Name)))}
|
|
||||||
}},
|
|
||||||
"homedirectory": {ldapField: "homeDirectory", notSearchable: true, fieldMapper: func(user *object.User) []V {
|
|
||||||
return []V{V("/home/" + user.Name)}
|
|
||||||
}},
|
|
||||||
"loginshell": {ldapField: "loginShell", notSearchable: true, fieldMapper: func(user *object.User) []V {
|
|
||||||
if user.IsForbidden || user.IsDeleted {
|
|
||||||
return []V{V("/sbin/nologin")}
|
|
||||||
} else {
|
|
||||||
return []V{V("/bin/bash")}
|
|
||||||
}
|
|
||||||
}},
|
|
||||||
"shadowlastchange": {ldapField: "shadowLastChange", notSearchable: true, fieldMapper: func(user *object.User) []V {
|
|
||||||
// "this attribute specifies number of days between January 1, 1970, and the date that the password was last modified"
|
|
||||||
updatedTime, err := time.Parse(time.RFC3339, user.UpdatedTime)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("shadowlastchange time.Parse error: %s", err)
|
|
||||||
updatedTime = time.Now()
|
|
||||||
}
|
|
||||||
return []V{V(fmt.Sprint(updatedTime.Unix() / 86400))}
|
|
||||||
}},
|
|
||||||
"pwdchangedtime": {ldapField: "pwdChangedTime", notSearchable: true, fieldMapper: func(user *object.User) []V {
|
|
||||||
updatedTime, err := time.Parse(time.RFC3339, user.UpdatedTime)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("pwdchangedtime time.Parse error: %s", err)
|
|
||||||
updatedTime = time.Now()
|
|
||||||
}
|
|
||||||
return []V{V(updatedTime.UTC().Format("20060102030405Z"))}
|
|
||||||
}},
|
|
||||||
"shadowmin": {ldapField: "shadowMin", notSearchable: true, constantValue: []V{V("0")}},
|
|
||||||
"shadowmax": {ldapField: "shadowMax", notSearchable: true, constantValue: []V{V("99999")}},
|
|
||||||
"shadowwarning": {ldapField: "shadowWarning", notSearchable: true, constantValue: []V{V("7")}},
|
|
||||||
"shadowexpire": {ldapField: "shadowExpire", notSearchable: true, fieldMapper: func(user *object.User) []V {
|
|
||||||
if user.IsForbidden {
|
|
||||||
return []V{V("1")}
|
|
||||||
} else {
|
|
||||||
return []V{V("-1")}
|
|
||||||
}
|
|
||||||
}},
|
|
||||||
"shadowinactive": {ldapField: "shadowInactive", notSearchable: true, constantValue: []V{V("0")}},
|
|
||||||
"shadowflag": {ldapField: "shadowFlag", notSearchable: true, constantValue: []V{V("0")}},
|
|
||||||
"memberof": {ldapField: "memberOf", notSearchable: true, fieldMapper: func(user *object.User) []V {
|
|
||||||
var groupdn []V
|
|
||||||
for _, groupId := range user.Groups {
|
|
||||||
group, err := object.GetGroup(groupId)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("memberOf object.GetGroup error: %s", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
groupdn = append(groupdn, V(fmt.Sprintf("cn=%s,cn=groups,ou=%s", group.Name, group.Owner)))
|
|
||||||
}
|
|
||||||
return groupdn
|
|
||||||
}},
|
|
||||||
"objectclass": {ldapField: "objectClass", notSearchable: true, constantValue: []V{
|
|
||||||
V("top"),
|
|
||||||
V("posixAccount"),
|
|
||||||
V("shadowAccount"),
|
|
||||||
V("person"),
|
|
||||||
V("organizationalPerson"),
|
|
||||||
V("inetOrgPerson"),
|
|
||||||
V("apple-user"),
|
|
||||||
V("sambaSamAccount"),
|
|
||||||
V("sambaIdmapEntry"),
|
|
||||||
V("extensibleObject"),
|
|
||||||
}},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var ldapGroupAttributesMapping = GroupFieldRelationMap{
|
var AdditionalLdapAttributes []message.LDAPString
|
||||||
"cn": {ldapField: "cn", hideOnStarOp: true, fieldMapper: func(group *object.Group) []V {
|
|
||||||
return []V{V(group.Name)}
|
|
||||||
}},
|
|
||||||
"gidnumber": {ldapField: "gidNumber", hideOnStarOp: true, fieldMapper: func(group *object.Group) []V {
|
|
||||||
return []V{V(fmt.Sprintf("%v", hash(group.Name)))}
|
|
||||||
}},
|
|
||||||
"member": {ldapField: "member", fieldMapper: func(group *object.Group) []V {
|
|
||||||
users, err := object.GetGroupUsers(group.GetId())
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("member object.GetGroupUsers error: %s", err)
|
|
||||||
return []V{V("")}
|
|
||||||
}
|
|
||||||
var members []V
|
|
||||||
for _, user := range users {
|
|
||||||
members = append(members, V(fmt.Sprintf("uid=%s,cn=users,ou=%s", user.Name, user.Owner)))
|
|
||||||
}
|
|
||||||
return members
|
|
||||||
}},
|
|
||||||
"memberuid": {ldapField: "memberUid", fieldMapper: func(group *object.Group) []V {
|
|
||||||
users, err := object.GetGroupUsers(group.GetId())
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("member object.GetGroupUsers error: %s", err)
|
|
||||||
return []V{V("")}
|
|
||||||
}
|
|
||||||
var members []message.AttributeValue
|
|
||||||
for _, user := range users {
|
|
||||||
members = append(members, message.AttributeValue(user.Name))
|
|
||||||
}
|
|
||||||
return members
|
|
||||||
}},
|
|
||||||
"description": {ldapField: "description", hideOnStarOp: true, fieldMapper: func(group *object.Group) []V {
|
|
||||||
return []V{V(group.DisplayName)}
|
|
||||||
}},
|
|
||||||
"objectclass": {ldapField: "objectClass", hideOnStarOp: true, constantValue: []V{
|
|
||||||
V("top"),
|
|
||||||
V("posixGroup"),
|
|
||||||
}},
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
AdditionalLdapUserAttributes []message.LDAPString
|
|
||||||
AdditionalLdapGroupAttributes []message.LDAPString
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
for _, v := range ldapUserAttributesMapping {
|
for k, v := range ldapAttributesMapping {
|
||||||
if v.hideOnStarOp {
|
if v.hideOnStarOp {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
AdditionalLdapUserAttributes = append(AdditionalLdapUserAttributes, message.LDAPString(v.ldapField))
|
AdditionalLdapAttributes = append(AdditionalLdapAttributes, message.LDAPString(k))
|
||||||
}
|
|
||||||
for _, v := range ldapGroupAttributesMapping {
|
|
||||||
if v.hideOnStarOp {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
AdditionalLdapGroupAttributes = append(AdditionalLdapGroupAttributes, message.LDAPString(v.ldapField))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -502,52 +307,6 @@ func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetFilteredOrganizations(m *ldap.Message) ([]*object.Organization, int) {
|
|
||||||
if m.Client.IsGlobalAdmin {
|
|
||||||
organizations, err := object.GetOrganizations("")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return organizations, ldap.LDAPResultSuccess
|
|
||||||
} else if m.Client.IsOrgAdmin {
|
|
||||||
requestUserId := util.GetId(m.Client.OrgName, m.Client.UserName)
|
|
||||||
user, err := object.GetUser(requestUserId)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
organization, err := object.GetOrganizationByUser(user)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return []*object.Organization{organization}, ldap.LDAPResultSuccess
|
|
||||||
} else {
|
|
||||||
return nil, ldap.LDAPResultInsufficientAccessRights
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetFilteredGroups(m *ldap.Message) ([]*object.Group, int) {
|
|
||||||
if m.Client.IsGlobalAdmin {
|
|
||||||
groups, err := object.GetGroups("")
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return groups, ldap.LDAPResultSuccess
|
|
||||||
} else if m.Client.IsOrgAdmin {
|
|
||||||
requestUserId := util.GetId(m.Client.OrgName, m.Client.UserName)
|
|
||||||
user, err := object.GetUser(requestUserId)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
groups, err := object.GetGroups(user.Owner)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return groups, ldap.LDAPResultSuccess
|
|
||||||
} else {
|
|
||||||
return nil, ldap.LDAPResultInsufficientAccessRights
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get user password with hash type prefix
|
// get user password with hash type prefix
|
||||||
// TODO not handle salt yet
|
// TODO not handle salt yet
|
||||||
// @return {md5}5f4dcc3b5aa765d61d8327deb882cf99
|
// @return {md5}5f4dcc3b5aa765d61d8327deb882cf99
|
||||||
@ -571,49 +330,18 @@ func getUserPasswordWithType(user *object.User) string {
|
|||||||
return fmt.Sprintf("{%s}%s", prefix, user.Password)
|
return fmt.Sprintf("{%s}%s", prefix, user.Password)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getAttribute(attributeName string, user *object.User) message.AttributeValue {
|
||||||
|
v, ok := ldapAttributesMapping[attributeName]
|
||||||
|
if !ok {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return v.GetAttributeValue(user)
|
||||||
|
}
|
||||||
|
|
||||||
func getUserFieldFromAttribute(attributeName string) (string, error) {
|
func getUserFieldFromAttribute(attributeName string) (string, error) {
|
||||||
v, ok := ldapUserAttributesMapping.CaseInsensitiveGet(attributeName)
|
v, ok := ldapAttributesMapping[attributeName]
|
||||||
if !ok {
|
if !ok {
|
||||||
return "", fmt.Errorf("attribute %s not supported", attributeName)
|
return "", fmt.Errorf("attribute %s not supported", attributeName)
|
||||||
}
|
}
|
||||||
return v.GetField()
|
return v.GetField()
|
||||||
}
|
}
|
||||||
|
|
||||||
func searchFilterForEquality(filter message.Filter, desc string, values ...string) string {
|
|
||||||
switch f := filter.(type) {
|
|
||||||
case message.FilterAnd:
|
|
||||||
for _, child := range f {
|
|
||||||
if val := searchFilterForEquality(child, desc, values...); val != "" {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case message.FilterOr:
|
|
||||||
for _, child := range f {
|
|
||||||
if val := searchFilterForEquality(child, desc, values...); val != "" {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case message.FilterNot:
|
|
||||||
return searchFilterForEquality(f.Filter, desc, values...)
|
|
||||||
case message.FilterSubstrings:
|
|
||||||
// Handle FilterSubstrings case if needed
|
|
||||||
case message.FilterEqualityMatch:
|
|
||||||
if strings.EqualFold(string(f.AttributeDesc()), desc) {
|
|
||||||
for _, value := range values {
|
|
||||||
if val := string(f.AssertionValue()); val == value {
|
|
||||||
return val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case message.FilterGreaterOrEqual:
|
|
||||||
// Handle FilterGreaterOrEqual case if needed
|
|
||||||
case message.FilterLessOrEqual:
|
|
||||||
// Handle FilterLessOrEqual case if needed
|
|
||||||
case message.FilterPresent:
|
|
||||||
// Handle FilterPresent case if needed
|
|
||||||
case message.FilterApproxMatch:
|
|
||||||
// Handle FilterApproxMatch case if needed
|
|
||||||
}
|
|
||||||
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user