From 53efa9ca145c2e0e0aa8c29c685b15fa1d3f611f Mon Sep 17 00:00:00 2001 From: Ralf Haferkamp Date: Thu, 13 Jan 2022 15:14:51 +0100 Subject: [PATCH] Switch to generating our own UUIDs for users By default the GraphAPI will generate the UUID itself now instead of relying on the LDAP server to generate a valid entryUUID attribute. This can been be switched off via the new `use_server_uuid` toggle in the LDAP config. --- graph/pkg/config/config.go | 7 ++++--- graph/pkg/config/defaultconfig.go | 5 +++-- graph/pkg/identity/ldap.go | 16 +++++++++++----- graph/pkg/service/v0/users.go | 8 ++++++++ 4 files changed, 26 insertions(+), 10 deletions(-) diff --git a/graph/pkg/config/config.go b/graph/pkg/config/config.go index d094cf54f92..6196bcdfc4e 100644 --- a/graph/pkg/config/config.go +++ b/graph/pkg/config/config.go @@ -34,9 +34,10 @@ type Spaces struct { } type LDAP struct { - URI string `ocisConfig:"uri" env:"GRAPH_LDAP_URI"` - BindDN string `ocisConfig:"bind_dn" env:"GRAPH_LDAP_BIND_DN"` - BindPassword string `ocisConfig:"bind_password" env:"GRAPH_LDAP_BIND_PASSWORD"` + URI string `ocisConfig:"uri" env:"GRAPH_LDAP_URI"` + BindDN string `ocisConfig:"bind_dn" env:"GRAPH_LDAP_BIND_DN"` + BindPassword string `ocisConfig:"bind_password" env:"GRAPH_LDAP_BIND_PASSWORD"` + UseServerUUID bool `ocisConfig:"use_server_uuid" env:"GRAPH_LDAP_SERVER_UUID"` UserBaseDN string `ocisConfig:"user_base_dn" env:"GRAPH_LDAP_USER_BASE_DN"` UserSearchScope string `ocisConfig:"user_search_scope" env:"GRAPH_LDAP_USER_SCOPE"` diff --git a/graph/pkg/config/defaultconfig.go b/graph/pkg/config/defaultconfig.go index acd24e83816..ae04f752ad7 100644 --- a/graph/pkg/config/defaultconfig.go +++ b/graph/pkg/config/defaultconfig.go @@ -31,6 +31,7 @@ func DefaultConfig() *Config { URI: "ldap://localhost:9125", BindDN: "", BindPassword: "", + UseServerUUID: false, UserBaseDN: "ou=users,dc=ocis,dc=test", UserSearchScope: "sub", UserFilter: "(objectClass=inetOrgPerson)", @@ -39,12 +40,12 @@ func DefaultConfig() *Config { UserNameAttribute: "uid", // FIXME: switch this to some more widely available attribute by default // ideally this needs to be constant for the lifetime of a users - UserIDAttribute: "entryUUID", + UserIDAttribute: "owncloudUUID", GroupBaseDN: "ou=groups,dc=ocis,dc=test", GroupSearchScope: "sub", GroupFilter: "(objectclass=groupOfNames)", GroupNameAttribute: "cn", - GroupIDAttribute: "cn", + GroupIDAttribute: "owncloudUUID", }, }, } diff --git a/graph/pkg/identity/ldap.go b/graph/pkg/identity/ldap.go index 47433c7e617..b9d1cae2b0d 100644 --- a/graph/pkg/identity/ldap.go +++ b/graph/pkg/identity/ldap.go @@ -6,6 +6,7 @@ import ( "net/url" "github.com/go-ldap/ldap/v3" + "github.com/gofrs/uuid" libregraph "github.com/owncloud/libre-graph-api-go" "github.com/owncloud/ocis/graph/pkg/config" @@ -14,6 +15,8 @@ import ( ) type LDAP struct { + useServerUUID bool + userBaseDN string userFilter string userScope int @@ -71,6 +74,7 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD } return &LDAP{ + useServerUUID: config.UseServerUUID, userBaseDN: config.UserBaseDN, userFilter: config.UserFilter, userScope: userScope, @@ -88,14 +92,9 @@ func NewLDAPBackend(lc ldap.Client, config config.LDAP, logger *log.Logger) (*LD // LDAP User Entry (using the inetOrgPerson LDAP Objectclass) add adds that to the // configured LDAP server func (i *LDAP) CreateUser(ctx context.Context, user libregraph.User) (*libregraph.User, error) { - ar := ldap.AddRequest{ DN: fmt.Sprintf("uid=%s,%s", *user.OnPremisesSamAccountName, i.userBaseDN), Attributes: []ldap.Attribute{ - { - Type: "objectClass", - Vals: []string{"inetOrgPerson", "organizationalPerson", "person", "top"}, - }, // inetOrgPerson requires "cn" { Type: "cn", @@ -116,6 +115,8 @@ func (i *LDAP) CreateUser(ctx context.Context, user libregraph.User) (*libregrap }, } + objectClasses := []string{"inetOrgPerson", "organizationalPerson", "person", "top"} + if user.PasswordProfile != nil && user.PasswordProfile.Password != nil { // TODO? This relies to the LDAP server to properly hash the password. // We might want to add support for the Password Modify LDAP Extended @@ -123,6 +124,11 @@ func (i *LDAP) CreateUser(ctx context.Context, user libregraph.User) (*libregrap // hashing here. ar.Attribute("userPassword", []string{*user.PasswordProfile.Password}) } + if !i.useServerUUID { + ar.Attribute("owncloudUUID", []string{uuid.Must(uuid.NewV4()).String()}) + objectClasses = append(objectClasses, "owncloud") + } + ar.Attribute("objectClass", objectClasses) // inetOrgPerson requires "sn" to be set. Set it to the Username if // Surname is not set in the Request diff --git a/graph/pkg/service/v0/users.go b/graph/pkg/service/v0/users.go index 4a0ae17b87d..88d87a420eb 100644 --- a/graph/pkg/service/v0/users.go +++ b/graph/pkg/service/v0/users.go @@ -60,6 +60,14 @@ func (g Graph) PostUser(w http.ResponseWriter, r *http.Request) { return } + // Disallow user-supplied IDs. It's supposed to be readonly. We're either + // generating them in the backend ourselves or rely on the Backend's + // storage (e.g. LDAP) to provide a unique ID. + if !isNilOrEmpty(u.Id) { + errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "user id is a read-only attribute") + return + } + if u, err = g.identityBackend.CreateUser(r.Context(), *u); err != nil { errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error()) return