Merge pull request #2947 from rhafer/ldap-as-user-backend

Add support for user creation and deletion to GraphAPI (LDAP backend)
This commit is contained in:
Jörn Friedrich Dreyer
2022-01-17 15:54:10 +01:00
committed by GitHub
11 changed files with 405 additions and 26 deletions
+16 -1
View File
@@ -34,7 +34,22 @@ func (i instrument) GetUsers(w http.ResponseWriter, r *http.Request) {
i.next.GetUsers(w, r)
}
// GetUsers implements the Service interface.
// GetUser implements the Service interface.
func (i instrument) GetUser(w http.ResponseWriter, r *http.Request) {
i.next.GetUser(w, r)
}
// PostUser implements the Service interface.
func (i instrument) PostUser(w http.ResponseWriter, r *http.Request) {
i.next.PostUser(w, r)
}
// DeleteUser implements the Service interface.
func (i instrument) DeleteUser(w http.ResponseWriter, r *http.Request) {
i.next.DeleteUser(w, r)
}
// PatchUser implements the Service interface.
func (i instrument) PatchUser(w http.ResponseWriter, r *http.Request) {
i.next.PatchUser(w, r)
}
+15
View File
@@ -38,3 +38,18 @@ func (l logging) GetUsers(w http.ResponseWriter, r *http.Request) {
func (l logging) GetUser(w http.ResponseWriter, r *http.Request) {
l.next.GetUser(w, r)
}
// PostUser implements the Service interface.
func (l logging) PostUser(w http.ResponseWriter, r *http.Request) {
l.next.PostUser(w, r)
}
// DeleteUser implements the Service interface.
func (l logging) DeleteUser(w http.ResponseWriter, r *http.Request) {
l.next.DeleteUser(w, r)
}
// PatchUser implements the Service interface.
func (l logging) PatchUser(w http.ResponseWriter, r *http.Request) {
l.next.PatchUser(w, r)
}
+6
View File
@@ -18,6 +18,9 @@ type Service interface {
GetMe(http.ResponseWriter, *http.Request)
GetUsers(http.ResponseWriter, *http.Request)
GetUser(http.ResponseWriter, *http.Request)
PostUser(http.ResponseWriter, *http.Request)
DeleteUser(http.ResponseWriter, *http.Request)
PatchUser(http.ResponseWriter, *http.Request)
}
// NewService returns a service implementation for Service.
@@ -67,8 +70,11 @@ func NewService(opts ...Option) Service {
})
r.Route("/users", func(r chi.Router) {
r.Get("/", svc.GetUsers)
r.Post("/", svc.PostUser)
r.Route("/{userID}", func(r chi.Router) {
r.Get("/", svc.GetUser)
r.Delete("/", svc.DeleteUser)
r.Patch("/", svc.PatchUser)
})
})
r.Route("/groups", func(r chi.Router) {
+15
View File
@@ -34,3 +34,18 @@ func (t tracing) GetUsers(w http.ResponseWriter, r *http.Request) {
func (t tracing) GetUser(w http.ResponseWriter, r *http.Request) {
t.next.GetUser(w, r)
}
// PostUser implements the Service interface.
func (t tracing) PostUser(w http.ResponseWriter, r *http.Request) {
t.next.PostUser(w, r)
}
// DeleteUser implements the Service interface.
func (t tracing) DeleteUser(w http.ResponseWriter, r *http.Request) {
t.next.DeleteUser(w, r)
}
// PatchUser implements the Service interface.
func (t tracing) PatchUser(w http.ResponseWriter, r *http.Request) {
t.next.PatchUser(w, r)
}
+97 -2
View File
@@ -1,6 +1,7 @@
package svc
import (
"encoding/json"
"errors"
"net/http"
"net/url"
@@ -8,9 +9,9 @@ import (
revactx "github.com/cs3org/reva/pkg/ctx"
"github.com/go-chi/chi/v5"
"github.com/go-chi/render"
libregraph "github.com/owncloud/libre-graph-api-go"
"github.com/owncloud/ocis/graph/pkg/identity"
"github.com/owncloud/ocis/graph/pkg/service/v0/errorcode"
//msgraph "github.com/owncloud/open-graph-api-go" // FIXME needs OnPremisesSamAccountName, OnPremisesDomainName and AdditionalData
)
// GetMe implements the Service interface.
@@ -32,7 +33,6 @@ func (g Graph) GetMe(w http.ResponseWriter, r *http.Request) {
}
// GetUsers implements the Service interface.
// TODO use cs3 api to look up user
func (g Graph) GetUsers(w http.ResponseWriter, r *http.Request) {
users, err := g.identityBackend.GetUsers(r.Context(), r.URL.Query())
if err != nil {
@@ -47,6 +47,36 @@ func (g Graph) GetUsers(w http.ResponseWriter, r *http.Request) {
render.JSON(w, r, &listResponse{Value: users})
}
func (g Graph) PostUser(w http.ResponseWriter, r *http.Request) {
u := libregraph.NewUser()
err := json.NewDecoder(r.Body).Decode(u)
if err != nil {
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
return
}
if isNilOrEmpty(u.DisplayName) || isNilOrEmpty(u.OnPremisesSamAccountName) || isNilOrEmpty(u.Mail) {
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "Missing Required Attribute")
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
}
render.Status(r, http.StatusOK)
render.JSON(w, r, u)
}
// GetUser implements the Service interface.
func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) {
userID := chi.URLParam(r, "userID")
@@ -74,3 +104,68 @@ func (g Graph) GetUser(w http.ResponseWriter, r *http.Request) {
render.Status(r, http.StatusOK)
render.JSON(w, r, user)
}
func (g Graph) DeleteUser(w http.ResponseWriter, r *http.Request) {
userID := chi.URLParam(r, "userID")
userID, err := url.PathUnescape(userID)
if err != nil {
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "unescaping user id failed")
}
if userID == "" {
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "missing user id")
return
}
err = g.identityBackend.DeleteUser(r.Context(), userID)
if err != nil {
var errcode errorcode.Error
if errors.As(err, &errcode) {
errcode.Render(w, r)
} else {
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
}
}
render.Status(r, http.StatusNoContent)
render.NoContent(w, r)
}
// PatchUser implements the Service Interface. Updates the specified attributes of an
// ExistingUser
func (g Graph) PatchUser(w http.ResponseWriter, r *http.Request) {
nameOrID := chi.URLParam(r, "userID")
nameOrID, err := url.PathUnescape(nameOrID)
if err != nil {
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "unescaping user id failed")
}
if nameOrID == "" {
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "missing user id")
return
}
changes := libregraph.NewUser()
err = json.NewDecoder(r.Body).Decode(changes)
if err != nil {
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, err.Error())
return
}
u, err := g.identityBackend.UpdateUser(r.Context(), nameOrID, *changes)
if err != nil {
var errcode errorcode.Error
if errors.As(err, &errcode) {
errcode.Render(w, r)
} else {
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
}
}
render.Status(r, http.StatusOK)
render.JSON(w, r, u)
}
func isNilOrEmpty(s *string) bool {
return s == nil || *s == ""
}