From 600e88e82f84266697e46174285f205217a999fc Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Thu, 30 Mar 2023 11:43:03 +0200 Subject: [PATCH] graph: Allow using binary LDAP UUIDs as user ids In Active Directories UUID attributes such as "objectGUID" use a binary syntax (oposed to the standard UUID syntax defined in RFC4530). This introduces a flag to enable support for binary UUIDs as the id for users and groups (similar to what the "users" and "groups" services already support) Fixes: #5815 --- services/graph/pkg/config/config.go | 16 ++-- services/graph/pkg/identity/ldap.go | 92 +++++++++++++++---- .../pkg/identity/ldap_education_class.go | 7 +- .../graph/pkg/identity/ldap_education_user.go | 7 +- services/graph/pkg/identity/ldap_group.go | 23 ++++- 5 files changed, 112 insertions(+), 33 deletions(-) diff --git a/services/graph/pkg/config/config.go b/services/graph/pkg/config/config.go index 406e3a77773..8d1e4f30bdc 100644 --- a/services/graph/pkg/config/config.go +++ b/services/graph/pkg/config/config.go @@ -64,18 +64,20 @@ type LDAP struct { UserDisplayNameAttribute string `yaml:"user_displayname_attribute" env:"LDAP_USER_SCHEMA_DISPLAY_NAME;GRAPH_LDAP_USER_DISPLAYNAME_ATTRIBUTE" desc:"LDAP Attribute to use for the displayname of users."` UserNameAttribute string `yaml:"user_name_attribute" env:"OCIS_LDAP_USER_SCHEMA_USERNAME;LDAP_USER_SCHEMA_USERNAME;GRAPH_LDAP_USER_NAME_ATTRIBUTE" desc:"LDAP Attribute to use for username of users." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_USER_SCHEMA_USERNAME changing name for consistency" deprecationReplacement:"OCIS_LDAP_USER_SCHEMA_USERNAME"` UserIDAttribute string `yaml:"user_id_attribute" env:"OCIS_LDAP_USER_SCHEMA_ID;LDAP_USER_SCHEMA_ID;GRAPH_LDAP_USER_UID_ATTRIBUTE" desc:"LDAP Attribute to use as the unique ID for users. This should be a stable globally unique ID like a UUID." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_USER_SCHEMA_ID changing name for consistency" deprecationReplacement:"OCIS_LDAP_USER_SCHEMA_ID"` + UserIDIsOctetString bool `yaml:"user_id_is_octet_string" env:"OCIS_LDAP_USER_SCHEMA_ID_IS_OCTETSTRING;GRAPH_LDAP_USER_SCHEMA_ID_IS_OCTETSTRING" desc:"Set this to true if the defined 'ID' attribute for users is of the 'OCTETSTRING' syntax. This is required when using the 'objectGUID' attribute of Active Directory for the user ID's."` UserTypeAttribute string `yaml:"user_type_attribute" env:"OCIS_LDAP_USER_SCHEMA_USER_TYPE;LDAP_USER_SCHEMA_USER_TYPE;GRAPH_LDAP_USER_TYPE_ATTRIBUTE" desc:"LDAP Attribute to distinguish between 'Member' and 'Guest' users. Default is 'ownCloudUserType'." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_USER_SCHEMA_USER_TYPE changing name for consistency" deprecationReplacement:"OCIS_LDAP_USER_SCHEMA_USER_TYPE"` UserEnabledAttribute string `yaml:"user_enabled_attribute" env:"OCIS_LDAP_USER_ENABLED_ATTRIBUTE;LDAP_USER_ENABLED_ATTRIBUTE;GRAPH_USER_ENABLED_ATTRIBUTE" desc:"LDAP Attribute to use as a flag telling if the user is enabled or disabled." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_USER_ENABLED_ATTRIBUTE changing name for consistency" deprecationReplacement:"OCIS_LDAP_USER_ENABLED_ATTRIBUTE"` DisableUserMechanism string `yaml:"disable_user_mechanism" env:"OCIS_LDAP_DISABLE_USER_MECHANISM;LDAP_DISABLE_USER_MECHANISM;GRAPH_DISABLE_USER_MECHANISM" desc:"An option to control the behavior for disabling users. Supported options are 'none', 'attribute' and 'group'. If set to 'group', disabling a user via API will add the user to the configured group for disabled users, if set to 'attribute' this will be done in the ldap user entry, if set to 'none' the disable request is not processed. Default is 'attribute'." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_DISABLE_USER_MECHANISM changing name for consistency" deprecationReplacement:"OCIS_LDAP_DISABLE_USER_MECHANISM"` LdapDisabledUsersGroupDN string `yaml:"ldap_disabled_users_group_dn" env:"OCIS_LDAP_DISABLED_USERS_GROUP_DN;LDAP_DISABLED_USERS_GROUP_DN;GRAPH_DISABLED_USERS_GROUP_DN" desc:"The distinguished name of the group to which added users will be classified as disabled when 'disable_user_mechanism' is set to 'group'." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_DISABLED_USERS_GROUP_DN changing name for consistency" deprecationReplacement:"OCIS_LDAP_DISABLED_USERS_GROUP_DN"` - GroupBaseDN string `yaml:"group_base_dn" env:"OCIS_LDAP_GROUP_BASE_DN;LDAP_GROUP_BASE_DN;GRAPH_LDAP_GROUP_BASE_DN" desc:"Search base DN for looking up LDAP groups." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_GROUP_BASE_DN changing name for consistency" deprecationReplacement:"OCIS_LDAP_GROUP_BASE_DN"` - GroupCreateBaseDN string `yaml:"group_create_base_dn" env:"GRAPH_LDAP_GROUP_CREATE_BASE_DN" desc:"Parent DN under which new groups are created. This DN needs to be subordinate to the 'GRAPH_LDAP_GROUP_BASE_DN'. This setting is only relevant when 'GRAPH_LDAP_SERVER_WRITE_ENABLED' is 'true'. It defaults to the value of 'GRAPH_LDAP_GROUP_BASE_DN'. All groups outside of this subtree are treated as readonly groups and cannot be updated."` - GroupSearchScope string `yaml:"group_search_scope" env:"OCIS_LDAP_GROUP_SCOPE;LDAP_GROUP_SCOPE;GRAPH_LDAP_GROUP_SEARCH_SCOPE" desc:"LDAP search scope to use when looking up groups. Supported scopes are 'base', 'one' and 'sub'." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_GROUP_SCOPE changing name for consistency" deprecationReplacement:"OCIS_LDAP_GROUP_SCOPE"` - GroupFilter string `yaml:"group_filter" env:"OCIS_LDAP_GROUP_FILTER;LDAP_GROUP_FILTER;GRAPH_LDAP_GROUP_FILTER" desc:"LDAP filter to add to the default filters for group searches." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_GROUP_FILTER changing name for consistency" deprecationReplacement:"OCIS_LDAP_GROUP_FILTER"` - GroupObjectClass string `yaml:"group_objectclass" env:"OCIS_LDAP_GROUP_OBJECTCLASS;LDAP_GROUP_OBJECTCLASS;GRAPH_LDAP_GROUP_OBJECTCLASS" desc:"The object class to use for groups in the default group search filter ('groupOfNames')." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_GROUP_OBJECTCLASS changing name for consistency" deprecationReplacement:"OCIS_LDAP_GROUP_OBJECTCLASS"` - GroupNameAttribute string `yaml:"group_name_attribute" env:"OCIS_LDAP_GROUP_SCHEMA_GROUPNAME;LDAP_GROUP_SCHEMA_GROUPNAME;GRAPH_LDAP_GROUP_NAME_ATTRIBUTE" desc:"LDAP Attribute to use for the name of groups." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_GROUP_SCHEMA_GROUPNAME changing name for consistency" deprecationReplacement:"OCIS_LDAP_GROUP_SCHEMA_GROUPNAME"` - GroupIDAttribute string `yaml:"group_id_attribute" env:"OCIS_LDAP_GROUP_SCHEMA_ID;LDAP_GROUP_SCHEMA_ID;GRAPH_LDAP_GROUP_ID_ATTRIBUTE" desc:"LDAP Attribute to use as the unique id for groups. This should be a stable globally unique ID like a UUID." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_GROUP_SCHEMA_ID changing name for consistency" deprecationReplacement:"OCIS_LDAP_GROUP_SCHEMA_ID"` + GroupBaseDN string `yaml:"group_base_dn" env:"OCIS_LDAP_GROUP_BASE_DN;LDAP_GROUP_BASE_DN;GRAPH_LDAP_GROUP_BASE_DN" desc:"Search base DN for looking up LDAP groups." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_GROUP_BASE_DN changing name for consistency" deprecationReplacement:"OCIS_LDAP_GROUP_BASE_DN"` + GroupCreateBaseDN string `yaml:"group_create_base_dn" env:"GRAPH_LDAP_GROUP_CREATE_BASE_DN" desc:"Parent DN under which new groups are created. This DN needs to be subordinate to the 'GRAPH_LDAP_GROUP_BASE_DN'. This setting is only relevant when 'GRAPH_LDAP_SERVER_WRITE_ENABLED' is 'true'. It defaults to the value of 'GRAPH_LDAP_GROUP_BASE_DN'. All groups outside of this subtree are treated as readonly groups and cannot be updated."` + GroupSearchScope string `yaml:"group_search_scope" env:"OCIS_LDAP_GROUP_SCOPE;LDAP_GROUP_SCOPE;GRAPH_LDAP_GROUP_SEARCH_SCOPE" desc:"LDAP search scope to use when looking up groups. Supported scopes are 'base', 'one' and 'sub'." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_GROUP_SCOPE changing name for consistency" deprecationReplacement:"OCIS_LDAP_GROUP_SCOPE"` + GroupFilter string `yaml:"group_filter" env:"OCIS_LDAP_GROUP_FILTER;LDAP_GROUP_FILTER;GRAPH_LDAP_GROUP_FILTER" desc:"LDAP filter to add to the default filters for group searches." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_GROUP_FILTER changing name for consistency" deprecationReplacement:"OCIS_LDAP_GROUP_FILTER"` + GroupObjectClass string `yaml:"group_objectclass" env:"OCIS_LDAP_GROUP_OBJECTCLASS;LDAP_GROUP_OBJECTCLASS;GRAPH_LDAP_GROUP_OBJECTCLASS" desc:"The object class to use for groups in the default group search filter ('groupOfNames')." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_GROUP_OBJECTCLASS changing name for consistency" deprecationReplacement:"OCIS_LDAP_GROUP_OBJECTCLASS"` + GroupNameAttribute string `yaml:"group_name_attribute" env:"OCIS_LDAP_GROUP_SCHEMA_GROUPNAME;LDAP_GROUP_SCHEMA_GROUPNAME;GRAPH_LDAP_GROUP_NAME_ATTRIBUTE" desc:"LDAP Attribute to use for the name of groups." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_GROUP_SCHEMA_GROUPNAME changing name for consistency" deprecationReplacement:"OCIS_LDAP_GROUP_SCHEMA_GROUPNAME"` + GroupIDAttribute string `yaml:"group_id_attribute" env:"OCIS_LDAP_GROUP_SCHEMA_ID;LDAP_GROUP_SCHEMA_ID;GRAPH_LDAP_GROUP_ID_ATTRIBUTE" desc:"LDAP Attribute to use as the unique id for groups. This should be a stable globally unique ID like a UUID." deprecationVersion:"3.0" removalVersion:"4.0.0" deprecationInfo:"LDAP_GROUP_SCHEMA_ID changing name for consistency" deprecationReplacement:"OCIS_LDAP_GROUP_SCHEMA_ID"` + GroupIDIsOctetString bool `yaml:"group_id_is_octet_string" env:"OCIS_LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING;GRAPH_LDAP_GROUP_SCHEMA_ID_IS_OCTETSTRING" desc:"Set this to true if the defined 'ID' attribute for groups is of the 'OCTETSTRING' syntax. This is required when using the 'objectGUID' attribute of Active Directory for the group ID's."` EducationResourcesEnabled bool `yaml:"education_resources_enabled" env:"GRAPH_LDAP_EDUCATION_RESOURCES_ENABLED" desc:"Enable LDAP support for managing education related resources."` EducationConfig LDAPEducationConfig diff --git a/services/graph/pkg/identity/ldap.go b/services/graph/pkg/identity/ldap.go index e784c3f2ffd..750f4d4bba2 100644 --- a/services/graph/pkg/identity/ldap.go +++ b/services/graph/pkg/identity/ldap.go @@ -9,7 +9,7 @@ import ( "github.com/CiscoM31/godata" "github.com/go-ldap/ldap/v3" - "github.com/gofrs/uuid" + "github.com/google/uuid" "github.com/libregraph/idm/pkg/ldapdn" libregraph "github.com/owncloud/libre-graph-api-go" "github.com/owncloud/ocis/v2/ocis-pkg/log" @@ -48,21 +48,23 @@ type LDAP struct { refintEnabled bool usePwModifyExOp bool - userBaseDN string - userFilter string - userObjectClass string - userScope int - userAttributeMap userAttributeMap + userBaseDN string + userFilter string + userObjectClass string + userIDisOctetString bool + userScope int + userAttributeMap userAttributeMap disableUserMechanism DisableUserMechanismType localUserDisableGroupDN string - groupBaseDN string - groupCreateBaseDN string - groupFilter string - groupObjectClass string - groupScope int - groupAttributeMap groupAttributeMap + groupBaseDN string + groupCreateBaseDN string + groupFilter string + groupObjectClass string + groupIDisOctetString bool + groupScope int + groupAttributeMap groupAttributeMap educationConfig educationConfig @@ -146,12 +148,14 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD userBaseDN: config.UserBaseDN, userFilter: config.UserFilter, userObjectClass: config.UserObjectClass, + userIDisOctetString: config.UserIDIsOctetString, userScope: userScope, userAttributeMap: uam, groupBaseDN: config.GroupBaseDN, groupCreateBaseDN: config.GroupCreateBaseDN, groupFilter: config.GroupFilter, groupObjectClass: config.GroupObjectClass, + groupIDisOctetString: config.GroupIDIsOctetString, groupScope: groupScope, groupAttributeMap: gam, educationConfig: educationConfig, @@ -262,7 +266,12 @@ func (i *LDAP) UpdateUser(ctx context.Context, nameOrID string, user libregraph. // Don't allow updates of the ID if user.GetId() != "" { - if e.GetEqualFoldAttributeValue(i.userAttributeMap.id) != user.GetId() { + id, err := i.ldapUUIDtoString(e, i.userAttributeMap.id, i.userIDisOctetString) + if err != nil { + i.logger.Warn().Str("dn", e.DN).Str(i.userAttributeMap.id, e.GetAttributeValue(i.userAttributeMap.id)).Msg("Invalid User. Cannot convert UUID") + return nil, errorcode.New(errorcode.GeneralException, "error converting uuid") + } + if id != user.GetId() { return nil, errorcode.New(errorcode.NotAllowed, "changing the UserId is not allowed") } } @@ -430,15 +439,43 @@ func (i *LDAP) searchLDAPEntryByFilter(basedn string, attrs []string, filter str return res.Entries[0], nil } +func filterEscapeUUID(binary bool, id string) (string, error) { + var escaped string + if binary { + pid, err := uuid.Parse(id) + if err != nil { + err := fmt.Errorf("error parsing id '%s' as UUID: %w", id, err) + return "", err + } + for _, b := range pid { + escaped = fmt.Sprintf("%s\\%02x", escaped, b) + } + } else { + escaped = ldap.EscapeFilter(id) + } + return escaped, nil +} + func (i *LDAP) getLDAPUserByID(id string) (*ldap.Entry, error) { - id = ldap.EscapeFilter(id) - filter := fmt.Sprintf("(%s=%s)", i.userAttributeMap.id, id) + idString, err := filterEscapeUUID(i.userIDisOctetString, id) + if err != nil { + return nil, fmt.Errorf("Invalid User id: %w", err) + } + filter := fmt.Sprintf("(%s=%s)", i.userAttributeMap.id, idString) return i.getLDAPUserByFilter(filter) } func (i *LDAP) getLDAPUserByNameOrID(nameOrID string) (*ldap.Entry, error) { - nameOrID = ldap.EscapeFilter(nameOrID) - filter := fmt.Sprintf("(|(%s=%s)(%s=%s))", i.userAttributeMap.userName, nameOrID, i.userAttributeMap.id, nameOrID) + idString, err := filterEscapeUUID(i.userIDisOctetString, nameOrID) + // err != nil just means that this is not a uuid so we can skip the uuid filterpart + // and just filter by name + filter := "" + if err == nil { + filter = fmt.Sprintf("(|(%s=%s)(%s=%s))", i.userAttributeMap.userName, ldap.EscapeFilter(nameOrID), i.userAttributeMap.id, idString) + } else { + filter = fmt.Sprintf("(%s=%s)", i.userAttributeMap.userName, ldap.EscapeFilter(nameOrID)) + } + return i.getLDAPUserByFilter(filter) } @@ -451,6 +488,7 @@ func (i *LDAP) getLDAPUserByFilter(filter string) (*ldap.Entry, error) { i.userAttributeMap.userName, i.userAttributeMap.surname, i.userAttributeMap.givenName, + i.userAttributeMap.accountEnabled, i.userAttributeMap.userType, } @@ -683,13 +721,29 @@ func (i *LDAP) updateUserPassowrd(ctx context.Context, dn, password string) erro return err } +func (i *LDAP) ldapUUIDtoString(e *ldap.Entry, attrType string, binary bool) (string, error) { + if binary { + rawValue := e.GetEqualFoldRawAttributeValue(attrType) + value, err := uuid.FromBytes(rawValue) + if err == nil { + return value.String(), nil + } + return "", err + } else { + return e.GetEqualFoldAttributeValue(attrType), nil + } +} + func (i *LDAP) createUserModelFromLDAP(e *ldap.Entry) *libregraph.User { if e == nil { return nil } opsan := e.GetEqualFoldAttributeValue(i.userAttributeMap.userName) - id := e.GetEqualFoldAttributeValue(i.userAttributeMap.id) + id, err := i.ldapUUIDtoString(e, i.userAttributeMap.id, i.userIDisOctetString) + if err != nil { + i.logger.Warn().Str("dn", e.DN).Str(i.userAttributeMap.id, e.GetAttributeValue(i.userAttributeMap.id)).Msg("Invalid User. Cannot convert UUID") + } givenName := e.GetEqualFoldAttributeValue(i.userAttributeMap.givenName) surname := e.GetEqualFoldAttributeValue(i.userAttributeMap.surname) @@ -720,7 +774,7 @@ func (i *LDAP) userToLDAPAttrValues(user libregraph.User) (map[string][]string, } if !i.useServerUUID { - attrs["owncloudUUID"] = []string{uuid.Must(uuid.NewV4()).String()} + attrs["owncloudUUID"] = []string{uuid.New().String()} } if user.AccountEnabled != nil { diff --git a/services/graph/pkg/identity/ldap_education_class.go b/services/graph/pkg/identity/ldap_education_class.go index ee65eb970da..c7f657355d6 100644 --- a/services/graph/pkg/identity/ldap_education_class.go +++ b/services/graph/pkg/identity/ldap_education_class.go @@ -150,7 +150,12 @@ func (i *LDAP) UpdateEducationClass(ctx context.Context, id string, class libreg var updateNeeded bool if class.GetId() != "" { - if g.GetEqualFoldAttributeValue(i.groupAttributeMap.id) != class.GetId() { + id, err := i.ldapUUIDtoString(g, i.groupAttributeMap.id, i.groupIDisOctetString) + if err != nil { + i.logger.Warn().Str("dn", g.DN).Str(i.userAttributeMap.id, g.GetAttributeValue(i.userAttributeMap.id)).Msg("Invalid class. Cannot convert UUID") + return nil, errorcode.New(errorcode.GeneralException, "error converting uuid") + } + if id != class.GetId() { return nil, errorcode.New(errorcode.NotAllowed, "changing the GroupID is not allowed") } } diff --git a/services/graph/pkg/identity/ldap_education_user.go b/services/graph/pkg/identity/ldap_education_user.go index 9c9a8cbae7a..8755ec7e153 100644 --- a/services/graph/pkg/identity/ldap_education_user.go +++ b/services/graph/pkg/identity/ldap_education_user.go @@ -91,7 +91,12 @@ func (i *LDAP) UpdateEducationUser(ctx context.Context, nameOrID string, user li // Don't allow updates of the ID if user.GetId() != "" { - if e.GetEqualFoldAttributeValue(i.userAttributeMap.id) != user.GetId() { + id, err := i.ldapUUIDtoString(e, i.userAttributeMap.id, i.userIDisOctetString) + if err != nil { + i.logger.Warn().Str("dn", e.DN).Str(i.userAttributeMap.id, e.GetAttributeValue(i.userAttributeMap.id)).Msg("Invalid User. Cannot convert UUID") + return nil, errorcode.New(errorcode.GeneralException, "error converting uuid") + } + if id != user.GetId() { return nil, errorcode.New(errorcode.NotAllowed, "changing the UserId is not allowed") } } diff --git a/services/graph/pkg/identity/ldap_group.go b/services/graph/pkg/identity/ldap_group.go index b3a2472f9a8..67a4abe2688 100644 --- a/services/graph/pkg/identity/ldap_group.go +++ b/services/graph/pkg/identity/ldap_group.go @@ -416,14 +416,24 @@ func (i *LDAP) groupToLDAPAttrValues(group libregraph.Group) (map[string][]strin } func (i *LDAP) getLDAPGroupByID(id string, requestMembers bool) (*ldap.Entry, error) { - id = ldap.EscapeFilter(id) - filter := fmt.Sprintf("(%s=%s)", i.groupAttributeMap.id, id) + idString, err := filterEscapeUUID(i.groupIDisOctetString, id) + if err != nil { + return nil, fmt.Errorf("Invalid group id: %w", err) + } + filter := fmt.Sprintf("(%s=%s)", i.groupAttributeMap.id, idString) return i.getLDAPGroupByFilter(filter, requestMembers) } func (i *LDAP) getLDAPGroupByNameOrID(nameOrID string, requestMembers bool) (*ldap.Entry, error) { - nameOrID = ldap.EscapeFilter(nameOrID) - filter := fmt.Sprintf("(|(%s=%s)(%s=%s))", i.groupAttributeMap.name, nameOrID, i.groupAttributeMap.id, nameOrID) + idString, err := filterEscapeUUID(i.groupIDisOctetString, nameOrID) + // err != nil just means that this is not a uuid so we can skip the uuid filterpart + // and just filter by name + filter := "" + if err == nil { + filter = fmt.Sprintf("(|(%s=%s)(%s=%s))", i.groupAttributeMap.name, ldap.EscapeFilter(nameOrID), i.groupAttributeMap.id, idString) + } else { + filter = fmt.Sprintf("(%s=%s)", i.userAttributeMap.userName, ldap.EscapeFilter(nameOrID)) + } return i.getLDAPGroupByFilter(filter, requestMembers) } @@ -510,7 +520,10 @@ func (i *LDAP) getGroupsForUser(dn string) ([]*ldap.Entry, error) { func (i *LDAP) createGroupModelFromLDAP(e *ldap.Entry) *libregraph.Group { name := e.GetEqualFoldAttributeValue(i.groupAttributeMap.name) - id := e.GetEqualFoldAttributeValue(i.groupAttributeMap.id) + id, err := i.ldapUUIDtoString(e, i.groupAttributeMap.id, i.groupIDisOctetString) + if err != nil { + i.logger.Warn().Str("dn", e.DN).Str(i.groupAttributeMap.id, e.GetAttributeValue(i.groupAttributeMap.id)).Msg("Invalid User. Cannot convert UUID") + } groupTypes := []string{} if i.isLDAPGroupReadOnly(e) {