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.
This commit is contained in:
Ralf Haferkamp
2022-01-13 15:14:51 +01:00
parent 840c9a7ddd
commit 53efa9ca14
4 changed files with 26 additions and 10 deletions

View File

@@ -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"`

View File

@@ -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",
},
},
}

View File

@@ -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

View File

@@ -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