Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions changelog/unreleased/enhancement-graph-create-guest-users.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
Enhancement: Allow creating guest users through the provisioning API

`POST /graph/v1.0/users` now accepts an explicit `userType` (e.g. `Guest`) on
creation instead of always forcing `Member` and rejecting any supplied type. This
aligns the provisioning API with the user types the system already recognizes
(`Member` and `Guest`).

Backwards compatible: omitting `userType` still defaults to `Member`, so existing
API consumers are unaffected. An unknown `userType` is rejected with a 400. Creating
users remains gated by the admin requirement on the route.

https://github.com/owncloud/ocis/pull/12471
13 changes: 9 additions & 4 deletions services/graph/pkg/service/v0/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,12 +500,17 @@ func (g Graph) PostUser(w http.ResponseWriter, r *http.Request) {
return
}

if u.HasUserType() {
logger.Info().Interface("user", u).Msg("could not create user: userType is a read-only attribute")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "userType is a read-only attribute")
// A userType may be set explicitly on creation (e.g. "Guest" for an invited
// external user). It must be a known type; when omitted it defaults to "Member".
// Who may create users at all is already gated by the admin requirement on the route.
switch {
case !u.HasUserType():
u.SetUserType("Member")
case !isValidUserType(u.GetUserType()):
logger.Info().Interface("user", u).Msg("could not create user: invalid userType")
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "invalid userType")
return
}
u.SetUserType("Member")

logger.Debug().Interface("user", u).Msg("calling create user on backend")
if u, err = g.identityBackend.CreateUser(r.Context(), *u); err != nil {
Expand Down
24 changes: 22 additions & 2 deletions services/graph/pkg/service/v0/users_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -964,11 +964,31 @@ var _ = Describe("Users", func() {
assertHandleBadAttributes(user)
})

It("handles set userType - it's read-only", func() {
user.SetUserType("Member")
It("rejects an invalid userType", func() {
user.SetUserType("not-a-valid-usertype")
assertHandleBadAttributes(user)
})

It("honors an explicit valid userType like Guest", func() {
roleService.On("AssignRoleToUser", mock.Anything, mock.Anything).Return(&settings.AssignRoleToUserResponse{}, nil)
identityBackend.On("CreateUser", mock.Anything, mock.Anything).Return(func(ctx context.Context, u libregraph.User) *libregraph.User {
u.SetId("/users/guest")
return &u
}, nil)
user.SetUserType("Guest")
userJson, err := json.Marshal(user)
Expect(err).ToNot(HaveOccurred())

r := httptest.NewRequest(http.MethodPost, "/graph/v1.0/users", bytes.NewBuffer(userJson))
r = r.WithContext(revactx.ContextSetUser(ctx, currentUser))
svc.PostUser(rr, r)

Expect(rr.Code).To(Equal(http.StatusCreated))
createdUser := libregraph.User{}
Expect(json.Unmarshal(rr.Body.Bytes(), &createdUser)).To(Succeed())
Expect(createdUser.GetUserType()).To(Equal("Guest"))
})

It("creates a user", func() {
roleService.On("AssignRoleToUser", mock.Anything, mock.Anything).Return(&settings.AssignRoleToUserResponse{}, nil)
identityBackend.On("CreateUser", mock.Anything, mock.Anything).Return(func(ctx context.Context, user libregraph.User) *libregraph.User {
Expand Down
Loading