Skip to content

Commit

Permalink
Switch to generating our own UUIDs for users
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rhafer committed Jan 13, 2022
1 parent 840c9a7 commit 53efa9c
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 10 deletions.
7 changes: 4 additions & 3 deletions graph/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand Down
5 changes: 3 additions & 2 deletions graph/pkg/config/defaultconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand All @@ -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",
},
},
}
Expand Down
16 changes: 11 additions & 5 deletions graph/pkg/identity/ldap.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -14,6 +15,8 @@ import (
)

type LDAP struct {
useServerUUID bool

userBaseDN string
userFilter string
userScope int
Expand Down Expand Up @@ -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,
Expand All @@ -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",
Expand All @@ -116,13 +115,20 @@ 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
// Operation for servers that implement it. (Or implement client-side
// 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
Expand Down
8 changes: 8 additions & 0 deletions graph/pkg/service/v0/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 53efa9c

Please sign in to comment.