mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-02 10:21:07 -06:00
graph: Groups convert CS3 code to its own backend
Until the LDAP backend is ready the existing CS3 code should keep working. This also adds the initial stubs for the upcoming LDAP Backend.
This commit is contained in:
@@ -11,6 +11,9 @@ import (
|
||||
type Backend interface {
|
||||
GetUser(ctx context.Context, nameOrId string) (*msgraph.User, error)
|
||||
GetUsers(ctx context.Context, queryParam url.Values) ([]*msgraph.User, error)
|
||||
|
||||
GetGroup(ctx context.Context, nameOrId string) (*msgraph.Group, error)
|
||||
GetGroups(ctx context.Context, queryParam url.Values) ([]*msgraph.Group, error)
|
||||
}
|
||||
|
||||
func CreateUserModelFromCS3(u *cs3.User) *msgraph.User {
|
||||
|
||||
@@ -4,7 +4,8 @@ import (
|
||||
"context"
|
||||
"net/url"
|
||||
|
||||
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
cs3group "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
|
||||
cs3user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
|
||||
cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
|
||||
msgraph "github.com/yaegashi/msgraph.go/beta"
|
||||
@@ -26,7 +27,7 @@ func (i *CS3) GetUser(ctx context.Context, userID string) (*msgraph.User, error)
|
||||
return nil, errorcode.New(errorcode.ServiceNotAvailable, err.Error())
|
||||
}
|
||||
|
||||
res, err := client.GetUserByClaim(ctx, &cs3.GetUserByClaimRequest{
|
||||
res, err := client.GetUserByClaim(ctx, &cs3user.GetUserByClaimRequest{
|
||||
Claim: "userid", // FIXME add consts to reva
|
||||
Value: userID,
|
||||
})
|
||||
@@ -57,7 +58,7 @@ func (i *CS3) GetUsers(ctx context.Context, queryParam url.Values) ([]*msgraph.U
|
||||
search = queryParam.Get("$search")
|
||||
}
|
||||
|
||||
res, err := client.FindUsers(ctx, &cs3.FindUsersRequest{
|
||||
res, err := client.FindUsers(ctx, &cs3user.FindUsersRequest{
|
||||
// FIXME presence match is currently not implemented, an empty search currently leads to
|
||||
// Unwilling To Perform": Search Error: error parsing filter: (&(objectclass=posixAccount)(|(cn=*)(displayname=*)(mail=*))), error: Present filter match for cn not implemented
|
||||
Filter: search,
|
||||
@@ -82,3 +83,87 @@ func (i *CS3) GetUsers(ctx context.Context, queryParam url.Values) ([]*msgraph.U
|
||||
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (i *CS3) GetGroups(ctx context.Context, queryParam url.Values) ([]*msgraph.Group, error) {
|
||||
client, err := pool.GetGatewayServiceClient(i.Config.Address)
|
||||
if err != nil {
|
||||
i.Logger.Error().Err(err).Msg("could not get client")
|
||||
return nil, errorcode.New(errorcode.ServiceNotAvailable, err.Error())
|
||||
}
|
||||
|
||||
search := queryParam.Get("search")
|
||||
if search == "" {
|
||||
search = queryParam.Get("$search")
|
||||
}
|
||||
|
||||
res, err := client.FindGroups(ctx, &cs3group.FindGroupsRequest{
|
||||
// FIXME presence match is currently not implemented, an empty search currently leads to
|
||||
// Unwilling To Perform": Search Error: error parsing filter: (&(objectclass=posixAccount)(|(cn=*)(displayname=*)(mail=*))), error: Present filter match for cn not implemented
|
||||
Filter: search,
|
||||
})
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
i.Logger.Error().Err(err).Str("search", search).Msg("error sending find groups grpc request")
|
||||
return nil, errorcode.New(errorcode.ServiceNotAvailable, err.Error())
|
||||
case res.Status.Code != cs3rpc.Code_CODE_OK:
|
||||
if res.Status.Code == cs3rpc.Code_CODE_NOT_FOUND {
|
||||
return nil, errorcode.New(errorcode.ItemNotFound, res.Status.Message)
|
||||
}
|
||||
i.Logger.Error().Err(err).Str("search", search).Msg("error sending find groups grpc request")
|
||||
return nil, errorcode.New(errorcode.GeneralException, res.Status.Message)
|
||||
}
|
||||
|
||||
groups := make([]*msgraph.Group, 0, len(res.Groups))
|
||||
|
||||
for _, group := range res.Groups {
|
||||
groups = append(groups, createGroupModelFromCS3(group))
|
||||
}
|
||||
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
func (i *CS3) GetGroup(ctx context.Context, groupID string) (*msgraph.Group, error) {
|
||||
client, err := pool.GetGatewayServiceClient(i.Config.Address)
|
||||
if err != nil {
|
||||
i.Logger.Error().Err(err).Msg("could not get client")
|
||||
return nil, errorcode.New(errorcode.ServiceNotAvailable, err.Error())
|
||||
}
|
||||
|
||||
res, err := client.GetGroupByClaim(ctx, &cs3group.GetGroupByClaimRequest{
|
||||
Claim: "groupid", // FIXME add consts to reva
|
||||
Value: groupID,
|
||||
})
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
i.Logger.Error().Err(err).Str("groupid", groupID).Msg("error sending get group by claim id grpc request")
|
||||
return nil, errorcode.New(errorcode.ServiceNotAvailable, err.Error())
|
||||
case res.Status.Code != cs3rpc.Code_CODE_OK:
|
||||
if res.Status.Code == cs3rpc.Code_CODE_NOT_FOUND {
|
||||
return nil, errorcode.New(errorcode.ItemNotFound, res.Status.Message)
|
||||
}
|
||||
i.Logger.Error().Err(err).Str("groupid", groupID).Msg("error sending get group by claim id grpc request")
|
||||
return nil, errorcode.New(errorcode.GeneralException, res.Status.Message)
|
||||
}
|
||||
|
||||
return createGroupModelFromCS3(res.Group), nil
|
||||
}
|
||||
|
||||
func createGroupModelFromCS3(g *cs3group.Group) *msgraph.Group {
|
||||
if g.Id == nil {
|
||||
g.Id = &cs3group.GroupId{}
|
||||
}
|
||||
return &msgraph.Group{
|
||||
DirectoryObject: msgraph.DirectoryObject{
|
||||
Entity: msgraph.Entity{
|
||||
ID: &g.Id.OpaqueId,
|
||||
},
|
||||
},
|
||||
OnPremisesDomainName: &g.Id.Idp,
|
||||
OnPremisesSamAccountName: &g.GroupName,
|
||||
DisplayName: &g.DisplayName,
|
||||
Mail: &g.Mail,
|
||||
// TODO when to fetch and expand memberof, usernames or ids?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,6 +136,14 @@ func (i *LDAP) GetUsers(ctx context.Context, queryParam url.Values) ([]*msgraph.
|
||||
return users, nil
|
||||
}
|
||||
|
||||
func (i *LDAP) GetGroup(ctx context.Context, groupID string) (*msgraph.Group, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (i *LDAP) GetGroups(ctx context.Context, queryParam url.Values) ([]*msgraph.Group, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (i *LDAP) createUserModelFromLDAP(e *ldap.Entry) *msgraph.User {
|
||||
return &msgraph.User{
|
||||
DisplayName: pointerOrNil(e.GetEqualFoldAttributeValue(i.userAttributeMap.displayName)),
|
||||
|
||||
@@ -29,15 +29,6 @@ func (g Graph) GetClient() (gateway.GatewayAPIClient, error) {
|
||||
return pool.GetGatewayServiceClient(g.config.Reva.Address)
|
||||
}
|
||||
|
||||
// The key type is unexported to prevent collisions with context keys defined in
|
||||
// other packages.
|
||||
type key int
|
||||
|
||||
const (
|
||||
userKey key = iota
|
||||
groupKey
|
||||
)
|
||||
|
||||
type listResponse struct {
|
||||
Value interface{} `json:"value,omitempty"`
|
||||
}
|
||||
|
||||
@@ -1,129 +1,50 @@
|
||||
package svc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"net/http"
|
||||
|
||||
cs3 "github.com/cs3org/go-cs3apis/cs3/identity/group/v1beta1"
|
||||
cs3rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
|
||||
"github.com/owncloud/ocis/graph/pkg/service/v0/errorcode"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/render"
|
||||
|
||||
//msgraph "github.com/owncloud/open-graph-api-go" // FIXME add groups to open graph, needs OnPremisesSamAccountName and OnPremisesDomainName
|
||||
msgraph "github.com/yaegashi/msgraph.go/v1.0"
|
||||
)
|
||||
|
||||
// GroupCtx middleware is used to load an User object from
|
||||
// the URL parameters passed through as the request. In case
|
||||
// the User could not be found, we stop here and return a 404.
|
||||
func (g Graph) GroupCtx(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
groupID := chi.URLParam(r, "groupID")
|
||||
if groupID == "" {
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "missing group id")
|
||||
return
|
||||
}
|
||||
|
||||
client, err := g.GetClient()
|
||||
if err != nil {
|
||||
g.logger.Error().Err(err).Msg("could not get client")
|
||||
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
res, err := client.GetGroupByClaim(r.Context(), &cs3.GetGroupByClaimRequest{
|
||||
Claim: "groupid", // FIXME add consts to reva
|
||||
Value: groupID,
|
||||
})
|
||||
|
||||
switch {
|
||||
case err != nil:
|
||||
g.logger.Error().Err(err).Str("groupid", groupID).Msg("error sending get group by claim id grpc request")
|
||||
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
case res.Status.Code != cs3rpc.Code_CODE_OK:
|
||||
if res.Status.Code == cs3rpc.Code_CODE_NOT_FOUND {
|
||||
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, res.Status.Message)
|
||||
return
|
||||
}
|
||||
g.logger.Error().Err(err).Str("groupid", groupID).Msg("error sending get group by claim id grpc request")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, res.Status.Message)
|
||||
return
|
||||
}
|
||||
|
||||
ctx := context.WithValue(r.Context(), groupKey, res.Group)
|
||||
next.ServeHTTP(w, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
|
||||
// GetGroups implements the Service interface.
|
||||
func (g Graph) GetGroups(w http.ResponseWriter, r *http.Request) {
|
||||
client, err := g.GetClient()
|
||||
groups, err := g.identityBackend.GetGroups(r.Context(), r.URL.Query())
|
||||
|
||||
if err != nil {
|
||||
g.logger.Error().Err(err).Msg("could not get client")
|
||||
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
search := r.URL.Query().Get("search")
|
||||
if search == "" {
|
||||
search = r.URL.Query().Get("$search")
|
||||
}
|
||||
|
||||
res, err := client.FindGroups(r.Context(), &cs3.FindGroupsRequest{
|
||||
// FIXME presence match is currently not implemented, an empty search currently leads to
|
||||
// Unwilling To Perform": Search Error: error parsing filter: (&(objectclass=posixAccount)(|(cn=*)(displayname=*)(mail=*))), error: Present filter match for cn not implemented
|
||||
Filter: search,
|
||||
})
|
||||
switch {
|
||||
case err != nil:
|
||||
g.logger.Error().Err(err).Str("search", search).Msg("error sending find groups grpc request")
|
||||
errorcode.ServiceNotAvailable.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
return
|
||||
case res.Status.Code != cs3rpc.Code_CODE_OK:
|
||||
if res.Status.Code == cs3rpc.Code_CODE_NOT_FOUND {
|
||||
errorcode.ItemNotFound.Render(w, r, http.StatusNotFound, res.Status.Message)
|
||||
return
|
||||
var errcode errorcode.Error
|
||||
if errors.As(err, &errcode) {
|
||||
errcode.Render(w, r)
|
||||
} else {
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, err.Error())
|
||||
}
|
||||
g.logger.Error().Err(err).Str("search", search).Msg("error sending find groups grpc request")
|
||||
errorcode.GeneralException.Render(w, r, http.StatusInternalServerError, res.Status.Message)
|
||||
return
|
||||
}
|
||||
|
||||
groups := make([]*msgraph.Group, 0, len(res.Groups))
|
||||
|
||||
for _, group := range res.Groups {
|
||||
groups = append(groups, createGroupModelFromCS3(group))
|
||||
}
|
||||
|
||||
render.Status(r, http.StatusOK)
|
||||
render.JSON(w, r, &listResponse{Value: groups})
|
||||
}
|
||||
|
||||
// GetGroup implements the Service interface.
|
||||
func (g Graph) GetGroup(w http.ResponseWriter, r *http.Request) {
|
||||
group := r.Context().Value(groupKey).(*cs3.Group)
|
||||
groupID := chi.URLParam(r, "groupID")
|
||||
if groupID == "" {
|
||||
errorcode.InvalidRequest.Render(w, r, http.StatusBadRequest, "missing group id")
|
||||
return
|
||||
}
|
||||
|
||||
group, err := g.identityBackend.GetGroup(r.Context(), groupID)
|
||||
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, createGroupModelFromCS3(group))
|
||||
}
|
||||
|
||||
func createGroupModelFromCS3(g *cs3.Group) *msgraph.Group {
|
||||
if g.Id == nil {
|
||||
g.Id = &cs3.GroupId{}
|
||||
}
|
||||
return &msgraph.Group{
|
||||
DirectoryObject: msgraph.DirectoryObject{
|
||||
Entity: msgraph.Entity{
|
||||
ID: &g.Id.OpaqueId,
|
||||
},
|
||||
},
|
||||
OnPremisesDomainName: &g.Id.Idp,
|
||||
OnPremisesSamAccountName: &g.GroupName,
|
||||
DisplayName: &g.DisplayName,
|
||||
Mail: &g.Mail,
|
||||
// TODO when to fetch and expand memberof, usernames or ids?
|
||||
}
|
||||
render.JSON(w, r, group)
|
||||
}
|
||||
|
||||
@@ -62,7 +62,6 @@ func NewService(opts ...Option) Service {
|
||||
r.Route("/groups", func(r chi.Router) {
|
||||
r.Get("/", svc.GetGroups)
|
||||
r.Route("/{groupID}", func(r chi.Router) {
|
||||
r.Use(svc.GroupCtx)
|
||||
r.Get("/", svc.GetGroup)
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user