Skip to content

Commit

Permalink
Nextcloud edits (#2135)
Browse files Browse the repository at this point in the history
  • Loading branch information
michielbdejong authored Oct 13, 2021
1 parent 4885697 commit a8dfb10
Show file tree
Hide file tree
Showing 11 changed files with 409 additions and 468 deletions.
3 changes: 3 additions & 0 deletions changelog/unreleased/nextcloud-test-improvements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Enhancement: Nextcloud test improvements

https://github.com/cs3org/reva/pull/2135
44 changes: 30 additions & 14 deletions pkg/auth/manager/nextcloud/nextcloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,17 @@ func init() {
registry.Register("nextcloud", New)
}

type mgr struct {
// Manager is the Nextcloud-based implementation of the auth.Manager interface
// see https://github.com/cs3org/reva/blob/v1.13.0/pkg/auth/auth.go#L32-L35
type Manager struct {
client *http.Client
endPoint string
}

// AuthManagerConfig contains config for a Nextcloud-based AuthManager
type AuthManagerConfig struct {
EndPoint string `mapstructure:"endpoint" docs:";The Nextcloud backend endpoint for user check"`
MockHTTP bool `mapstructure:"mock_http"`
}

// Action describes a REST request to forward to the Nextcloud backend
Expand Down Expand Up @@ -76,29 +79,42 @@ func New(m map[string]interface{}) (auth.Manager, error) {
}
c.init()

return NewAuthManager(c, &http.Client{})
return NewAuthManager(c)
}

// NewAuthManager returns a new Nextcloud-based AuthManager
func NewAuthManager(c *AuthManagerConfig, hc *http.Client) (auth.Manager, error) {
return &mgr{
func NewAuthManager(c *AuthManagerConfig) (*Manager, error) {
var client *http.Client
if c.MockHTTP {
// called := make([]string, 0)
// nextcloudServerMock := GetNextcloudServerMock(&called)
// client, _ = TestingHTTPClient(nextcloudServerMock)

// Wait for SetHTTPClient to be called later
client = nil
} else {
client = &http.Client{}
}

return &Manager{
endPoint: c.EndPoint, // e.g. "http://nc/apps/sciencemesh/"
client: hc,
client: client,
}, nil
}

func (am *mgr) Configure(ml map[string]interface{}) error {
// Configure method as defined in https://github.com/cs3org/reva/blob/v1.13.0/pkg/auth/auth.go#L32-L35
func (am *Manager) Configure(ml map[string]interface{}) error {
return nil
}

func (am *mgr) do(ctx context.Context, a Action) (int, []byte, error) {
// SetHTTPClient sets the HTTP client
func (am *Manager) SetHTTPClient(c *http.Client) {
am.client = c
}

func (am *Manager) do(ctx context.Context, a Action) (int, []byte, error) {
log := appctx.GetLogger(ctx)
// user, err := getUser(ctx)
// if err != nil {
// return 0, nil, err
// }
// url := am.endPoint + "~" + a.username + "/api/" + a.verb
url := "http://localhost/apps/sciencemesh/~" + a.username + "/api/auth/" + a.verb
url := am.endPoint + "~" + a.username + "/api/auth/" + a.verb
log.Info().Msgf("am.do %s %s", url, a.argS)
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(a.argS))
if err != nil {
Expand All @@ -122,7 +138,7 @@ func (am *mgr) do(ctx context.Context, a Action) (int, []byte, error) {
}

// Authenticate method as defined in https://github.com/cs3org/reva/blob/28500a8/pkg/auth/auth.go#L31-L33
func (am *mgr) Authenticate(ctx context.Context, clientID, clientSecret string) (*user.User, map[string]*authpb.Scope, error) {
func (am *Manager) Authenticate(ctx context.Context, clientID, clientSecret string) (*user.User, map[string]*authpb.Scope, error) {
type paramsObj struct {
ClientID string `json:"clientID"`
ClientSecret string `json:"clientSecret"`
Expand Down
46 changes: 37 additions & 9 deletions pkg/auth/manager/nextcloud/nextcloud_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ package nextcloud_test

import (
"context"
"fmt"
"os"

"google.golang.org/grpc/metadata"
Expand All @@ -38,6 +39,39 @@ import (
. "github.com/onsi/gomega"
)

func setUpNextcloudServer() (*nextcloud.Manager, *[]string, func()) {
var conf *nextcloud.AuthManagerConfig

ncHost := os.Getenv("NEXTCLOUD")
fmt.Printf(`NEXTCLOUD env var: "%s"`, ncHost)
if len(ncHost) == 0 {
conf = &nextcloud.AuthManagerConfig{
EndPoint: "http://mock.com/apps/sciencemesh/",
MockHTTP: true,
}
nc, _ := nextcloud.NewAuthManager(conf)
called := make([]string, 0)
h := nextcloud.GetNextcloudServerMock(&called)
mock, teardown := nextcloud.TestingHTTPClient(h)
nc.SetHTTPClient(mock)
return nc, &called, teardown
}
conf = &nextcloud.AuthManagerConfig{
EndPoint: ncHost + "/apps/sciencemesh/",
MockHTTP: false,
}
nc, _ := nextcloud.NewAuthManager(conf)
return nc, nil, func() {}
}

func checkCalled(called *[]string, expected string) {
if called == nil {
return
}
Expect(len(*called)).To(Equal(1))
Expect((*called)[0]).To(Equal(expected))
}

var _ = Describe("Nextcloud", func() {
var (
ctx context.Context
Expand Down Expand Up @@ -94,14 +128,9 @@ var _ = Describe("Nextcloud", func() {
// Authenticate(ctx context.Context, clientID, clientSecret string) (*user.User, map[string]*authpb.Scope, error)
Describe("Authenticate", func() {
It("calls the GetHome endpoint", func() {
called := make([]string, 0)

h := nextcloud.GetNextcloudServerMock(&called)
mock, teardown := nextcloud.TestingHTTPClient(h)
am, called, teardown := setUpNextcloudServer()
defer teardown()
am, _ := nextcloud.NewAuthManager(&nextcloud.AuthManagerConfig{
EndPoint: "http://mock.com/apps/sciencemesh/",
}, mock)

user, scope, err := am.Authenticate(ctx, "einstein", "relativity")
Expect(err).ToNot(HaveOccurred())
Expect(user).To(Equal(&userpb.User{
Expand All @@ -128,8 +157,7 @@ var _ = Describe("Nextcloud", func() {
Role: 1,
},
}))
Expect(len(called)).To(Equal(1))
Expect(called[0]).To(Equal(`POST /apps/sciencemesh/~einstein/api/auth/Authenticate {"clientID":"einstein","clientSecret":"relativity"}`))
checkCalled(called, `POST /apps/sciencemesh/~einstein/api/auth/Authenticate {"clientID":"einstein","clientSecret":"relativity"}`)
})
})

Expand Down
78 changes: 54 additions & 24 deletions pkg/share/manager/nextcloud/nextcloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,17 @@ func init() {
registry.Register("nextcloud", New)
}

type mgr struct {
// Manager is the Nextcloud-based implementation of the share.Manager interface
// see https://github.com/cs3org/reva/blob/v1.13.0/pkg/share/share.go#L29-L54
type Manager struct {
client *http.Client
endPoint string
}

// ShareManagerConfig contains config for a Nextcloud-based ShareManager
type ShareManagerConfig struct {
EndPoint string `mapstructure:"endpoint" docs:";The Nextcloud backend endpoint for user check"`
MockHTTP bool `mapstructure:"mock_http"`
}

// Action describes a REST request to forward to the Nextcloud backend
Expand Down Expand Up @@ -108,33 +111,52 @@ func getUser(ctx context.Context) (*userpb.User, error) {
return u, nil
}

// New returns an share manager implementation that verifies against a Nextcloud backend.
// New returns a share manager implementation that verifies against a Nextcloud backend.
func New(m map[string]interface{}) (share.Manager, error) {
c, err := parseConfig(m)
if err != nil {
return nil, err
}
c.init()

return NewShareManager(c, &http.Client{})
return NewShareManager(c)
}

// NewShareManager returns a new Nextcloud-based ShareManager
func NewShareManager(c *ShareManagerConfig, hc *http.Client) (share.Manager, error) {
return &mgr{
func NewShareManager(c *ShareManagerConfig) (*Manager, error) {
var client *http.Client
if c.MockHTTP {
// called := make([]string, 0)
// nextcloudServerMock := GetNextcloudServerMock(&called)
// client, _ = TestingHTTPClient(nextcloudServerMock)

// Wait for SetHTTPClient to be called later
client = nil
} else {
client = &http.Client{}
}

return &Manager{
endPoint: c.EndPoint, // e.g. "http://nc/apps/sciencemesh/"
client: hc,
client: client,
}, nil
}

func (sm *mgr) do(ctx context.Context, a Action) (int, []byte, error) {
// SetHTTPClient sets the HTTP client
func (sm *Manager) SetHTTPClient(c *http.Client) {
sm.client = c
}

func (sm *Manager) do(ctx context.Context, a Action) (int, []byte, error) {
log := appctx.GetLogger(ctx)
user, err := getUser(ctx)
if err != nil {
return 0, nil, err
}
// url := am.endPoint + "~" + a.username + "/api/" + a.verb
url := "http://localhost/apps/sciencemesh/~" + user.Username + "/api/share/" + a.verb
// url := "http://localhost/apps/sciencemesh/~" + user.Username + "/api/share/" + a.verb
url := sm.endPoint + "~" + user.Username + "/api/share/" + a.verb

log.Info().Msgf("am.do %s %s", url, a.argS)
req, err := http.NewRequest(http.MethodPost, url, strings.NewReader(a.argS))
if err != nil {
Expand All @@ -157,7 +179,9 @@ func (sm *mgr) do(ctx context.Context, a Action) (int, []byte, error) {
return resp.StatusCode, body, nil
}

func (sm *mgr) Share(ctx context.Context, md *provider.ResourceInfo, g *collaboration.ShareGrant) (*collaboration.Share, error) {
// Share as defined in the share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/share/share.go#L29-L54
func (sm *Manager) Share(ctx context.Context, md *provider.ResourceInfo, g *collaboration.ShareGrant) (*collaboration.Share, error) {
type paramsObj struct {
Md *provider.ResourceInfo `json:"md"`
G *collaboration.ShareGrant `json:"g"`
Expand Down Expand Up @@ -196,8 +220,9 @@ func (sm *mgr) Share(ctx context.Context, md *provider.ResourceInfo, g *collabor
}, err
}

// GetShare gets the information for a share by the given ref.
func (sm *mgr) GetShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.Share, error) {
// GetShare as defined in the share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/share/share.go#L29-L54
func (sm *Manager) GetShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.Share, error) {
bodyStr, err := json.Marshal(ref)
if err != nil {
return nil, err
Expand Down Expand Up @@ -226,8 +251,9 @@ func (sm *mgr) GetShare(ctx context.Context, ref *collaboration.ShareReference)
}, err
}

// Unshare deletes the share pointed by ref.
func (sm *mgr) Unshare(ctx context.Context, ref *collaboration.ShareReference) error {
// Unshare as defined in the share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/share/share.go#L29-L54
func (sm *Manager) Unshare(ctx context.Context, ref *collaboration.ShareReference) error {
bodyStr, err := json.Marshal(ref)
if err != nil {
return err
Expand All @@ -237,8 +263,9 @@ func (sm *mgr) Unshare(ctx context.Context, ref *collaboration.ShareReference) e
return err
}

// UpdateShare updates the mode of the given share.
func (sm *mgr) UpdateShare(ctx context.Context, ref *collaboration.ShareReference, p *collaboration.SharePermissions) (*collaboration.Share, error) {
// UpdateShare as defined in the share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/share/share.go#L29-L54
func (sm *Manager) UpdateShare(ctx context.Context, ref *collaboration.ShareReference, p *collaboration.SharePermissions) (*collaboration.Share, error) {
type paramsObj struct {
Ref *collaboration.ShareReference `json:"ref"`
P *collaboration.SharePermissions `json:"p"`
Expand Down Expand Up @@ -277,9 +304,9 @@ func (sm *mgr) UpdateShare(ctx context.Context, ref *collaboration.ShareReferenc
}, err
}

// ListShares returns the shares created by the user. If md is provided is not nil,
// it returns only shares attached to the given resource.
func (sm *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.Share, error) {
// ListShares as defined in the share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/share/share.go#L29-L54
func (sm *Manager) ListShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.Share, error) {
bodyStr, err := json.Marshal(filters)
if err != nil {
return nil, err
Expand Down Expand Up @@ -315,8 +342,9 @@ func (sm *mgr) ListShares(ctx context.Context, filters []*collaboration.Filter)
return pointers, err
}

// ListReceivedShares returns the list of shares the user has access.
func (sm *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.ReceivedShare, error) {
// ListReceivedShares as defined in the share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/share/share.go#L29-L54
func (sm *Manager) ListReceivedShares(ctx context.Context, filters []*collaboration.Filter) ([]*collaboration.ReceivedShare, error) {
bodyStr, err := json.Marshal(filters)
if err != nil {
return nil, err
Expand Down Expand Up @@ -362,8 +390,9 @@ func (sm *mgr) ListReceivedShares(ctx context.Context, filters []*collaboration.

}

// GetReceivedShare returns the information for a received share the user has access.
func (sm *mgr) GetReceivedShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.ReceivedShare, error) {
// GetReceivedShare as defined in the share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/share/share.go#L29-L54
func (sm *Manager) GetReceivedShare(ctx context.Context, ref *collaboration.ShareReference) (*collaboration.ReceivedShare, error) {
bodyStr, err := json.Marshal(ref)
if err != nil {
return nil, err
Expand Down Expand Up @@ -403,8 +432,9 @@ func (sm *mgr) GetReceivedShare(ctx context.Context, ref *collaboration.ShareRef
}, err
}

// UpdateReceivedShare updates the received share with share state.
func (sm *mgr) UpdateReceivedShare(ctx context.Context, receivedShare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error) {
// UpdateReceivedShare as defined in the share.Manager interface
// https://github.com/cs3org/reva/blob/v1.13.0/pkg/share/share.go#L29-L54
func (sm Manager) UpdateReceivedShare(ctx context.Context, receivedShare *collaboration.ReceivedShare, fieldMask *field_mask.FieldMask) (*collaboration.ReceivedShare, error) {
type paramsObj struct {
ReceivedShare *collaboration.ReceivedShare `json:"received_share"`
FieldMask *field_mask.FieldMask `json:"field_mask"`
Expand Down
2 changes: 1 addition & 1 deletion pkg/share/manager/nextcloud/nextcloud_server_mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const serverStateHome = "HOME"
var serverState = serverStateEmpty

var responses = map[string]Response{
`POST /apps/sciencemesh/~tester/api/share/Share {"md":{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/some/path","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}},"g":{"grantee":{"Id":null},"permissions":{"permissions":{}}}}`: {200, `{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/share/Share {"md":{"opaque":{},"type":1,"id":{"opaque_id":"fileid-/some/path"},"checksum":{},"etag":"deadbeef","mime_type":"text/plain","mtime":{"seconds":1234567890},"path":"/some/path","permission_set":{},"size":12345,"canonical_metadata":{},"arbitrary_metadata":{"metadata":{"da":"ta","some":"arbi","trary":"meta"}}},"g":{"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"permissions":{"permissions":{}}}}`: {200, `{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/share/GetShare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`: {200, `{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}}`, serverStateHome},
`POST /apps/sciencemesh/~tester/api/share/Unshare {"Spec":{"Id":{"opaque_id":"some-share-id"}}}`: {200, ``, serverStateHome},
`POST /apps/sciencemesh/~tester/api/share/UpdateShare {"ref":{"Spec":{"Id":{"opaque_id":"some-share-id"}}},"p":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}}}`: {200, `{"id":{},"resource_id":{},"permissions":{"permissions":{"add_grant":true,"create_container":true,"delete":true,"get_path":true,"get_quota":true,"initiate_file_download":true,"initiate_file_upload":true,"list_grants":true,"list_container":true,"list_file_versions":true,"list_recycle":true,"move":true,"remove_grant":true,"purge_recycle":true,"restore_file_version":true,"restore_recycle_item":true,"stat":true,"update_grant":true,"deny_grant":true}},"grantee":{"Id":{"UserId":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1}}},"owner":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"creator":{"idp":"0.0.0.0:19000","opaque_id":"f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c","type":1},"ctime":{"seconds":1234567890},"mtime":{"seconds":1234567890}}`, serverStateHome},
Expand Down
Loading

0 comments on commit a8dfb10

Please sign in to comment.