Skip to content

Commit

Permalink
Nextcloud storage integration tests & add Nextcloud drivers for auth …
Browse files Browse the repository at this point in the history
…and user (#2043)
  • Loading branch information
michielbdejong authored Sep 8, 2021
1 parent f004c26 commit f2109fc
Show file tree
Hide file tree
Showing 18 changed files with 728 additions and 120 deletions.
6 changes: 6 additions & 0 deletions changelog/unreleased/nextcloud-user-backend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Nextcloud user backend

Adds Nextcloud as a user backend (Nextcloud drivers for 'auth' and 'user').
Also adds back the Nextcloud storage integration tests.

https://github.com/cs3org/reva/pull/2043
140 changes: 140 additions & 0 deletions examples/nextcloud-integration/revad.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
[shared]
gatewaysvc = "localhost:19000"

[grpc]
address = "0.0.0.0:19000"

[grpc.services.gateway]
authregistrysvc = "localhost:19000"
appprovidersvc = "localhost:19000"
appregistry = "localhost:19000"
storageregistrysvc = "localhost:19000"
preferencessvc = "localhost:19000"
userprovidersvc = "localhost:19000"
usershareprovidersvc = "localhost:19000"
publicshareprovidersvc = "localhost:19000"
ocmcoresvc = "localhost:19000"
ocmshareprovidersvc = "localhost:19000"
ocminvitemanagersvc = "localhost:19000"
ocmproviderauthorizersvc = "localhost:19000"
commit_share_to_storage_grant = false
datagateway = "http://localhost:19001/data"
transfer_expires = 6 # give it a moment

[grpc.services.authregistry]
driver = "static"

[grpc.services.authregistry.drivers.static.rules]
basic = "localhost:19000"

[grpc.services.storageregistry]
driver = "static"

[grpc.services.storageregistry.drivers.static]
home_provider = "/home"

[grpc.services.storageregistry.drivers.static.rules]
"/home" = {"address" = "localhost:19000"}
"123e4567-e89b-12d3-a456-426655440000" = {"address" = "localhost:19000"}

[grpc.services.usershareprovider]
driver = "memory"

[grpc.services.ocmcore]
driver = "json"

# Note that ocmcore and ocmshareprovider should use the same file for storing the shares.
[grpc.services.ocmcore.drivers.json]
file = "/var/tmp/reva/shares_server_1.json"

[grpc.services.ocminvitemanager]
driver = "json"

[grpc.services.ocmshareprovider]
driver = "json"

[grpc.services.ocmshareprovider.drivers.json]
file = "/var/tmp/reva/shares_server_1.json"

[grpc.services.ocmproviderauthorizer]
driver = "json"

[grpc.services.ocmproviderauthorizer.drivers.json]
providers = "/etc/revad/providers.json"

[grpc.services.publicshareprovider]
driver = "memory"

[grpc.services.appprovider]
driver = "demo"
iopsecret = "testsecret"
wopiurl = "http://0.0.0.0:8880/"
wopibridgeurl = "http://localhost:8000/wopib"

[grpc.services.appregistry]
driver = "static"

[grpc.services.appregistry.static.rules]
"text/plain" = "localhost:19000"
"text/markdown" = "localhost:19000"
"application/compressed-markdown" = "localhost:19000"
"application/vnd.oasis.opendocument.text" = "localhost:19000"
"application/vnd.oasis.opendocument.spreadsheet" = "localhost:19000"
"application/vnd.oasis.opendocument.presentation" = "localhost:19000"

[grpc.services.storageprovider]
driver = "nextcloud"
mount_path = "/home"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
expose_data_server = true
data_server_url = "http://127.0.0.1:19001/data"
enable_home_creation = true
disable_tus = true

[grpc.services.storageprovider.mimetypes]
".zmd" = "application/compressed-markdown"

[grpc.services.storageprovider.drivers.nextcloud]
end_point = "http://localhost/apps/sciencemesh/"
user_layout = "{{.Username}}"


[grpc.services.authprovider]
auth_manager = "nextcloud"
[grpc.services.authprovider.drivers.nextcloud]
end_point = "http://localhost/apps/sciencemesh/"

[grpc.services.userprovider]
driver = "nextcloud"
[grpc.services.userprovider.drivers.nextcloud]
end_point = "http://localhost/apps/sciencemesh/"

[http]
enabled_services = ["ocmd"]
enabled_middlewares = ["providerauthorizer", "cors"]
address = "0.0.0.0:19001"

[http.services.dataprovider]
driver = "nextcloud"

[http.services.prometheus]
[http.services.sysinfo]

[http.services.dataprovider.drivers.localhome]
user_layout = "{{.Username}}"

[http.services.ocmd]
prefix = "ocm"

[http.middlewares.providerauthorizer]
driver = "json"

[http.middlewares.providerauthorizer.drivers.json]
providers = "/etc/revad/providers.json"

[http.services.ocs]
prefix = "ocs"

[http.services.ocdav]

[http.middlewares.cors]
1 change: 1 addition & 0 deletions pkg/auth/manager/loader/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
_ "github.com/cs3org/reva/pkg/auth/manager/json"
_ "github.com/cs3org/reva/pkg/auth/manager/ldap"
_ "github.com/cs3org/reva/pkg/auth/manager/machine"
_ "github.com/cs3org/reva/pkg/auth/manager/nextcloud"
_ "github.com/cs3org/reva/pkg/auth/manager/oidc"
_ "github.com/cs3org/reva/pkg/auth/manager/publicshares"
// Add your own here
Expand Down
152 changes: 152 additions & 0 deletions pkg/auth/manager/nextcloud/nextcloud.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
// Copyright 2018-2021 CERN
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// In applying this license, CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.

// Package nextcloud verifies a clientID and clientSecret against a Nextcloud backend.
package nextcloud

import (
"context"
"encoding/json"
"io"
"net/http"
"strings"

authpb "github.com/cs3org/go-cs3apis/cs3/auth/provider/v1beta1"
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/auth"
"github.com/cs3org/reva/pkg/auth/manager/registry"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
)

func init() {
registry.Register("nextcloud", New)
}

type mgr struct {
client *http.Client
endPoint string
}

type config struct {
EndPoint string `mapstructure:"endpoint" docs:";The Nextcloud backend endpoint for user check"`
}

// Action describes a REST request to forward to the Nextcloud backend
type Action struct {
verb string
username string
argS string
}

func (c *config) init() {
}

func parseConfig(m map[string]interface{}) (*config, error) {
c := &config{}
if err := mapstructure.Decode(m, c); err != nil {
err = errors.Wrap(err, "error decoding conf")
return nil, err
}
return c, nil
}

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

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

func (am *mgr) Configure(ml map[string]interface{}) error {
return nil
}

func (am *mgr) 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/" + 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 {
return 0, nil, err
}

req.Header.Set("Content-Type", "application/json")
resp, err := am.client.Do(req)
if err != nil {
return 0, nil, err
}

defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return 0, nil, err
}

log.Info().Msgf("am.do response %d %s", resp.StatusCode, body)
return resp.StatusCode, body, nil
}

// 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) {
var params = map[string]string{
"password": clientSecret,
// "username": clientID,
}
bodyStr, err := json.Marshal(params)
if err != nil {
return nil, nil, err
}
log := appctx.GetLogger(ctx)
log.Info().Msgf("Authenticate %s %s", clientID, bodyStr)

statusCode, _, err := am.do(ctx, Action{"Authenticate", clientID, string(bodyStr)})

if err != nil {
return nil, nil, err
}

if statusCode != 200 {
return nil, nil, errors.New("Username/password not recognized by Nextcloud backend")
}
user := &user.User{
Username: clientID,
Id: &user.UserId{
OpaqueId: clientID,
Idp: "localhost",
Type: 1,
},
Mail: clientID,
DisplayName: clientID,
Groups: nil,
}
return user, nil, nil
}
Loading

0 comments on commit f2109fc

Please sign in to comment.