1
0
mirror of https://github.com/cs3org/reva.git synced 2025-04-18 13:44:12 +03:00

Create home directory on login on configured home storage providers and other stuff (#469)

This commit is contained in:
Hugo G. Labrador 2020-01-17 07:04:20 +01:00 committed by GitHub
parent 4c7513415e
commit e6c824652a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
81 changed files with 769 additions and 2499 deletions

View File

@ -1,2 +1,3 @@
Aritz Brosa <aritz.brosa.iartza@cern.ch> zazola <aritz.brosa@gmail.com>
Giuseppe Lo Presti <giuseppe.lopresti@cern.ch> Giuseppe <giuseppe.lopresti@cern.ch>
Michael D'Silva <michael.dsilva@aarnet.edu.au>

View File

@ -8,5 +8,6 @@
- Ilja Neumann <ineumann@owncloud.com>
- Jörn Friedrich Dreyer <jfd@butonic.de>
- Michael D'Silva <md@aarnet.edu.au>
- Michael D'Silva <michael.dsilva@aarnet.edu.au>
- Mohitty <mohitt@iitk.ac.in>
- Thomas Boerger <thomas@webhippie.de>

View File

@ -77,10 +77,6 @@ func readConfig() (*config, error) {
}
func writeConfig(c *config) error {
if c.AuthHeader == "" {
c.AuthHeader = "x-access-token"
}
data, err := json.Marshal(c)
if err != nil {
return err
@ -89,8 +85,7 @@ func writeConfig(c *config) error {
}
type config struct {
Host string `json:"host"`
AuthHeader string `json:"auth_header"`
Host string `json:"host"`
}
func read(r *bufio.Reader) (string, error) {

View File

@ -104,13 +104,6 @@ skip_methods = ["/status.php"]
[http.middlewares.auth.token_managers.jwt]
secret = "{{.TokenSecret}}"
[http.middlewares.auth.token_strategies.header]
header = "X-Access-Token"
[http.middlewares.auth.token_writers.header]
header = "X-Access-Token"
# GRPC interceptors
[grpc.interceptors.trace]
@ -126,15 +119,11 @@ priority = 300
[grpc.interceptors.auth]
priority = 400
# keys for grpc metadata are always lowercase, so interceptors headers need to use lowercase.
header = "x-access-token"
token_strategy = "header"
token_manager = "jwt"
# GenerateAccessToken contains the credentials in the payload. Skip auth, otherwise services cannot obtain a token.
skip_methods = ["/cs3.authproviderv1beta1.AuthService/GenerateAccessToken"]
[grpc.interceptors.auth.token_strategies.header]
header = "X-Access-Token"
[grpc.interceptors.auth.token_managers.jwt]
secret = "{{.TokenSecret}}"

View File

@ -30,8 +30,6 @@ import (
"google.golang.org/grpc/metadata"
)
const defaultHeader = "x-access-token"
func getAuthContext() context.Context {
ctx := context.Background()
// read token from file
@ -41,7 +39,7 @@ func getAuthContext() context.Context {
return ctx
}
ctx = token.ContextSetToken(ctx, t)
ctx = metadata.AppendToOutgoingContext(ctx, defaultHeader, t)
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, t)
return ctx
}

View File

@ -33,6 +33,7 @@ import (
"github.com/cs3org/reva/pkg/logger"
"github.com/cs3org/reva/pkg/rgrpc"
"github.com/cs3org/reva/pkg/rhttp"
"github.com/cs3org/reva/pkg/sharedconf"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/rs/zerolog"
@ -44,6 +45,7 @@ import (
// Run runs a reva server with the given config file and pid file.
func Run(mainConf map[string]interface{}, pidFile string) {
parseSharedConfOrDie(mainConf["shared"])
coreConf := parseCoreConfOrDie(mainConf["core"])
logConf := parseLogConfOrDie(mainConf["log"])
@ -333,6 +335,13 @@ func parseCoreConfOrDie(v interface{}) *coreConf {
return c
}
func parseSharedConfOrDie(v interface{}) {
if err := sharedconf.Decode(v); err != nil {
fmt.Fprintf(os.Stderr, "error decoding shared config: %s\n", err.Error())
os.Exit(1)
}
}
func parseLogConfOrDie(v interface{}) *logConf {
c := &logConf{}
if err := mapstructure.Decode(v, c); err != nil {

View File

@ -1,53 +0,0 @@
# REVA Documentation
:warning: REVA is a very young project and documentation is subject to change very often!
* [Installing REVA](./installing-reva.md)
* [Building REVA from Sources](./building-reva.md)
* [Beginner's Guide](./beginner-guide.md)
* [Controlling REVA](./controlling-reva.md)
* [Command-line parameters](./command-line.md)
## Guides
* [Getting started with REVA](./guides/getting-started.md)
## Config reference
* [Core](./config/core.md)
* [Log](./config/log.md)
* [HTTP](./config/http.md)
* [GRPC](./config/grpc.md)
**HTTP services**
* [helloworld](./config/http/services/helloworld.md)
* [datagateway](./config/http/services/datagateway.md)
* [dataprovider](./config/http/services/dataprovider.md)
* [prometheussvc](./config/http/services/prometheus.md)
* [ocdav](./config/http/services/ocdav.md)
* [ocs](./config/http/services/ocs.md)
* [oidcprovider](./config/http/services/oidcprovider.md)
* [wellknown](./config/http/services/wellknown.md)
**HTTP middleware**
* [auth](./config/http/middleware/auth.md)
* [cors](./config/http/middleware/cors.md)
* [log](./config/http/middleware/log.md)
**GRPC Services**
* [authprovider](./config/grpc/services/authprovider.md)
* [authregistry](./config/grpc/services/authregistry.md)
* [gateway](./config/grpc/services/gateway.md)
* [helloworld](./config/grpc/services/helloworld.md)
* [storageprovider](./config/grpc/services/storageprovider.md)
* [storageregistry](./config/grpc/services/storageregistry.md)
* [userprovider](./config/grpc/services/userprovider.md)
* [usershareprovider](./config/grpc/services/usershareprovider.md)
**GRPC interceptors**
* [auth](./config/grpc/interceptors/auth.md)

View File

@ -1 +0,0 @@
remote_theme: pmarsceill/just-the-docs

View File

@ -1,95 +0,0 @@
# Beginner's Guide
This guide gives a basic introduction to revad and describes some simple tasks that can be done with it.
This guide assumes that revad is already installed on the reader's machine.
If this is not, see [Installing REVA](./installing-reva.md).
This guide describes how to start and stop the **REVA daemon (revad)**, and reload its configuration, explains the structure of the configuration
file and describes how to set up revad to serve some basic services.
By default, the configuration file is named revad.toml and placed in the directory /etc/revad/revad.toml.
## Starting, Stopping, and Reloading Configuration
To start revad, run the executable file:
```
revad -c revad.toml -p /var/tmp/revad.pid
```
Once revad is started, it can be controlled by invoking the executable with the -s parameter. Use the following syntax:
```
revad -s <signal> -p /var/tmp/revad.pid
```
Where signal may be one of the following:
* stop — fast shutdown (aborts in-flight requests)
* quit — graceful shutdown
* reload — reloading the configuration file (forks a new process)
For example, to stop revad gracefully, the following command can be executed:
```
revad -s quit -p /var/tmp/revad.pid
```
*This command should be executed under the same user that started revad.*
Changes made in the configuration file will not be applied until the command to reload configuration is sent to revad or it is restarted. To reload configuration, execute:
```
revad -s reload -p /var/tmp/revad.pid
```
Once the main process receives the signal to reload configuration, it checks the syntax validity of the new configuration file and tries to apply the configuration provided in it. If this is a success, the main process forks a new process. The new forked process will gracefully kill the parent process. During a period of time until all ongoing requests are served, both processes will share the same network socket, the old parent process will serve ongoing requests and the new process will serve only new requests. No requests are dropped during the reload. If the provided configuration is invalid, the forked process will die and the master process will continue serving requests.
A signal may also be sent to the revad process with the help of Unix tools such as the *kill* utility. In this case a signal is sent directly to a process with a given process ID. The process ID of the revad master process is written to the pid file, as configured with the *-s* flag. For example, if the master process ID is 1610, to send the QUIT signal resulting in revads graceful shutdown, execute:
```
kill -s QUIT 1610
```
For getting the list of all running revad processes, the *ps* utility may be used, for example, in the following way:
```
ps -ax | grep revad
```
For more information on sending signals to revad, see [Controlling REVA](./controlling-reva.md).
## Configuration Files Structure
revad configuration file is written in [TOML](https://github.com/toml-lang/toml) language.
revad consists of services which are controlled by directives specified in the configuration file.
An example configuration file is the following:
```
[http]
enabled_services = ["helloworldsvc"]
```
Running revad, will output some lines similar to these:
```
4:44PM INF main.go:94 > version= commit= branch= go_version= build_date= build_platform= pid=27856
4:44PM INF main.go:95 > running on 4 cpus pid=27856
4:44PM INF grace/grace.go:181 > pidfile saved at: /tmp/gonzalhu/revad-44b42674-2f10-4d06-b681-328b5a9b2581.pid pid=27856 pkg=grace
4:44PM INF httpserver/httpserver.go:233 > http service enabled: helloworldsvc@/ pid=27856 pkg=httpserver
4:44PM INF httpserver/httpserver.go:134 > http server listening at http://localhost:9998 pid=27856 pkg=httpserver
```
Revad will listen by default at http://localhost:9998, curl-ing this address will render the message *Hello World!*.
The *helloworldsvc* is one of the many services available in revad. To modify the configuration for this service a new directive is added to the configuration:
```
[http]
enabled_services = ["helloworldsvc"]
[http.services.helloworldsvc]
message = "Ola Mundo!"
```
Reloading revad (```revad -s reload -p /var/tmp/revad.pid```) will render the new message.

View File

@ -1,11 +0,0 @@
# Building REVA
To build REVA the Go compiler needs to be installed. See [Install Go](https://golang.org/doc/install) to install
the Go programming language that installs the Go compiler.
```
git clone https://github.com/cs3org/reva
cd reva
make deps
make
```

View File

@ -1,16 +0,0 @@
# Command line parameters
revad supports the following command-line parameters:
```
Usage of ./revad:
-c string
set configuration file (default "/etc/revad/revad.toml")
-p string
pid file. If empty defaults to a random file in the OS temporary directory
-s string
send signal to a master process: stop, quit, reload
-t test configuration and exit
-version
show version and exit
```

View File

@ -1,53 +0,0 @@
# Core functionality
Example configuration:
```
[core]
max_cpus = 2
tracing_enabled = true
```
## Directives
```
Syntax: max_cpus = uint | "uint%"
Default: max_cpus = "100%"
```
If max_cpus is set it determines the available cpus to schedule revad processes.
```
Syntax: tracing_enabled = boolean
Default: tracing_enabled = false
```
```
Syntax: tracing_endpoint = string
Default: tracing_endpoint = "localhost:6831"
```
```
Syntax: tracing_collector = string
Default: tracing_collector = "http://localhost:14268/api/traces"
```
```
Syntax: tracing_service_name = string
Default: tracing_service_name = "revad"
```
```
Syntax: disable_http = false | true
Default: disable_http = false
```
If disable_http is set to false, revad will not listen on the specified http network and address and
http services will not be exposed by revad.
```
Syntax: disable_grpc = false | true
Default: disable_grpc = false
```
If disable_grpc is set to false, revad will not listen on the specified grpc network and address and
grpc services will not be exposed by revad.

View File

@ -1,51 +0,0 @@
# gRPC functionality
Example configuration:
```
[grpc]
network = tcp
address = 0.0.0.0:9999
enabled_services = ["storageprovidersvc"]
[grpc.services.storageprovidersvc]
driver = "local"
mount_path = "/localfs"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
tmp_folder = "/var/tmp"
[grpc.services.storageprovidersvc.drivers.local]
root = "/var/data"
```
## Directives
```
Syntax: network = tcp
Default: network = tcp
```
network specifies what network type to listen for requests. The only supported
network type for the moment is a tcp socket.
```
Syntax: address = string
Default: address = "0.0.0.0:9999"
```
address specifies the listening address for connections.
```
Syntax: enabled_services = [string, string, ...]
Default: enabled_services = []
```
enabled_services specifies the grpc services exposed by revad.
The value is a list containing the names of the services.
By default, no service is exposed.
```
Syntax: shutdown_deadline = int
Default: shutdown_deadline = 60
```
shutdown_deadline specifies how much time in seconds to wait for the
grpc server to shutdown. Once the deadline is reached, ongoing requests that
did not finish will be aborted.

View File

@ -1,48 +0,0 @@
# GRPC interceptor: auth
This interceptor authenticates requests to
GRPC services.
To enable the interceptor:
```
[grpc]
enabled_interceptors = ["auth"]
```
Example configuration:
```
[grpc.interceptors.auth]
token_manager = "jwt"
#header = "x-access-token"
skip_methods = [
# allow calls that happen during authentication
"/cs3.gatewayv0alpha.GatewayService/Authenticate",
"/cs3.gatewayv0alpha.GatewayService/WhoAmI",
"/cs3.gatewayv0alpha.GatewayService/GetUser",
"/cs3.gatewayv0alpha.GatewayService/ListAuthProviders",
"/cs3.authregistryv0alpha.AuthRegistryService/ListAuthProviders",
"/cs3.authregistryv0alpha.AuthRegistryService/GetAuthProvider",
"/cs3.authproviderv0alpha.AuthProviderService/Authenticate",
"/cs3.userproviderv0alpha.UserProviderService/GetUser",
]
[grpc.interceptors.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
```
## Directives
```
Syntax: token_manager = string
Default: token_manager = "jwt"
```
token_manager specifies the strategy to use verify the access token.
Available token managers shipped with REVA can be consulted at the end of this section.
The default manager is to verify it using JWT.
**The token manager configured for the authentication service and the token manager for
this middleware MUST be the same**.
TODO: header
TODO: skip_methods

View File

@ -1,141 +0,0 @@
# gRPC Service: authprovider
To enable the service:
```
[grpc]
enabled_services = ["authprovider"]
```
Example configuration:
```
[grpc.services.authprovider]
auth_manager = "demo"
token_manager = "jwt"
user_manager = "demo"
```
## Directives
```
Syntax: auth_manager = string
Default: auth_manager = "demo"
```
auth_manager specifies the auth driver to use for the authentication service.
Available drivers shipped with REVA can be consulted at the end of this section.
The default driver (demo) is a hardcoded in-memory list of well-known physicists.
```
Syntax: token_manager = string
Default: token_manager = "demo"
```
token_manager specifies the token driver to use for the authentication service. Available drivers shipped with REVA can be consulted at the end of this section.
The default driver (jwt) forges [JWT](https://tools.ietf.org/html/rfc7519) tokens.
```
Syntax: user_manager = string
Default: user_manager = "demo"
```
user_manager specifies the user manager to use for obtaining user information
like display names and groups associated to an user.
Available managers shipped with REVA can be consulted at the end of this section.
The default driver (demo) is a hardcoded in-memory catalog of well-known physicists.
## Auth managers
### Demo
The demo driver authenticates against a hardcoded in-memory catalog
of well-known physicists.
This is the list of credentials:
```
einstein => relativity
marie => radioactivity
richard => superfluidity
```
### JSON
The json driver allows using a json file to authenticate users.
TODO: example json config
### LDAP
The LDAP driver authenticates against an LDAP server.
Example configuration:
```
[grpc.services.authsvc.auth_managers.ldap"
hostname = "example.org"
port = 389
base_dn = "CN=Users,DC=example,DC=org"
filter = "(&(objectClass=person)(objectClass=user)(cn=%s))"
bind_username = "foo"
bind_password = "bar"
```
#### Directives
```
Syntax: hostname = string
Default: hostname = ""
```
hostname specifies the hostname of the LDAP server.
```
Syntax: port = int
Default: port = 389
```
port specifies the port of the LDAP server.
```
Syntax: base_dn = string
Default: base_dn = ""
```
base_dn specifies the Base DN to use to query the LDAP server.
```
Syntax: filter = string
Default: filter = ""
```
filter specifies the LDAP filter to authenticate users.
The filter needs to contains a '%s' placeholder where the username will be set
in the filter.
```
Syntax: bind_username = string
Default: bind_username = ""
```
bind_username specifies the username to bind agains the LDAP server.
```
Syntax: bind_password = string
Default: bind_password = ""
```
bind_password specifies the password to use to bind agains the LDAP server.
## Token managers
### JWT
The jwt manager forges [JWT](https://tools.ietf.org/html/rfc7519) tokens.
#### Directives
```
Syntax: secret = string
Default: secret = ""
```
secret specifies the secret to use to sign a JWT token.
## User managers
### Demo
The demo manager contains a hard-coded in-memory catalog of user information
of well-known physicists. This manager is to be used with the *demo* auth manager.

View File

@ -1,201 +0,0 @@
# gRPC Service: storageprovider
To enable the service:
```
[grpc]
enabled_services = ["storageprovider"]
```
Example configuration:
```
[grpc.services.storageprovider]
driver = "local"
mount_path = "/localfs"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
tmp_folder = "/var/tmp"
[grpc.services.storageprovider.drivers.local]
root = "/var/data"
```
## Directives
```
Syntax: mount_path = string
Default: mount_path = ""
```
mount_path specifies where to mount the storage provider
in the global REVA namespace. This directive needs to be specified
to run the service.
```
Syntax: mount_id = string
Default: mount_id = ""
```
mount_id specifies the identifier to append to internal object ids
so they become routable accross the REVA global namespace. This directive
needs to be specified to run the service.
```
Syntax: tmp_folder = string
Default: tmp_folder = "/tmp"
```
tmp_folder specifies where temporary files will be stored
on the local filesystem. The default is to use the
system default for a temporary folder (```echo $TMPDIR```).
```
Syntax: driver = string
Default: driver = "local"
```
driver specifies the filesystem driver to use for the storage provider.
Available drivers shipped with REVA can be consulted at the end of this section.
The default is to use a local filesystem to store the files.
storageprovidersvc specifies the location of the storage provider.
## Storage drivers
### Local filesystem
The local driver stores the files in a local filesytem.
Example configuration:
```
[grpc.services.storageprovidersvc.drivers.local]
root = "/var/data"
```
#### Directives
```
Syntax: root = string
Default: root = "/tmp"
```
root specifies the directory in the local filesystem for storing data.
### EOS driver - [CERN Open Storage](http://eos.web.cern.ch/)
The EOS driver stores the files in a remote EOS storage system.
Example configuration:
```
[grpc.services.storageprovidersvc.drivers.eos]
namespace = "/eos/user/"
master_url = "root://eosuser.example.org"
```
#### Directives
```
Syntax: namespace = string
Default: namespace = "/eos"
```
namespace speficies the namespace on the remote EOS
storage system to perform storage operations.
```
Syntax: eos_binary = string
Default: eos_binary = "/usr/bin/eos"
```
eos_binary specifies the location of the eos client binary.
```
Syntax: xrdcopy_binary = string
Default: xrdcopy_binary = "/usr/bin/xrdcopy"
```
xrdcopy_binary specifies the location of the xrdcopy client binary.
```
Syntax: master_url = string
Default: master_url = "root://example.org"
```
master_url specifies the master EOS MGM url.
```
Syntax: slave_url = string
Default: slave_url = "root://example.org"
```
slave_url specifies the slave EOS MGM url.
```
Syntax: cache_directory = string
Default: cache_directory = "/tmp"
```
cache_directory specifies where to store temporary files.
The default value is system default for a temporary folder (```echo $TMPDIR```).
```
Syntax: show_hidden_sys_files = true | false
Default: show_hidden_sys_files = false
```
If show_hidden_sys_files is set to true, system files
used by EOS are exposed to the clients. System files follow the pattern
*.sys.** like version folders (.sys.v#.*) or atomic files (.sys.a#.).
```
Syntax: force_single_user_mode = true | false
Default: force_single_user_mode = false
```
If force_single_user_mode is set all EOS command sent to the EOS
storage system will be sent as a single user specified by the *single_username*
directive. This directive is usefull when the access to EOS is done by
web servers like Apache and all the commands run as www-data or apache unix user.
```
Syntax: single_username = string
Default: single_username = ""
```
single_username specifies the unix account for run EOS commands.
### Owncloud data directory
The `owncloud` driver stores the files in a local filesytem using the owncloud data directory layout. Files will be assigned a uuid, stored in extended attributes and cahced via redis.
Example configuration:
```
[grpc.services.storageprovidersvc.drivers.owncloud]
datadirectory = "/data"
```
#### Directives
```
Syntax: datadirectory = string
Default: datadirectory = ""
```
datadirectory specifies the directory in the local filesystem for storing data.
```
Syntax: scan = boolean
Default: scan = true
```
scan will scan files on the first request to index file ids into the configured redis server
```
Syntax: autocreate = boolean
Default: autocreate = true
```
autocreate will create the home dir and necessary subfolders for new users
```
Syntax: redis = string
Default: redis = ":6379"
```
redis is used to store fileid to path mappings

View File

@ -1,46 +0,0 @@
# HTTP functionality
Example configuration:
```
[http]
network = tcp
address = 0.0.0.0:9998
enabled_services = ["helloworldsvc"]
[http.services.helloworldsvc]
hello_message = "Ola Mundo!"
```
## Directives
```
Syntax: network = tcp
Default: network = tcp
```
network specifies what network type to listen for requests. The only supported
network type for the moment is a tcp socket.
```
Syntax: address = string
Default: address = "0.0.0.0:9998"
```
address specifies the listening address for connections.
```
Syntax: enabled_services = [string, string, ...]
Default: enabled_services = []
```
enabled_services specifies the http services exposed by revad.
The value is a list containing the names of the services.
By default, not service is exposed.
```
Syntax: enabled_middlewares = [string, string, ...]
Default: enabled_middlewares = ["log", "trace"]
```
enabled_middlewares specifies the http middlwares used on the
HTTP request->response chain.
The value is a list containing the names of the middlewares.
By default, the log and trace middlewares are enabled.

View File

@ -1,190 +0,0 @@
# HTTP Middleware: auth
This middleware authenticates requests to
HTTP services.
The logic is as follows: when a requests comes, the token strategy is triggered
to obtain an access token from the request. If a token is found, authenticaton
is not triggered. If a token is not found, the credentials strategy is
triggered to obtain user credentials (basic auth, OpenIDConnect, ...).
Then these credentials are validated against the authentication service
and if they are valid, an access token is obtained. This access token is written
to the response using a token writer strategy (reponse header, response cookie, ...).
Once the access token is obtained either because is set on the request or because
authentication was successful, the token is verified using the token manager
strategy (jwt) to obtain the user context and pass it to outgoing requests.
To enable the middleware:
```
[http]
enabled_middlewares = ["auth"]
```
Example configuration:
```
[http.middlewares.auth]
gateway = "localhost:9999"
auth_type = "basic"
credential_strategy = "basic"
token_strategy = "header"
token_writer = "header"
token_manager = "jwt"
[http.middlewares.auth.token_managers.jwt]
secret = "bar"
[http.middlewares.auth.token_strategies.header]
header = "X-Access-Token"
[http.middlewares.auth.token_writers.header]
header = "X-Access-Token"
```
## Directives
```
Syntax: gateway = string
Default: gateway = "0.0.0.0:9999"
```
gateway specifies the location of the gateway service.
```
Syntax: auth_type = string
Default: auth_type = ""
```
auth_type specifies the type of authprovider the gateway should look up using the configured authregistry. Must be set (`basic` or `oidc` make sense, but those are arbitrary strings the are just used to do a lookup of the actual authprovider url)
```
Syntax: credential_strategy = string
Default: credential_strategy = "basic"
```
credential_strategy specifies the strategy to use to obtain
user credentials.
Available strategies shipped with REVA can be consulted at the end of this section.
The default strategy is [Basic Auth](https://tools.ietf.org/html/rfc7617).
```
Syntax: token_strategy = string
Default: token_strategy = "header"
```
token_strategy specifies the strategy to use to obtain
the access token from the HTTP request.
Available strategies shipped with REVA can be consulted at the end of this section.
The default strategy is obtain the token from an HTTP header.
```
Syntax: token_writer = string
Default: token_writer = "header"
```
token_writer specifies the strategy to use write the
access token once is obtained to the HTTP response so clients
can re-send it subsequent requests to avoid performing expensive authentication
calls to the authentication service.
Available writer strategies shipped with REVA can be consulted at the end of this section.
The default strategy is write the access token in an HTTP response header.
```
Syntax: token_manager = string
Default: token_manager = "jwt"
```
token_manager specifies the strategy to use verify the access token.
Available token managers shipped with REVA can be consulted at the end of this section.
The default manager is to verify it using JWT.
**The token manager configured for the authentication service and the token manager for
this middleware MUST be the same**.
TODO: skip_methods
## Credential strategies
### Basic Authentication
This strategy obtains the credentials from Basic Auth.
To enable the strategy:
```
[http.middlewares.auth]
credential_strategy = "basic"
```
### OpenID Connect - **Work in Progress**
This strategy obtains the open id connect token as the credentials
that is passed to the authentication service to be verified
agains the configured identity provider public keys.
To enable the strategy:
```
[http.middlewares.auth]
credential_strategy = "oidc"
```
## Token strategies
### Header
This token strategy obtains the access token from an HTTP request header.
To enable the strategy:
```
[http.middlewares.auth]
token_strategy = "header"
```
#### Directives
```
Syntax: header = string
Default: header = ""
```
header specifies header name that contains the token.
## Token writers
### Header
This writer strategy writes the access token to an HTTP response header
specified by tbe **header** directive.
To enable the strategy:
```
[http.middlewares.auth]
token_writer = "header"
[http.middlewares.auth.token_writers.header]
header = "X-Access-Token"
```
#### Directives
```
Syntax: header = string
Default: header = ""
```
header specifies header name to use to write the token.
## Token managers
### JWT
This token manager verifies the token using the JWT shared secret.
To enable the strategy:
```
[http.middlewares.auth]
token_manager = "jwt"
[http.middlewares.auth.token_managers.jwt]
secret = "bar"
```
#### Directives
```
Syntax: secret = string
Default: secret = ""
```
secret specifies the shared secret to verify the JWT token.

View File

@ -1,23 +0,0 @@
# HTTP Middleware: cors
The cors middleware takes care of CORS headers. It is needed to allow authenticating users using oidc, which will make cross origin resource POST requests when using the recommended autorization code flow.
If you hide the idp, phoenix and reva behind a reverse proxy and serve them all from the same domain you may be able to disable it.
To enable the middleware:
```
[http]
enabled_middlewares = ["cors"]
```
Example configuration:
```
[http.middlewares.cors]
allowed_origins = ["*"] # allow requests from everywhere
allowed_methods = ["OPTIONS", "GET", "PUT", "POST", "DELETE", "MKCOL", "PROPFIND", "PROPPATCH", "MOVE", "COPY", "REPORT", "SEARCH"]
allowed_headers = ["Origin", "Accept", "Depth", "Content-Type", "X-Requested-With", "Authorization", "Ocs-Apirequest", "If-None-Match"]
allow_credentials = true
options_passthrough = false
```

View File

@ -1,3 +0,0 @@
# HTTP Middleware: log
The logging middleware is always enabled with the highest priority. It will always receive requests first.

View File

@ -1,40 +0,0 @@
# HTTP Service: helloworld
This service is for demo purposes.
It exposes a single endpoint that renders a
hello message that can be changed in the configuration file.
To enable the service:
```
[http]
enabled_services = ["helloworld"]
```
Example configuration:
```
[http.services.helloworld]
hello_message = "Ola Mundo!"
```
## Directives
```
Syntax: prefix = string
Default: prefix = "helloworld"
```
`prefix` specifies where the service should be exposed.
For example, if the prefix is "myservice", it will be
reachable at http://localhost:9998/myservice
```
Syntax: message = string
Default: message = "Hello World!"
```
`message` defines the message that will be rendered under the
http endpoint configured by the **prefix** directive.

View File

@ -1,52 +0,0 @@
# HTTP Service: ocdav
This service exposes an [ownCloud](https://ownlcloud.org/)
WebDAV endpoint. This service allows ownCloud sync clients to connect
to this endpoint to synchronize files against the configured storage provider.
This service also allows to mount the storage provider using a WebDAV mount
from many operative systems, like Finder for MacOS, Network Drive for Windows or
davfs2 on Linux.
To enable the service:
```
[http]
enabled_services = ["ocdav"]
```
Example configuration:
```
[http.services.ocdav]
prefix = "webdav"
```
## Directives
```
Syntax: prefix = string
Default: prefix = "webdav"
```
prefix specifies where the service should be exposed.
For example, if the prefix is "myservice", it will be
reachable at [http://localhost:9998/myservice](http://localhost:9998/myservice)
```
Syntax: chunk_folder = string
Default: chunk_folder = "/tmp"
```
chunk_folder specifies where file chunks will be stored
on the local filesystem. The default is to use the
system default for a temporary folder (```echo $TMPDIR```).
```
Syntax: storageprovidersvc = string
Default: storageprovidersvc = 0.0.0.0:9999
```
storageprovidersvc specifies the location of the storage provider.
The ocdavsvc service acts as a protocol translator between WebDAV and
the gRPC CS3 API for StorageProvider.

View File

@ -1,29 +0,0 @@
# HTTP Service: prometheus
This service exposes a [Prometheus](https://prometheus.io/)
telemetry endpoint so metrics can be consumed.
To enable the service:
```
[http]
enabled_services = ["prometheus"]
```
Example configuration:
```
[http.services.prometheus]
prefix = "metrics"
```
## Directives
```
Syntax: prefix = string
Default: prefix = "metrics"
```
prefix specifies where the service should be exposed.
For example, if the prefix is "myservice", it will be
reachable at http://localhost:9998/myservice

View File

@ -1,39 +0,0 @@
# Log functionality
Example configuration:
```
[log]
level = "debug"
mode = "json"
output = "/var/log/revad.log"
```
## Directives
```
Syntax: level = string
Default: level = "debug"
```
`level` defines the log level, eg. "debug", "warn", "info"
```
Syntax: output = string
Default: output = "stderr"
```
output sets the output for writting logs. The "stdout" and "stderr" strings have special meaning
as they will set the log output to stdout and stderr respectively. revad will create the filename
specified in the directive if it does not exists. revad does not perform any log rotate logic, this task
is delegated to tools like *logrotate(8)* configured by the system administrator.
```
Syntax: mode = "dev" | "prod"
Default: mode = "dev"
```
mode sets the format for the logs. dev mode sets the output to be consumed by humans on a terminal.
prod mode sets the output format to JSON so it can be parsed by machines and send to central logging systems
like Kibana.

View File

@ -1,51 +0,0 @@
# Controlling REVA
revad can be controlled with signals. The process ID of the master process is written to the file */var/run/revad.pid* by default. This name may be changed with the *-p* flag:
```
-p string
pid file (default "/var/run/revad.pid")
```
The master process supports the following signals:
* TERM, INT: fast shutdown
* QUIT: graceful shutdown
* HUP: changing configuration, starting new process with the new configuration, graceful shutdown of old parent processes
## Changing Configuration
In order for revad to re-read the configuration file, a HUP signal should be sent to the master process.
The master process forks a new child that checks the configuration file for syntax validity,
then tries to apply new configuration, and inherits listening sockets.
If this fails, it kills itself and the parent process continues to work with old configuration.
If this succeeds, the forked child sends a message to old parent process requesting it to shut down gracefully.
Parent process close listening sockets and continue to service old clients.
After all clients are serviced, old process is shut down.
Lets illustrate this by example. Imagine that revad is run on Darwin and the command:
```
ps axw -o pid,user,%cpu,command | egrep '(revad|PID)'
```
produces the following output:
```
PID USER %CPU COMMAND
46011 gonzalhu 0.0 ./revad -c revad.toml -p revad.pid
```
If HUP is sent to the master process, the output becomes:
```
PID USER %CPU COMMAND
46491 gonzalhu 0.0 ./revad -c revad.toml -p revad.pid
```
## Upgrading Executable on the Fly
In order to upgrade the server executable, the new executable file
should be put in place of an old file first. After that, an HUP signal should be
sent to the master process.
The master process run the new executable file that in turn starts a new child process.

View File

@ -1,161 +0,0 @@
# Getting started with REVA
This guide assumes that you have REVA already installed in your system.
## Basic configuration
```
$ echo "" > ~/revad.toml
$ revad -c ~/revad.toml
9:20AM INF dev/reva/cmd/revad/main.go:94 > version= commit= branch= go_version= build_date= build_platform= pid=2177
9:20AM INF dev/reva/cmd/revad/main.go:95 > running on 4 cpus pid=2177
9:20AM INF dev/reva/cmd/revad/main.go:118 > nothing to do, no grpc/http enabled_services declared in config pid=2177
```
An empty configuration will output those lines, stating that no services have been enabled and therefore the program exists.
Let's change the log output format to JSON.
```
$ cat ~/revad.toml
[log]
mode = "json"
```
```
$ revad -c ~/revad.toml
{"level":"info","pid":9355,"time":"2019-10-16T09:22:17+02:00","caller":"/home/gonzalhu/dev/reva/cmd/revad/main.go:94","message":"version= commit= branch= go_version= build_date= build_platform="}
{"level":"info","pid":9355,"time":"2019-10-16T09:22:17+02:00","caller":"/home/gonzalhu/dev/reva/cmd/revad/main.go:95","message":"running on 4 cpus"}
{"level":"info","pid":9355,"time":"2019-10-16T09:22:17+02:00","caller":"/home/gonzalhu/dev/reva/cmd/revad/main.go:118","message":"nothing to do, no grpc/http enabled_services declared in config"}
```
REVA by default will use all the available CPU cores, let's change that to use only 50%:
```
[core]
max_cpus = "50%"
```
```
$ revad -c ~/revad.toml
9:25AM INF dev/reva/cmd/revad/main.go:94 > version= commit= branch= go_version= build_date= build_platform= pid=19783
9:25AM INF dev/reva/cmd/revad/main.go:95 > running on 2 cpus pid=19783
9:25AM INF dev/reva/cmd/revad/main.go:118 > nothing to do, no grpc/http enabled_services declared in config pid=19783
```
## HTTP services
Let's enable the helloworld service:
```
$ cat revad.toml
[http]
enabled_services = ["helloworldsvc"]
```
```
$ revad -c ~/revad.toml
9:27AM INF dev/reva/cmd/revad/main.go:94 > version= commit= branch= go_version= build_date= build_platform= pid=24558
9:27AM INF dev/reva/cmd/revad/main.go:95 > running on 4 cpus pid=24558
9:27AM INF dev/reva/cmd/revad/grace/grace.go:181 > pidfile saved at: /tmp/gonzalhu/revad-ea51bb72-2d20-403e-a7db-73843e530115.pid pid=24558 pkg=grace
9:27AM INF dev/reva/cmd/revad/httpserver/httpserver.go:233 > http service enabled: helloworldsvc@/ pid=24558 pkg=httpserver
9:27AM INF dev/reva/cmd/revad/httpserver/httpserver.go:134 > http server listening at http://localhost:9998 pid=24558 pkg=httpserver
```
When the directive `enabled_services` is declared and the value is not empty, REVA will start an HTTP server with the declared services, in this case, the helloworld service.
When REVA starts it will create a PID (process ID file), that will contain the PID of the REVA process, this file is needed to do reloads of the service as explained in [Controlling REVA](/controlling-reva.md). If no `-p flag` is specified, REVA will create the PID file in the operating system temporary directory, in this example: `/tmp/gonzalhu/revad-ea51bb72-2d20-403e-a7db-73843e530115.pid`.
The line `http service enabled: helloworldsvc@/` indicated that the helloworld service has been enabled and it can be reach at the root URL (`/`).
We can `curl` this endpoint:
```
$ curl http://localhost:9998
Hello World!
```
In the log lines of the server we see the result of the HTTP request:
```
9:34AM INF dev/reva/cmd/revad/svcs/httpsvcs/handlers/log/log.go:112 > http end="16/Oct/2019:09:34:11 +0200" host=127.0.0.1 method=GET pid=13968 pkg=httpserver proto=HTTP/1.1 size=12 start="16/Oct/2019:09:34:11 +0200" status=200 time_ns=67614 traceid=af56a393712698d362b0939b2caabb72 uri=/ url=/
```
The helloworld service allows to change the message being returned with the `message` directive:
```
$ cat revad.toml
[http]
enabled_services = ["helloworldsvc"]
[http.services.helloworldsvc]
message = "Ola Mundo!"
```
## GRPC services
REVA offers the possibility to expose GRPC services, let's do an example with the GRPC helloworld service:
```
$ cat ~/revad.toml
[grpc]
enable_reflection = true # needed to query GRPC services dynamically without having the protobuf definitions.
enabled_services = ["helloworldsvc"]
```
```
$ revad -c ~/revad.toml
9:44AM INF dev/reva/cmd/revad/main.go:94 > version= commit= branch= go_version= build_date= build_platform= pid=13514
9:44AM INF dev/reva/cmd/revad/main.go:95 > running on 4 cpus pid=13514
9:44AM INF dev/reva/cmd/revad/grace/grace.go:181 > pidfile saved at: /tmp/gonzalhu/revad-68d20c91-1d3a-4e1c-a2a3-e9216e2f63d5.pid pid=13514 pkg=grace
9:44AM INF dev/reva/cmd/revad/grpcserver/grpcserver.go:177 > grpc service enabled: helloworldsvc pid=13514 pkg=grpcserver
9:44AM INF dev/reva/cmd/revad/grpcserver/grpcserver.go:141 > grpc server listening at tcp:0.0.0.0:9999 pid=13514 pkg=grpcserver
```
To query the GRPC endpoint we need another tool, we'll use [grpcurl](https://github.com/fullstorydev/grpcurl), make sure you have it installed.
We can list the available services:
```
$ grpcurl -plaintext localhost:9999 list
grpc.reflection.v1alpha.ServerReflection
revad.helloworld.HelloWorldService
```
And we can ask the server the available methods for a service:
```
$ grpcurl -plaintext localhost:9999 describe revad.helloworld.HelloWorldService
revad.helloworld.HelloWorldService is a service:
service HelloWorldService {
rpc Hello ( .revad.helloworld.HelloRequest ) returns ( .revad.helloworld.HelloResponse );
}
```
Let's query the method:
```
$ grpcurl -plaintext localhost:9999 'revad.helloworld.HelloWorldService/Hello'
{
"message": "Hello Mr. Nobody"
}
```
The HelloWorldService accepts a message for its Hello method:
```
$ grpcurl -plaintext localhost:9999 describe revad.helloworld.HelloRequest
revad.helloworld.HelloRequest is a message:
message HelloRequest {
string name = 1;
}
```
```
$ grpcurl -plaintext -d '{"name": "Alice"}' localhost:9999 'revad.helloworld.HelloWorldService/Hello'
{
"message": "Hello Alice"
}
```

View File

@ -1,7 +0,0 @@
# Installing REVA
REVA is written in Go and is shipped as a statically compiled single binary.
Releases are available in the [Releases](https://github.com/cs3org/reva/releases) page.
REVA can also be compiled from source files. While more flexible, this approach may be complex
for a beginner. For more information, see [Building REVA](./building-reva.md).

View File

@ -1,25 +0,0 @@
[core]
log_file = "stderr"
log_mode = "dev"
max_cpus = "100%"
disable_http = true
[log]
level = "debug"
mode = "console"
[grpc]
network = "tcp"
address = "0.0.0.0:9998"
enabled_services = [
"authsvc"
]
[grpc.services.authsvc]
auth_manager = "oidc"
[grpc.services.authsvc.auth_managers.oidc]
provider = "http://0.0.0.0:10000"
insecure = true
client_id = "phoenix"
client_secret = "foobar"

View File

@ -1,74 +0,0 @@
[core]
max_cpus = "2"
[log]
level = "debug"
[grpc]
network = "tcp"
address = "0.0.0.0:9999"
enabled_services = ["storageprovidersvc", "authsvc", "storageregistrysvc", "preferencessvc", "usershareprovidersvc"]
enabled_interceptors = ["auth"]
[grpc.services.usershareprovidersvc]
driver = "memory"
[grpc.services.storageprovidersvc]
driver = "local"
mount_path = "/"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
# we point to the datagatewaysvc.
data_server_url = "http://localhost:9998/data"
[grpc.services.storageprovidersvc.available_checksums]
md5 = 100
unset = 1000
[grpc.services.storageprovidersvc.drivers.local]
root = "/var/tmp/reva/data"
[grpc.services.authsvc]
auth_manager = "demo"
token_manager = "jwt"
user_manager = "demo"
[grpc.services.authsvc.token_managers.jwt]
secret = "Pive-Fumkiu4"
[grpc.services.storageregistrysvc]
driver = "static"
[grpc.services.storageregistrysvc.drivers.static.rules]
"/" = "localhost:9999"
"123e4567-e89b-12d3-a456-426655440000" = "localhost:9999"
[grpc.interceptors.auth]
token_manager = "jwt"
skip_methods = ["/cs3.authv0alpha.AuthService/GenerateAccessToken", "/cs3.authv0alpha.AuthService/WhoAmI"]
[grpc.interceptors.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
[http]
address = "0.0.0.0:9998"
enabled_services = ["datasvc"]
enabled_middlewares = ["auth"]
[http.middlewares.auth]
gatewaysvc = "0.0.0.0:9999"
credential_strategy = "basic"
token_strategy = "header"
token_writer = "header"
token_manager = "jwt"
skip_methods = ["/owncloud/status.php", "/metrics"]
[http.middlewares.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
[http.services.datasvc]
driver = "local"
prefix = "data"
temp_folder = "/var/tmp/"
[http.services.datasvc.drivers.local]
root = "/var/tmp/reva/data"

View File

@ -1,30 +0,0 @@
# This oidc-provider.toml config starts an authprovider that uses the oidc introspection endpoint to authenticate requests
# See https://tools.ietf.org/html/rfc7662 for the spec
[core]
log_file = "stderr"
log_mode = "dev"
max_cpus = "100%"
disable_http = true
[log]
level = "debug"
mode = "console"
[grpc]
address = "0.0.0.0:9998"
enabled_services = [
"authprovider"
]
[grpc.services.authprovider]
auth_manager = "oidc"
userprovidersvc = "http://localhost:10000"
[grpc.services.authprovider.auth_managers.oidc]
provider = "http://localhost:10000"
insecure = true
# credentials used for the introspection endpoint with basic auth
# also rate limit the endpoint: https://tools.ietf.org/html/rfc7662#section-4
# TODO(jfd) introduce rate limits
client_id = "reva"
client_secret = "foobar"

View File

@ -1,18 +0,0 @@
{
"__doc": "install https://github.com/owncloud/ocis-phoenix, then run this with `./ocis-phoenix-testing-linux-amd64 server --http-addr localhost:8300 --config-file phoenix.oidc.config.json --log-level debug`",
"server": "http://localhost:10000",
"theme": "owncloud",
"version": "0.1.0",
"openIdConnect": {
"metadataUrl": "http://localhost:10000/.well-known/openid-configuration",
"authority": "http://localhost:10000",
"client_id": "phoenix",
"response_type": "code",
"scope": "openid profile email"
},
"apps": [
"files",
"markdown-editor",
"pdf-viewer"
]
}

View File

@ -1,10 +1,14 @@
[shared]
jwt_secret = "Pive-Fumkiu4"
gatewaysvc = "localhost:19000"
# This frontend.toml config file will start a reva service that:
# - serves as the entrypoint for owncloud APIs.
# - serves http endpoints on port 20080
# - /owncloud - ocdav
# - /ocs - ocs
# - /oauth2 - oidcprovider
# - /.well-known - wellknown service to announce openid-configuration
# - / --------------- ocdav
# - /ocs ------------ ocs
# - /oauth2 --------- oidcprovider
# - /.well-known ---- wellknown service to announce openid-configuration
# - TODO(diocas): ocm
# - authenticates requests using oidc bearer auth and basic auth as fallback
# - serves the grpc services on port 18002
@ -14,74 +18,26 @@ address = "0.0.0.0:20099"
[grpc.services.authprovider]
auth_manager = "oidc"
[grpc.services.authprovider.auth_managers.oidc]
# If you want to use your own openid provider change this config
[grpc.services.authprovider.auth_managers.oidc]
issuer = "http://localhost:20080"
[grpc.interceptors.auth]
token_manager = "jwt"
[grpc.interceptors.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
[http]
address = "0.0.0.0:20080"
[http.middlewares.auth]
gateway = "localhost:19000"
credential_chain = ["basic", "bearer"]
token_strategy = "header"
token_writer = "header"
token_manager = "jwt"
[http.middlewares.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
[http.middlewares.cors]
allowed_origins = ["*"]
allowed_methods = [
"OPTIONS",
"GET",
"PUT",
"POST",
"DELETE",
"MKCOL",
"PROPFIND",
"PROPPATCH",
"MOVE",
"COPY",
"REPORT",
"SEARCH"
]
allowed_headers = [
"Origin",
"Accept",
"Depth",
"Content-Type",
"X-Requested-With",
"Authorization",
"Ocs-Apirequest",
"If-Match",
"If-None-Match",
"Destination",
"Overwrite"
]
allow_credentials = true
options_passthrough = false
[http.services.wellknown]
issuer = "http://localhost:20080"
authorization_endpoint = "http://localhost:20080/oauth2/auth"
token_endpoint = "http://localhost:20080/oauth2/token"
#jwks_uri = ""
revocation_endpoint = "http://localhost:20080/oauth2/auth"
introspection_endpoint = "http://localhost:20080/oauth2/introspect"
userinfo_endpoint = "http://localhost:20080/oauth2/userinfo"
#end_session_endpoint =
[http.services.oidcprovider]
prefix = "oauth2"
gateway = "localhost:19000"
issuer = "http://localhost:20080"
[http.services.oidcprovider.clients.phoenix]
@ -95,16 +51,14 @@ public = true # force PKCS for public clients
[http.services.ocdav]
# serve ocdav on the root path
prefix = ""
chunk_folder = "/var/tmp/revad/chunks"
chunk_folder = "/var/tmp/reva/chunks"
# for user lookups
gateway = "localhost:19000"
# prefix the path of requests to /dav/files with this namespace
# While owncloud has only listed usernames at this endpoint CERN has
# been exposing more than just usernames. For owncloud deployments we
# can prefix the path to jail the requests to the correct CS3 namespace.
# In this deployment we mounted the owncloud storage provider at /oc. It
# expects a username as the first path segment.
files_namespace = "/"
# currently, only the desktop client will use this endpoint, but only if
# the dav.chunking capability is available
# TODO implement a path wrapper that rewrites `<username>` into the path
@ -113,10 +67,10 @@ files_namespace = "/"
# for eos we need to rewrite the path
# TODO strip the username from the path so the CS3 namespace can be mounted
# at the files/<username> endpoint? what about migration? separate reva instance
files_namespace = "/oc"
# similar to the dav/files endpoint we can configure a prefix for the old webdav endpoint
# we use the old webdav endpoint to present the cs3 namespace
webdav_namespace = "/"
# note: this changes the tree that is rendered at remote.php/webdav from the users home to the cs3 namespace
# use webdav_namespace = "/home" to use the old namespace that only exposes the users files
# this endpoint should not affect the desktop client sync but will present different folders for the other clients:
@ -124,12 +78,7 @@ webdav_namespace = "/"
# - the ios ios uses the core.webdav-root capability which points to remote.php/webdav in oc10
# - the oc js sdk is hardcoded to the remote.php/webdav so it will see the new tree
# - TODO android? no sync ... but will see different tree
[http.services.ocs]
# prefix = "ocs"
# for user lookups and sharing
gateway = "localhost:19000"
webdav_namespace = "/home"
# options for the /ocs/v1.php/config endpoint
[http.services.ocs.config]
@ -143,26 +92,31 @@ ssl = "false"
[http.services.ocs.capabilities.capabilities.core]
poll_interval = 60
webdav_root = "remote.php/webdav"
[http.services.ocs.capabilities.capabilities.core.status]
installed = true
maintenance = false
needsDbUpgrade = false
version = "10.0.11.5"
versionstring = "10.0.11"
version = "10.1.0.5"
versionstring = "10.1.0"
edition = "community"
productname = "reva"
hostname = ""
[http.services.ocs.capabilities.capabilities.checksums]
supported_types = ["SHA256"]
preferred_upload_type = "SHA256"
[http.services.ocs.capabilities.capabilities.files]
private_links = false
bigfilechunking = false
blacklisted_files = []
undelete = true
versioning = true
[http.services.ocs.capabilities.capabilities.dav]
chunking = "1.0"
[http.services.ocs.capabilities.capabilities.files_sharing]
api_enabled = true
resharing = true
@ -172,6 +126,7 @@ share_with_group_members_only = true
share_with_membership_groups_only = true
default_permissions = 22
search_min_length = 3
[http.services.ocs.capabilities.capabilities.files_sharing.public]
enabled = true
send_mail = true
@ -179,27 +134,35 @@ social_share = true
upload = true
multiple = true
supports_upload_only = true
[http.services.ocs.capabilities.capabilities.files_sharing.public.password]
enforced = true
[http.services.ocs.capabilities.capabilities.files_sharing.public.password.enforced_for]
read_only = true
read_write = true
upload_only = true
[http.services.ocs.capabilities.capabilities.files_sharing.public.expire_date]
enabled = true
[http.services.ocs.capabilities.capabilities.files_sharing.user]
send_mail = true
[http.services.ocs.capabilities.capabilities.files_sharing.user_enumeration]
enabled = true
group_members_only = true
[http.services.ocs.capabilities.capabilities.files_sharing.federation]
outgoing = true
incoming = true
[http.services.ocs.capabilities.capabilities.notifications]
endpoints = ["list", "get", "delete"]
[http.services.ocs.capabilities.version]
edition = "reva"
major = 10
minor = 0
micro = 11
string = "10.0.11"
minor = 1
micro = 0
string = "10.1.0"

View File

@ -1,3 +1,7 @@
[shared]
jwt_secret = "Pive-Fumkiu4"
gatewaysvc = "localhost:19000"
# This gateway.toml config file will start a reva service that:
# - serves as a gateway for all requests
# - looks up the storageprovider using a storageregistry
@ -8,12 +12,6 @@
[grpc]
address = "0.0.0.0:19000"
[grpc.interceptors.auth]
token_manager = "jwt"
[grpc.interceptors.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
[grpc.services.gateway]
# registries
authregistrysvc = "localhost:19000"
@ -31,55 +29,33 @@ commit_share_to_storage_grant = true
datagateway = "http://localhost:19001/data"
transfer_shared_secret = "replace-me-with-a-transfer-secret" # for direct uploads
transfer_expires = 6 # give it a moment
token_manager = "jwt"
[grpc.services.gateway.token_managers.jwt]
secret = "Pive-Fumkiu4"
#disable_home_creation_on_login = true
[grpc.services.authregistry]
driver = "static"
[grpc.services.authregistry.drivers.static.rules]
# started with the users.toml
basic = "localhost:18000"
# started with the frontend.toml
bearer = "localhost:20099"
basic = "localhost:18000" # started with the users.toml
bearer = "localhost:20099" # started with the frontend.toml
[grpc.services.storageregistry]
driver = "static"
[grpc.services.storageregistry.drivers.static.rules]
# this is the list of namespaces that build the cs3 namespace
# - every storage as mounted in the root
[grpc.services.storageregistry.drivers.static]
home_provider = "/home"
[grpc.services.storageregistry.drivers.static.rules]
# mount a home storage provider that uses a context based path wrapper
# to jail users into their home dir
"/home" = "localhost:12000"
# the home storage cannot be access by fileid, because it is 'virtual'
# check the storage-home.toml. it uses the same storageid, so id based requests are routed to the next storage
# mount a storage provider without a path wrapper for direct access to files
# mount a storage provider without a path wrapper for direct access to users.
"/oc" = "localhost:11000"
"123e4567-e89b-12d3-a456-426655440000" = "localhost:11000"
"/" = "localhost:11100"
"123e4567-e89b-12d3-a456-426655440001" = "localhost:11100"
# another mount point might be "/projects/"
[http]
address = "0.0.0.0:19001"
[http.services.datagateway]
prefix = "data"
gateway = "" # TODO not needed?
transfer_shared_secret = "replace-me-with-a-transfer-secret"
[http.middlewares.auth]
gatewaysvc = "0.0.0.0:19000"
credential_chain = ["basic", "bearer"]
token_strategy = "header"
token_writer = "header"
token_manager = "jwt"
[http.middlewares.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"

View File

@ -1,17 +1,13 @@
[shared]
jwt_secret = "Pive-Fumkiu4"
# GRPC:
# - serves user and public link shares
[grpc]
address = "0.0.0.0:17000"
[grpc.interceptors.auth]
token_manager = "jwt"
[grpc.services.usershareprovider]
driver = "memory"
[grpc.services.publicshareprovider]
driver = "memory"
[grpc.interceptors.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"

View File

@ -1,4 +1,8 @@
# This storage-home.toml config file will start a reva service that:
[shared]
jwt_secret = "Pive-Fumkiu4"
gatewaysvc = "localhost:19000"
# - authenticates grpc storage provider requests using the internal jwt token
# - authenticates http upload and download requests requests using basic auth
# - serves the home storage provider on grpc port 12000
@ -9,55 +13,31 @@
# their home directory
[grpc]
network = "tcp"
address = "0.0.0.0:12000"
[grpc.interceptors.auth]
token_manager = "jwt"
[grpc.interceptors.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
# This is a storage proider that grants direct acces to the wrapped storage
[grpc.services.storageprovider]
driver = "owncloud"
# the context path wrapper reads tho username from the context and prefixes the relative storage path with it
path_wrapper = "context"
mount_path = "/home"
# TODO same storage id as the /oc/ storage provider
# if we have an id, we can directly go to that storage, no need to wrap paths
mount_id = "123e4567-e89b-12d3-a456-426655440000"
# we have a locally running dataprovider
expose_data_server = true
# this is where clients can find it
# the context path wrapper reads tho username from the context and prefixes the relative storage path with it
[grpc.services.storageprovider]
driver = "owncloud"
mount_path = "/home"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
expose_data_server = true
path_wrapper = "context"
data_server_url = "http://localhost:12001/data"
[grpc.services.storageprovider.available_checksums]
md5 = 100
unset = 1000
enable_home_creation = true
[grpc.services.storageprovider.drivers.owncloud]
datadirectory = "/var/tmp/reva/data"
[grpc.services.storageprovider.path_wrappers.context]
prefix = ""
[http]
address = "0.0.0.0:12001"
[http.middlewares.auth]
gatewaysvc = "localhost:19000"
credential_chain = ["basic", "bearer"]
token_strategy = "header"
token_writer = "header"
token_manager = "jwt"
[http.middlewares.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
[http.services.dataprovider]
driver = "owncloud"
prefix = "data"
temp_folder = "/var/tmp/"
[http.services.dataprovider.drivers.owncloud]

View File

@ -1,55 +1,34 @@
# This storage.toml config file will start a reva service that:
[shared]
jwt_secret = "Pive-Fumkiu4"
gatewaysvc = "localhost:19000"
# - authenticates grpc storage provider requests using the internal jwt token
# - authenticates http upload and download requests requests using basic auth
# - serves the storage provider on grpc port 11000
# - serves http dataprovider for this storage on port 11001
# - /data - dataprovider: file up and download
[grpc]
network = "tcp"
address = "0.0.0.0:11000"
[grpc.interceptors.auth]
token_manager = "jwt"
[grpc.interceptors.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
# This is a storage proider that grants direct acces to the wrapped storage
# we have a locally running dataprovider
[grpc.services.storageprovider]
driver = "owncloud"
mount_path = "/oc"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
# we have a locally running dataprovider
expose_data_server = true
# this is where clients can find it
data_server_url = "http://localhost:11001/data"
[grpc.services.storageprovider.available_checksums]
md5 = 100
unset = 1000
[grpc.services.storageprovider.drivers.owncloud]
datadirectory = "/var/tmp/reva/data"
[http]
address = "0.0.0.0:11001"
enabled_services = ["dataprovider"]
enabled_middlewares = ["auth"]
[http.middlewares.auth]
gatewaysvc = "localhost:19000"
credential_chain = ["basic", "bearer"]
token_strategy = "header"
token_writer = "header"
token_manager = "jwt"
[http.middlewares.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
[http.services.dataprovider]
driver = "owncloud"
prefix = "data"
temp_folder = "/var/tmp/"
[http.services.dataprovider.drivers.owncloud]

View File

@ -1,40 +0,0 @@
# This storage-root.toml config file will start a reva service that:
# - authenticates grpc storage provider requests using the internal jwt token
# - serves a root storage provider on grpc port 11100
# it is used to render the root namespace. you need to create a folder
# layout in "/var/tmp/reva/root" that matches the storage registry:
# tree /var/tmp/reva/root should give for this example
# /var/tmp/reva/root
# ├── home
# └── oc
# that will allow you to list the existing namespaces.
# TODO either make the gateway return a proper ListCollection for the root,
# TODO or implement a virtual storage that implements this
[grpc]
network = "tcp"
address = "0.0.0.0:11100"
[grpc.interceptors.auth]
token_manager = "jwt"
[grpc.interceptors.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
# This is a storage proider that grants direct acces to the wrapped storage
[grpc.services.storageprovider]
driver = "local"
mount_path = "/"
# if we have an id, we can directly go to that storage, no need to wrap paths
mount_id = "123e4567-e89b-12d3-a456-426655440001"
[grpc.services.storageprovider.available_checksums]
md5 = 100
unset = 1000
[grpc.services.storageprovider.drivers.local]
root = "/var/tmp/reva/root"
[grpc.services.storageprovider.path_wrappers.context]
prefix = ""

View File

@ -1,16 +1,12 @@
[shared]
jwt_secret = "Pive-Fumkiu4"
# This users.toml config file will start a reva service that:
# - handles user metadata and user preferences
# - serves the grpc services on port 18000
[grpc]
network = "tcp"
address = "0.0.0.0:18000"
[grpc.interceptors.auth]
token_manager = "jwt"
[grpc.interceptors.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
[grpc.services.authprovider]
auth_manager = "json"

View File

@ -1,222 +0,0 @@
# This standalone.oidc.toml config file will start a reva service that:
# - authenticates requests using openid connect
# - serves http requests on port 10000
# - / - ocdav: owncloud webdav api
# - /data - dataprovider: file up and download
# - /oauth2 - an openid connect provider implementation for development
# - /.well-known - used for openid connect discovery
# - /metrics - prometheus: metrics
# - serves grpc requests on port 9999
# - authprovider - provides basic auth
# - storageprovider - handles storage metadata
# - usershareprovider - provides user shares
# - userprovider - provides user matadata (used to look up email, displayname etc after a login)
# - preferences - provides user preferences
# - gateway: to lookup services and authenticate requests
# - authregistry - used by the gateway to look up auth providers
# - storageregistry - used by the gateway to look up storage providers
[core]
max_cpus = "2" # defaults to runtime.NumCPU()
#tracing_enabled = false
#tracing_endpoint = "localhost:6831"
#tracing_collector = "http://localhost:14268/api/traces"
#tracing_service_name = "revad"
[log]
level = "debug"
#mode = "console" # "console" or "json"
#output = "./standalone.log"
[http]
#network = "tcp"
# allow access from any host, not only localhost
address = "0.0.0.0:10000" # "localhost:9998"
enabled_services = ["dataprovider", "ocdav", "prometheus", "wellknown", "oidcprovider", "ocs"]
enabled_middlewares = ["cors", "auth"]
[http.middlewares.auth]
gateway = "localhost:9999"
auth_type = "oidc" # used to look up the authprovider in the authregistry by the gateway
credential_strategy = "oidc"
token_strategy = "header"
token_writer = "header"
token_manager = "jwt"
skip_methods = [
"/favicon.ico",
"/status.php",
"/oauth2",
"/oauth2/auth",
"/oauth2/token",
# TODO protect the introspection endpoint from external requests.
# should only be reachable by internal services, which is why the
# oidc-provider.toml has clientid and secret that are used for a basic auth
"/oauth2/introspect",
"/oauth2/userinfo",
"/oauth2/sessions",
"/.well-known/openid-configuration",
"/metrics"
]
[http.middlewares.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
[http.middlewares.cors]
allowed_origins = ["*"]
allowed_methods = ["OPTIONS", "GET", "PUT", "POST", "DELETE", "MKCOL", "PROPFIND", "PROPPATCH", "MOVE", "COPY", "REPORT", "SEARCH"]
allowed_headers = ["Origin", "Accept", "Depth", "Content-Type", "X-Requested-With", "Authorization", "Ocs-Apirequest", "If-None-Match"]
allow_credentials = true
options_passthrough = false
[http.services.wellknown]
issuer = "http://localhost:10000"
authorization_endpoint = "http://localhost:10000/oauth2/auth"
token_endpoint = "http://localhost:10000/oauth2/token"
#jwks_uri = ""
revocation_endpoint = "http://localhost:10000/oauth2/auth"
introspection_endpoint = "http://localhost:10000/oauth2/introspect"
userinfo_endpoint = "http://localhost:10000/oauth2/userinfo"
#end_session_endpoint =
[http.services.oidcprovider]
prefix = "oauth2"
gateway = "localhost:9999"
auth_type = "basic"
issuer = "http://localhost:10000"
[http.services.oidcprovider.clients.phoenix]
id = "phoenix"
redirect_uris = ["http://localhost:8300/oidc-callback.html", "http://localhost:8300/"]
grant_types = ["implicit", "refresh_token", "authorization_code", "password", "client_credentials"]
response_types = ["code"] # use authorization code flow, see https://developer.okta.com/blog/2019/05/01/is-the-oauth-implicit-flow-dead for details
scopes = ["openid", "profile", "email", "offline"]
public = true # force PKCS for public clients
[http.services.oidcprovider.clients.reva]
id = "reva"
grant_types = ["implicit", "refresh_token", "authorization_code", "password", "client_credentials"]
response_types = ["code"] # use authorization code flow
# private clients can use a secret
client_secret = "$2a$10$IxMdI6d.LIRZPpSfEwNoeu4rY3FhDREsxFJXikcgdRRAStxUlsuEO" # = "foobar"
scopes = ["openid", "profile", "email", "offline"]
# to debug the oidc provider allow https://oidcdebugger.com
[http.services.oidcprovider.clients.oidcdebugger]
id = "oidcdebugger"
redirect_uris = ["https://oidcdebugger.com/debug"]
grant_types = ["implicit", "refresh_token", "authorization_code", "password", "client_credentials"]
response_types = ["id_token token", "code"]
client_secret = "$2a$10$IxMdI6d.LIRZPpSfEwNoeu4rY3FhDREsxFJXikcgdRRAStxUlsuEO" # = "foobar"
scopes = ["openid", "profile", "email", "offline"]
[http.services.dataprovider]
driver = "local"
prefix = "data"
tmp_folder = "/var/tmp/"
[http.services.dataprovider.drivers.local]
root = "/var/tmp/reva/data"
[http.services.ocdav]
prefix = ""
chunk_folder = "/var/tmp/revad/chunks"
gateway = "localhost:9999"
[grpc]
#network = "tcp"
# allow access from any host, not only localhost
address = "0.0.0.0:9999" # "localhost:9999"
enabled_services = [
"authprovider", # provides basic auth
"storageprovider", # handles storage metadata
"usershareprovider", # provides user shares
"userprovider", # provides user matadata (used to look up email, displayname etc after a login)
"preferences", # provides user preferences
"gateway", # to lookup services and authenticate requests
"authregistry", # used by the gateway to look up auth providers
"storageregistry", # used by the gateway to look up storage providers
]
enabled_interceptors = ["auth"]
[grpc.interceptors.auth]
token_manager = "jwt"
#header = "x-access-token"
skip_methods = [
# we need to allow calls that happen during authentication
"/cs3.gateway.v1beta1.GatewayAPI/Authenticate",
"/cs3.gateway.v1beta1.GatewayAPI/WhoAmI",
"/cs3.gateway.v1beta1.GatewayAPI/GetUser",
"/cs3.gateway.v1beta1.GatewayAPI/ListAuthProviders",
"/cs3.auth.registry.v1beta1.RegistryAPI/ListAuthProviders",
"/cs3.auth.registry.v1beta1.RegistryAPI/GetAuthProvider",
"/cs3.auth.provider.v1beta1.ProviderAPI/Authenticate",
"/cs3.identity.user.v1beta1.UserAPI/GetUser",
]
[grpc.interceptors.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
[grpc.services.userprovider]
driver = "json"
[grpc.services.userprovider.drivers.json]
users = "./examples/users.demo.json"
[grpc.services.authregistry]
driver = "static"
[grpc.services.authregistry.drivers.static.rules]
basic = "localhost:9999"
# needs to be started as a second service using the oidc-provider.toml
oidc = "localhost:9998"
[grpc.services.usershareprovider]
driver = "memory"
[grpc.services.storageprovider]
driver = "local"
mount_path = "/"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
data_server_url = "http://localhost:10000/data"
expose_data_server = true
[grpc.services.storageprovider.available_checksums]
md5 = 100
unset = 1000
[grpc.services.storageprovider.drivers.local]
root = "/var/tmp/reva/data"
# cannot be started in the same process because it has to serve the same
# "/cs3.auth.provider.v1beta1.ProviderAPI/Authenticate" request as the oidcprovider
[grpc.services.authprovider]
auth_manager = "json"
userprovidersvc = "localhost:9999"
[grpc.services.authprovider.auth_managers.json]
users = "./examples/users.demo.json"
[grpc.services.storageregistry]
driver = "static"
[grpc.services.storageregistry.drivers.static.rules]
"/" = "localhost:9999"
"123e4567-e89b-12d3-a456-426655440000" = "localhost:9999"
[grpc.services.gateway]
authregistrysvc = "localhost:9999"
storageregistrysvc = "localhost:9999"
appregistrysvc = "localhost:9999"
preferencessvc = "localhost:9999"
usershareprovidersvc = "localhost:9999"
publicshareprovidersvc = "localhost:9999"
ocmshareprovidersvc = "localhost:9999"
userprovidersvc = "localhost:9999"
commit_share_to_storage_grant = true
datagateway = "http://localhost:10000/data"
transfer_shared_secret = "replace-me-with-a-transfer-secret"
transfer_expires = 6 # give it a moment
token_manager = "jwt"
[grpc.services.gateway.token_managers.jwt]
secret = "Pive-Fumkiu4"

View File

@ -1,166 +0,0 @@
# This standalone.toml config file will start a reva service that:
# - authenticates requests using basic auth
# - serves http requests on port 10000
# - /owncloud - ocdav: owncloud webdav api
# - /data - dataprovider: file up and download
# - /metrics - prometheus: metrics
# - serves grpc requests on port 9999
# - authprovider - provides basic auth
# - storageprovider - handles storage metadata
# - usershareprovider - provides user shares
# - userprovider - provides user matadata (used to look up email, displayname etc after a login)
# - preferences - provides user preferences
# - gateway: to lookup services and authenticate requests
# - authregistry - used by the gateway to look up auth providers
# - storageregistry - used by the gateway to look up storage providers
[core]
max_cpus = "2" # defaults to runtime.NumCPU()
#tracing_enabled = false
#tracing_endpoint = "localhost:6831"
#tracing_collector = "http://localhost:14268/api/traces"
#tracing_service_name = "revad"
[log]
level = "debug"
#mode = "console" # "console" or "json"
#output = "./standalone.log"
[http]
#network = "tcp"
# allow access from any host, not only localhost
address = "0.0.0.0:10000" # "localhost:9998"
enabled_services = ["ocdav", "dataprovider", "prometheus"] # []
enabled_middlewares = ["cors", "auth"] # []
[http.middlewares.auth]
gateway = "localhost:9999"
auth_type = "basic" # used to look up the authprovider in the authregistry by the gateway
credential_strategy = "basic"
token_strategy = "header"
token_writer = "header"
token_manager = "jwt"
skip_methods = ["/owncloud/status.php", "/metrics"] # []
[http.middlewares.auth.token_strategies.header]
header = "X-Access-Token"
[http.middlewares.auth.token_writers.header]
header = "X-Access-Token"
[http.middlewares.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
[http.services.dataprovider]
driver = "local"
prefix = "data"
temp_folder = "/var/tmp/"
[http.services.dataprovider.drivers.local]
root = "/var/tmp/reva/data"
[http.services.ocdav]
prefix = "owncloud"
chunk_folder = "/var/tmp/revad/chunks"
gateway = "localhost:9999"
[grpc]
#network = "tcp"
# allow access from any host, not only localhost
address = "0.0.0.0:9999" # "localhost:9999"
enabled_services = [
"authprovider", # provides basic auth
"storageprovider", # handles storage metadata
"usershareprovider", # provides user shares
"userprovider", # provides user matadata (used to look up email, displayname etc after a login)
"preferences", # provides user preferences
"gateway", # to lookup services and authenticate requests
"authregistry", # used by the gateway to look up auth providers
"storageregistry", # used by the gateway to look up storage providers
]
enabled_interceptors = ["auth"]
[grpc.interceptors.auth]
token_manager = "jwt"
#header = "x-access-token"
skip_methods = [
# we need to allow calls that happen during authentication
"/cs3.gateway.v1beta1.GatewayAPI/Authenticate",
"/cs3.gateway.v1beta1.GatewayAPI/WhoAmI",
"/cs3.gateway.v1beta1.GatewayAPI/GetUser",
"/cs3.gateway.v1beta1.GatewayAPI/ListAuthProviders",
"/cs3.auth.registry.v1beta1.RegistryAPI/ListAuthProviders",
"/cs3.auth.registry.v1beta1.RegistryAPI/GetAuthProvider",
"/cs3.auth.provider.v1beta1.ProviderAPI/Authenticate",
"/cs3.identity.user.v1beta1.UserAPI/GetUser",
]
[grpc.interceptors.auth.token_managers.jwt]
secret = "Pive-Fumkiu4"
[grpc.services.usershareprovider]
driver = "memory"
[grpc.services.storageprovider]
driver = "local"
mount_path = "/"
mount_id = "123e4567-e89b-12d3-a456-426655440000"
data_server_url = "http://localhost:10000/data"
# make the gateway return the storageprovider reported by the storageprovider
expose_data_server = true
[grpc.services.storageprovider.available_checksums]
md5 = 100
unset = 1000
[grpc.services.storageprovider.drivers.local]
root = "/var/tmp/reva/data"
# the authprovider handles basic auth
[grpc.services.authprovider]
auth_manager = "json"
userprovidersvc = "localhost:9999"
[grpc.services.authprovider.auth_managers.json]
users = "./examples/users.demo.json"
[grpc.services.authprovider.token_managers.jwt]
secret = "Pive-Fumkiu4"
[grpc.services.userprovider]
driver = "json"
[grpc.services.userprovider.drivers.json]
users = "./examples/users.demo.json"
[grpc.services.authregistry]
driver = "static"
[grpc.services.authregistry.drivers.static.rules]
basic = "localhost:9999"
oidc = "localhost:9998"
[grpc.services.storageregistry]
driver = "static"
[grpc.services.storageregistry.drivers.static.rules]
"/" = "localhost:9999"
"123e4567-e89b-12d3-a456-426655440000" = "localhost:9999"
[grpc.services.gateway]
authregistrysvc = "localhost:9999"
storageregistrysvc = "localhost:9999"
appregistrysvc = "localhost:9999"
preferencessvc = "localhost:9999"
usershareprovidersvc = "localhost:9999"
publicshareprovidersvc = "localhost:9999"
ocmshareprovidersvc = "localhost:9999"
userprovidersvc = "localhost:9999"
commit_share_to_storage_grant = true
datagateway = "http://localhost:10000/data"
transfer_shared_secret = "replace-me-with-a-transfer-secret"
transfer_expires = 6 # give it a moment
token_manager = "jwt"
[grpc.services.gateway.token_managers.jwt]
secret = "Pive-Fumkiu4"

View File

@ -1,35 +0,0 @@
[
{
"id": {
"opaque_id": "4c510ada-c86b-4815-8820-42cdf82c3d51",
"idp": "http://localhost:10000"
},
"username": "einstein",
"secret": "relativity",
"mail": "einstein@example.org",
"display_name": "Albert Einstein",
"groups": ["sailing-lovers", "violin-haters", "physics-lovers"]
},
{
"id": {
"opaque_id": "f7fbf8c8-139b-4376-b307-cf0a8c2d0d9c",
"idp": "http://localhost:10000"
},
"username": "marie",
"secret": "radioactivity",
"mail": "marie@example.org",
"display_name": "Marie Curie",
"groups": ["radium-lovers", "polonium-lovers", "physics-lovers"]
},
{
"id": {
"opaque_id": "932b4540-8d16-481e-8ef4-588e4b6b151c",
"idp": "http://localhost:10000"
},
"username": "richard",
"secret": "superfluidity",
"mail": "richard@example.org",
"display_name": "Richard Feynman",
"groups": ["quantum-lovers", "philosophy-haters", "physics-lovers"]
}
]

View File

@ -1,32 +0,0 @@
[
{
"id": {
"opaque_id": "c6e5995d6c7fa1986b830b78b478e6c2",
"idp": "localhost:10000"
},
"username": "aaliyah_abernathy",
"secret": "secret",
"mail": "aaliyah_abernathy@owncloudqa.com",
"display_name": "Aaliyah Abernathy"
},
{
"id": {
"opaque_id": "9fb5f8d212cbf3fc55f1bf67d97ed05d",
"idp": "localhost:10000"
},
"username": "aaliyah_adams",
"secret": "secret",
"mail": "aaliyah_adams@owncloudqa.com",
"display_name": "Aaliyah Adams"
},
{
"id": {
"opaque_id": "a84075b398fe6a0aee1155f8ead13331",
"idp": "localhost:10000"
},
"username": "aaliyah_anderson",
"secret": "secret",
"mail": "aaliyah_anderson@owncloudqa.com",
"display_name": "Aaliyah Anderson"
}
]

3
go.mod
View File

@ -7,7 +7,7 @@ require (
github.com/aws/aws-sdk-go v1.28.2
github.com/cheggaaa/pb v1.0.28
github.com/coreos/go-oidc v2.1.0+incompatible
github.com/cs3org/go-cs3apis v0.0.0-20191128165347-19746c015c83
github.com/cs3org/go-cs3apis v0.0.0-20200115100126-824a5f718250
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/fatih/color v1.7.0 // indirect
github.com/go-openapi/strfmt v0.19.2 // indirect
@ -24,6 +24,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/pkg/xattr v0.4.1
github.com/pquerna/cachecontrol v0.0.0-20180517163645-1555304b9b35 // indirect
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829 // indirect
github.com/rs/cors v1.7.0
github.com/rs/zerolog v1.17.2
go.opencensus.io v0.22.1

55
go.sum
View File

@ -1,35 +1,19 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
contrib.go.opencensus.io/exporter/jaeger v0.1.0 h1:WNc9HbA38xEQmsI40Tjd/MNU/g8byN2Of7lwIjv0Jdc=
contrib.go.opencensus.io/exporter/jaeger v0.1.0/go.mod h1:VYianECmuFPwU37O699Vc1GOcy+y8kOsfaxHRImmjbA=
contrib.go.opencensus.io/exporter/jaeger v0.2.0 h1:nhTv/Ry3lGmqbJ/JGvCjWxBl5ozRfqo86Ngz59UAlfk=
contrib.go.opencensus.io/exporter/jaeger v0.2.0/go.mod h1:ukdzwIYYHgZ7QYtwVFQUjiT28BJHiMhTERo32s6qVgM=
contrib.go.opencensus.io/exporter/prometheus v0.1.0 h1:SByaIoWwNgMdPSgl5sMqM2KDE5H/ukPWBRo314xiDvg=
contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/apache/thrift v0.12.0 h1:pODnxUFNcjP9UTLZGTdeh+j16A8lJbRvD3rOtrk/7bs=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/aws/aws-sdk-go v1.25.41 h1:/hj7nZ0586wFqpwjNpzWiUTwtaMgxAZNZKHay80MdXw=
github.com/aws/aws-sdk-go v1.25.41/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.26.2 h1:MzYLmCeny4bMQcAbYcucIduVZKp0sEf1eRLvHpKI5Is=
github.com/aws/aws-sdk-go v1.26.2/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.26.3 h1:szQdfJcUBAhQT0zZEx4sxoDuWb7iScoucxCiVxDmaBk=
github.com/aws/aws-sdk-go v1.26.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.26.4 h1:vQ1XmULJriCx8QTmvtEl511rskbZeTkr0xq59ky3kfI=
github.com/aws/aws-sdk-go v1.26.4/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.26.6 h1:LinjO5+t9K/TyrZbSU1BaVJ5wIG3DlX5SffZ32Eg+kU=
github.com/aws/aws-sdk-go v1.26.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.26.7 h1:ObjEnmzvSdYy8KVd3me7v/UMyCn81inLy2SyoIPoBkg=
github.com/aws/aws-sdk-go v1.26.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.28.2 h1:j5IXG9CdyLfcVfICqo1PXVv+rua+QQHbkXuvuU/JF+8=
@ -43,23 +27,22 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM=
github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cs3org/go-cs3apis v0.0.0-20191128165347-19746c015c83 h1:9bcp1jc6+36XUfuOae/w0BVrbzeVKBp/OqhTfCal40U=
github.com/cs3org/go-cs3apis v0.0.0-20191128165347-19746c015c83/go.mod h1:IsVGyZrOLUQD48JIhlM/xb3Vz6He5o2+W0ZTfUGY+IU=
github.com/cs3org/go-cs3apis v0.0.0-20200113082535-e58b99ae8f80 h1:ui+ztsFshmOv1yR3HRPaDRz1J/G6VQLd0ZUaBG33fWU=
github.com/cs3org/go-cs3apis v0.0.0-20200113082535-e58b99ae8f80/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20200113170445-f5790f408edc h1:qY/nHxpK3mJHkmWveEpwQCWHeNBjlDgk+o4t/5QeZM4=
github.com/cs3org/go-cs3apis v0.0.0-20200113170445-f5790f408edc/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/cs3org/go-cs3apis v0.0.0-20200115100126-824a5f718250 h1:N/WWs9OegcgFlsUo7/iahxq+e3luhZKu0B8wLrWBsTQ=
github.com/cs3org/go-cs3apis v0.0.0-20200115100126-824a5f718250/go.mod h1:UXha4TguuB52H14EMoSsCqDj7k8a/t7g4gVP+bgY5LY=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/elazarl/goproxy v0.0.0-20181003060214-f58a169a71a5/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-openapi/errors v0.19.2 h1:a2kIyV3w+OS3S97zxUndRVD46+FhGOUBDFY7nmu4CsY=
@ -71,8 +54,6 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0 h1:xU6/SpYbvkNYiptHJYEDRseDLvYE7wSqhYYNy0QSUzI=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 h1:ZgQEtGgCBiWRM39fZuwSd1LwSqqSW0hOdXCYYDX0R3I=
@ -83,7 +64,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v2.0.0+incompatible h1:K/R+8tc58AaqLkqG2Ol3Qk+DR/TlNuhuh457pBFPtt0=
github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
@ -100,14 +80,12 @@ github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2z
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4 h1:z53tR0945TRRQO/fLEVPI6SMv7ZflF0TEaTAoU7tOzg=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jedib0t/go-pretty v4.3.0+incompatible h1:CGs8AVhEKg/n9YbUenWmNStRW2PHJzaeDodcfvRAbIo=
github.com/jedib0t/go-pretty v4.3.0+incompatible/go.mod h1:XemHduiw8R651AF9Pt4FwCTKeG3oo7hrHJAoznj9nag=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@ -127,11 +105,6 @@ github.com/moul/http2curl v0.0.0-20170919181001-9ac6cf4d929b/go.mod h1:8UbvGypXm
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oleiade/reflections v1.0.0 h1:0ir4pc6v8/PJ0yw5AEtMddfXpWBXg9cnG7SgSoJuCgY=
github.com/oleiade/reflections v1.0.0/go.mod h1:RbATFBbKYkVdqmSFtx13Bb/tVhR0lgOBXunWTZKeL4w=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/openzipkin/zipkin-go v0.1.6 h1:yXiysv1CSK7Q5yjGy1710zZGnsbMUIjluWBxtLXHPBo=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/ory/fosite v0.30.2 h1:1HQZPXQ+PdeIe27H9Fjfvxem5uxVc/diIwUDk5XTEM4=
github.com/ory/fosite v0.30.2/go.mod h1:Lq9qQ9Sl6mcea2Tt8J7PU+wUeFYPZ+vg7N3zPVKGbN8=
github.com/ory/go-convenience v0.1.0 h1:zouLKfF2GoSGnJwGq+PE/nJAE6dj2Zj5QlTgmMTsTS8=
@ -139,7 +112,6 @@ github.com/ory/go-convenience v0.1.0/go.mod h1:uEY/a60PL5c12nYz4V5cHY03IBmwIAEm8
github.com/parnurzeal/gorequest v0.2.15/go.mod h1:3Kh2QUMJoqw3icWAecsyzkpY7UzRfDhbRdTjtNwNiUE=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -170,7 +142,6 @@ github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a h1:9a8MnZMP0X2nL
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1 h1:/K3IL0Z1quvmJ7X0A1AwNEK7CRkVK3YwfOU/QAL4WGg=
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
@ -194,7 +165,6 @@ github.com/uber/jaeger-client-go v2.15.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMW
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
go.mongodb.org/mongo-driver v1.0.3 h1:GKoji1ld3tw2aC+GX1wbr/J2fX13yNacEYoJ8Nhr0yU=
go.mongodb.org/mongo-driver v1.0.3/go.mod h1:u7ryQJ+DOzQmeO7zB6MHyr8jkEQvC8vH7qLUO4lqsUM=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.1 h1:8dP3SGL7MPB94crU3bEPplMPe83FI4EouesJUeFHv50=
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
@ -210,7 +180,6 @@ golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTk
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181005035420-146acd28ed58/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -236,10 +205,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEha
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181021155630-eda9bb28ed51/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190415081028-16da32be82c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -250,7 +217,6 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@ -259,9 +225,6 @@ golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190828213141-aed303cbaa74/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.3.2 h1:iTp+3yyl/KOtxa/d1/JUE0GGSoR6FuW5udver22iwpw=
google.golang.org/api v0.3.2/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0 h1:KKgc1aqhV8wDPbDzlDtpvyjZFY3vjz85FP7p4wcQUyI=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
@ -276,13 +239,10 @@ google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb h1:i1Ppqkc3WQXikh8
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1 h1:wdKvqQk7IttEw92GoRyKG2IDrUIpgpj6H6m81yfeMW0=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0 h1:2dTRdpdFEEhJYQD8EMLB61nnrzSCTbG38PhqdhvOltg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
@ -292,14 +252,11 @@ gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUy
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.27 h1:kJdccidYzt3CaHD1crCFTS1hxyhSi059NhOFUf03YFo=
gopkg.in/cheggaaa/pb.v1 v1.0.27/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ldap.v2 v2.5.1 h1:wiu0okdNfjlBzg6UWvd1Hn8Y+Ux17/u/4nlk4CQr6tU=
gopkg.in/ldap.v2 v2.5.1/go.mod h1:oI0cpe/D7HRtBQl8aTg+ZmzFUAvu4lsv3eLXMLGFxWk=
gopkg.in/square/go-jose.v2 v2.1.9/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/square/go-jose.v2 v2.2.2 h1:orlkJ3myw8CN1nVQHBFfloD+L3egixIa4FvUP6RosSA=
gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@ -36,14 +36,9 @@ import (
"google.golang.org/grpc/status"
)
const (
defaultHeader = "x-access-token"
)
type config struct {
// TODO(labkode): access a map is more performant as uri as fixed in length
// for SkipMethods.
Header string `mapstructure:"header"`
TokenManager string `mapstructure:"token_manager"`
TokenManagers map[string]map[string]interface{} `mapstructure:"token_managers"`
}
@ -66,14 +61,10 @@ func NewUnary(m map[string]interface{}, unprotected []string) (grpc.UnaryServerI
return nil, err
}
if conf.Header == "" {
conf.Header = defaultHeader
if conf.TokenManager == "" {
conf.TokenManager = "jwt"
}
if conf.TokenManager == "" {
err := errors.New("auth: token manager is not configured for interceptor")
return nil, err
}
h, ok := tokenmgr.NewFuncs[conf.TokenManager]
if !ok {
return nil, errors.New("auth: token manager does not exist: " + conf.TokenManager)
@ -97,10 +88,10 @@ func NewUnary(m map[string]interface{}, unprotected []string) (grpc.UnaryServerI
span.AddAttributes(trace.BoolAttribute("auth_enabled", true))
tkn, _ := token.ContextGetToken(ctx)
tkn, ok := token.ContextGetToken(ctx)
if tkn == "" {
log.Warn().Msg("access token not found")
if !ok || tkn == "" {
log.Warn().Msg("access token not found or empty")
return nil, status.Errorf(codes.Unauthenticated, "auth: core access token not found")
}
@ -134,8 +125,8 @@ func NewStream(m map[string]interface{}, unprotected []string) (grpc.StreamServe
return nil, err
}
if conf.Header == "" {
conf.Header = defaultHeader
if conf.TokenManager == "" {
conf.TokenManager = "jwt"
}
h, ok := tokenmgr.NewFuncs[conf.TokenManager]
@ -157,9 +148,9 @@ func NewStream(m map[string]interface{}, unprotected []string) (grpc.StreamServe
return handler(srv, ss)
}
tkn, _ := token.ContextGetToken(ctx)
tkn, ok := token.ContextGetToken(ctx)
if tkn == "" {
if !ok || tkn == "" {
log.Warn().Msg("access token not found")
return status.Errorf(codes.Unauthenticated, "auth: core access token not found")
}

View File

@ -26,24 +26,21 @@ import (
"google.golang.org/grpc/metadata"
)
const defaultHeader = "x-access-token"
// NewUnary returns a new unary interceptor that adds
// the token to the context.
func NewUnary() grpc.UnaryServerInterceptor {
interceptor := func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
var tkn string
md, ok := metadata.FromIncomingContext(ctx)
if ok && md != nil {
if val, ok := md[defaultHeader]; ok {
if val, ok := md[token.TokenHeader]; ok {
if len(val) > 0 && val[0] != "" {
tkn = val[0]
tkn := val[0]
ctx = token.ContextSetToken(ctx, tkn)
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, tkn)
}
}
}
ctx = metadata.AppendToOutgoingContext(ctx, defaultHeader, tkn)
ctx = token.ContextSetToken(ctx, tkn)
return handler(ctx, req)
}
return interceptor
@ -55,18 +52,17 @@ func NewStream() grpc.StreamServerInterceptor {
interceptor := func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
ctx := ss.Context()
var tkn string
md, ok := metadata.FromIncomingContext(ss.Context())
if ok && md != nil {
if val, ok := md[defaultHeader]; ok {
if val, ok := md[token.TokenHeader]; ok {
if len(val) > 0 && val[0] != "" {
tkn = val[0]
tkn := val[0]
ctx = token.ContextSetToken(ctx, tkn)
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, tkn)
}
}
}
ctx = metadata.AppendToOutgoingContext(ctx, defaultHeader, tkn)
ctx = token.ContextSetToken(ctx, tkn)
wrapped := newWrappedServerStream(ctx, ss)
return handler(srv, wrapped)
}

View File

@ -25,11 +25,14 @@ import (
registry "github.com/cs3org/go-cs3apis/cs3/auth/registry/v1beta1"
gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
storageprovider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/rgrpc/status"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
tokenpkg "github.com/cs3org/reva/pkg/token"
"github.com/pkg/errors"
"google.golang.org/grpc/metadata"
)
func (s *svc) Authenticate(ctx context.Context, req *gateway.AuthenticateRequest) (*gateway.AuthenticateResponse, error) {
@ -82,39 +85,6 @@ func (s *svc) Authenticate(ctx context.Context, req *gateway.AuthenticateRequest
}, nil
}
// TODO(labkode): we don't ned to call the user manager in the auth phase
// as the auth must provide a valid user. The mapping between user credentials and
// unique claims is done at the Authenticate logic an not here.
/*
userClient, err := pool.GetUserProviderServiceClient(s.c.UserProviderEndpoint)
if err != nil {
log.Err(err).Msg("error getting user provider client")
return &gateway.AuthenticateResponse{
Status: status.NewInternal(ctx, err, "error getting user provider service client"),
}, nil
}
getUserReq := &user.GetUserRequest{
UserId: uid,
}
getUserRes, err := userClient.GetUser(ctx, getUserReq)
if err != nil {
err = errors.Wrap(err, "authsvc: error in GetUser")
res := &gateway.AuthenticateResponse{
Status: status.NewUnauthenticated(ctx, err, "error getting user information"),
}
return res, nil
}
if getUserRes.Status.Code != rpc.Code_CODE_OK {
err := status.NewErrorFromCode(getUserRes.Status.Code, "authsvc")
return &gateway.AuthenticateResponse{
Status: status.NewUnauthenticated(ctx, err, "error getting user information"),
}, nil
}
*/
user := res.User
token, err := s.tokenmgr.MintToken(ctx, user)
@ -126,6 +96,38 @@ func (s *svc) Authenticate(ctx context.Context, req *gateway.AuthenticateRequest
return res, nil
}
if s.c.DisableHomeCreationOnLogin {
gwRes := &gateway.AuthenticateResponse{
Status: status.NewOK(ctx),
User: res.User,
Token: token,
}
return gwRes, nil
}
// we need to pass the token to authenticate the CreateHome request.
// TODO(labkode): appending to existing context will not pass the token.
ctx = tokenpkg.ContextSetToken(ctx, token)
ctx = metadata.AppendToOutgoingContext(ctx, tokenpkg.TokenHeader, token) // TODO(jfd): hardcoded metadata key. use PerRPCCredentials?
// create home directory
createHomeReq := &storageprovider.CreateHomeRequest{}
createHomeRes, err := s.CreateHome(ctx, createHomeReq)
if err != nil {
log.Err(err).Msg("error calling CreateHome")
return &gateway.AuthenticateResponse{
Status: status.NewInternal(ctx, err, "error creating user home"),
}, nil
}
if createHomeRes.Status.Code != rpc.Code_CODE_OK {
err := status.NewErrorFromCode(createHomeRes.Status.Code, "gateway")
log.Err(err).Msg("error calling Createhome")
return &gateway.AuthenticateResponse{
Status: status.NewInternal(ctx, err, "error creating user home"),
}, nil
}
gwRes := &gateway.AuthenticateResponse{
Status: status.NewOK(ctx),
User: res.User,

View File

@ -47,6 +47,7 @@ type config struct {
UserProviderEndpoint string `mapstructure:"userprovidersvc"`
CommitShareToStorageGrant bool `mapstructure:"commit_share_to_storage_grant"`
CommitShareToStorageRef bool `mapstructure:"commit_share_to_storage_ref"`
DisableHomeCreationOnLogin bool `mapstructure:"disable_home_creation_on_login"`
DataGatewayEndpoint string `mapstructure:"datagateway"`
TransferSharedSecret string `mapstructure:"transfer_shared_secret"`
TranserExpires int64 `mapstructure:"transfer_expires"`
@ -71,6 +72,15 @@ func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) {
return nil, err
}
// set defaults
if c.ShareFolder == "" {
c.ShareFolder = "shares"
}
if c.TokenManager == "" {
c.TokenManager = "jwt"
}
// ensure DataGatewayEndpoint is a valid URI
if c.DataGatewayEndpoint == "" {
return nil, errors.New("datagateway is not defined")

View File

@ -27,6 +27,7 @@ import (
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/rgrpc/status"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
@ -65,20 +66,90 @@ func (s *svc) sign(ctx context.Context, target string) (string, error) {
return tkn, nil
}
func (s *svc) GetHome(ctx context.Context, ref *registry.GetHomeRequest) (*registry.GetHomeResponse, error) {
func (s *svc) CreateHome(ctx context.Context, req *provider.CreateHomeRequest) (*provider.CreateHomeResponse, error) {
log := appctx.GetLogger(ctx)
homeReq := &provider.GetHomeRequest{}
homeRes, err := s.GetHome(ctx, homeReq)
if err != nil {
log.Err(err).Msgf("gateway: error calling GetHome")
return &provider.CreateHomeResponse{
Status: status.NewInternal(ctx, err, "error creating home"),
}, nil
}
if homeRes.Status.Code != rpc.Code_CODE_OK {
err := status.NewErrorFromCode(homeRes.Status.Code, "gateway")
log.Err(err).Msg("gateway: bad grpc code")
return &provider.CreateHomeResponse{
Status: status.NewInternal(ctx, err, "error calling GetHome"),
}, nil
}
c, err := s.findByPath(ctx, homeRes.Path)
if err != nil {
log.Err(err).Msg("gateway: error finding storage provider")
if _, ok := err.(errtypes.IsNotFound); ok {
return &provider.CreateHomeResponse{
Status: status.NewNotFound(ctx, "storage provider not found"),
}, nil
}
return &provider.CreateHomeResponse{
Status: status.NewInternal(ctx, err, "error finding storage provider"),
}, nil
}
res, err := c.CreateHome(ctx, req)
if err != nil {
log.Err(err).Msg("gateway: error creating home on storage provider")
return &provider.CreateHomeResponse{
Status: status.NewInternal(ctx, err, "error calling CreateHome"),
}, nil
}
return res, nil
}
func (s *svc) GetHome(ctx context.Context, req *provider.GetHomeRequest) (*provider.GetHomeResponse, error) {
c, err := pool.GetStorageRegistryClient(s.c.StorageRegistryEndpoint)
if err != nil {
err = errors.Wrap(err, "gateway: error getting storage registry client")
return nil, err
return &provider.GetHomeResponse{
Status: status.NewInternal(ctx, err, "error finding storage registry"),
}, nil
}
res, err := c.GetHome(ctx, &registry.GetHomeRequest{})
if err != nil {
err = errors.Wrap(err, "gateway: error calling GetHome")
return nil, err
return &provider.GetHomeResponse{
Status: status.NewInternal(ctx, err, "error calling GetHome"),
}, nil
}
return res, nil
if res.Status.Code != rpc.Code_CODE_OK {
err := status.NewErrorFromCode(res.Status.Code, "gateway")
return &provider.GetHomeResponse{
Status: status.NewInternal(ctx, err, "error calling GetHome"),
}, nil
}
storageClient, err := pool.GetStorageProviderServiceClient(res.Provider.Address)
if err != nil {
err = errors.Wrap(err, "gateway: error getting storage provider client")
return &provider.GetHomeResponse{
Status: status.NewInternal(ctx, err, "error getting home"),
}, nil
}
homeRes, err := storageClient.GetHome(ctx, req)
if err != nil {
err = errors.Wrap(err, "gateway: error getting GetHome from storage provider")
return &provider.GetHomeResponse{
Status: status.NewInternal(ctx, err, "error getting home"),
}, nil
}
return homeRes, nil
}
func (s *svc) InitiateFileDownload(ctx context.Context, req *provider.InitiateFileDownloadRequest) (*gateway.InitiateFileDownloadResponse, error) {

View File

@ -26,7 +26,6 @@ import (
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
collaboration "github.com/cs3org/go-cs3apis/cs3/sharing/collaboration/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/rgrpc/status"
@ -389,19 +388,8 @@ func (s *svc) UpdateReceivedShare(ctx context.Context, req *collaboration.Update
share := getShareRes.Share
// get user home
storageRegClient, err := pool.GetStorageRegistryClient(s.c.StorageRegistryEndpoint)
if err != nil {
log.Err(err).Msg("gateway: error getting storage registry client")
return &collaboration.UpdateReceivedShareResponse{
Status: &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
},
}, nil
}
homeReq := &registry.GetHomeRequest{}
homeRes, err := storageRegClient.GetHome(ctx, homeReq)
homeReq := &provider.GetHomeRequest{}
homeRes, err := s.GetHome(ctx, homeReq)
if err != nil {
err := errors.Wrap(err, "gateway: error calling GetHome")
return &collaboration.UpdateReceivedShareResponse{
@ -410,8 +398,6 @@ func (s *svc) UpdateReceivedShare(ctx context.Context, req *collaboration.Update
}
// reference path is the home path + some name
// TODO(labkode): where shares should be created, here we can define the folder in the gateway
// so the target path on the home storage provider will be:
// CreateReferene(cs3://home/shares/x)
// CreateReference(cs3://eos/user/g/gonzalhu/.shares/x)
// CreateReference(cs3://eos/user/.hidden/g/gonzalhu/shares/x)
@ -421,9 +407,12 @@ func (s *svc) UpdateReceivedShare(ctx context.Context, req *collaboration.Update
// It is the responsibility of the gateway to resolve these references and merge the response back
// from the main request.
// TODO(labkode): the name of the share should be the filename it points to by default.
refPath := path.Join(homeRes.Path, req.Ref.String())
// TODO(labkode): create share folder if it does not exist. Maybe at home directory creation time (login)?
refPath := path.Join(homeRes.Path, s.c.ShareFolder, req.Ref.String())
createRefReq := &provider.CreateReferenceRequest{
Path: refPath,
Path: refPath,
// cs3 is the Scheme and %s/%s is the Opaque parts of a net.URL.
TargetUri: fmt.Sprintf("cs3:%s/%s", share.Share.ResourceId.GetStorageId(), share.Share.ResourceId.GetOpaqueId()),
}

View File

@ -46,16 +46,17 @@ func init() {
}
type config struct {
MountPath string `mapstructure:"mount_path"`
MountID string `mapstructure:"mount_id"`
Driver string `mapstructure:"driver"`
Drivers map[string]map[string]interface{} `mapstructure:"drivers"`
PathWrapper string `mapstructure:"path_wrapper"`
PathWrappers map[string]map[string]interface{} `mapstructure:"path_wrappers"`
TmpFolder string `mapstructure:"tmp_folder"`
DataServerURL string `mapstructure:"data_server_url"`
ExposeDataServer bool `mapstructure:"expose_data_server"` // if true the client will be able to upload/download directly to it
AvailableXS map[string]uint32 `mapstructure:"available_checksums"`
MountPath string `mapstructure:"mount_path"`
MountID string `mapstructure:"mount_id"`
Driver string `mapstructure:"driver"`
Drivers map[string]map[string]interface{} `mapstructure:"drivers"`
PathWrapper string `mapstructure:"path_wrapper"`
PathWrappers map[string]map[string]interface{} `mapstructure:"path_wrappers"`
TmpFolder string `mapstructure:"tmp_folder"`
DataServerURL string `mapstructure:"data_server_url"`
ExposeDataServer bool `mapstructure:"expose_data_server"` // if true the client will be able to upload/download directly to it
EnableHomeCreation bool `mapstructure:"enable_home_creation"`
AvailableXS map[string]uint32 `mapstructure:"available_checksums"`
}
type service struct {
@ -111,6 +112,11 @@ func New(m map[string]interface{}, ss *grpc.Server) (rgrpc.Service, error) {
return nil, err
}
// set sane defaults
if len(c.AvailableXS) == 0 {
c.AvailableXS = map[string]uint32{"md5": 100, "unset": 1000}
}
// use os temporary folder if empty
tmpFolder := c.TmpFolder
if tmpFolder == "" {
@ -282,6 +288,50 @@ func (s *service) GetPath(ctx context.Context, req *provider.GetPathRequest) (*p
return res, nil
}
func (s *service) GetHome(ctx context.Context, req *provider.GetHomeRequest) (*provider.GetHomeResponse, error) {
home, err := s.storage.GetHome(ctx)
if err != nil {
st := status.NewInternal(ctx, err, "error getting home")
return &provider.GetHomeResponse{
Status: st,
}, nil
}
home = path.Join(s.mountPath, home)
res := &provider.GetHomeResponse{
Status: status.NewOK(ctx),
Path: home,
}
return res, nil
}
func (s *service) CreateHome(ctx context.Context, req *provider.CreateHomeRequest) (*provider.CreateHomeResponse, error) {
log := appctx.GetLogger(ctx)
if !s.conf.EnableHomeCreation {
err := errtypes.NotSupported("storageprovider: create home directories not enabled")
log.Err(err).Msg("storageprovider: home creation is disabled")
st := status.NewUnimplemented(ctx, err, "creating home directories is disabled by configuration")
return &provider.CreateHomeResponse{
Status: st,
}, nil
}
if err := s.storage.CreateHome(ctx); err != nil {
st := status.NewInternal(ctx, err, "error creating home")
log.Err(err).Msg("storageprovider: error calling CreateHome of storage driver")
return &provider.CreateHomeResponse{
Status: st,
}, nil
}
res := &provider.CreateHomeResponse{
Status: status.NewOK(ctx),
}
return res, nil
}
func (s *service) CreateContainer(ctx context.Context, req *provider.CreateContainerRequest) (*provider.CreateContainerResponse, error) {
newRef, err := s.unwrap(ctx, req.Ref)
if err != nil {

View File

@ -140,8 +140,8 @@ func (s *service) GetHome(ctx context.Context, req *registrypb.GetHomeRequest) (
}
res := &registrypb.GetHomeResponse{
Status: status.NewOK(ctx),
Path: p,
Status: status.NewOK(ctx),
Provider: p,
}
return res, nil
}

View File

@ -33,6 +33,7 @@ import (
"github.com/cs3org/reva/pkg/rgrpc/status"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/rhttp/global"
"github.com/cs3org/reva/pkg/sharedconf"
"github.com/cs3org/reva/pkg/token"
tokenmgr "github.com/cs3org/reva/pkg/token/manager/registry"
"github.com/cs3org/reva/pkg/user"
@ -42,13 +43,9 @@ import (
"google.golang.org/grpc/metadata"
)
const (
defaultHeader = "x-access-token"
)
type config struct {
Priority int `mapstructure:"priority"`
GatewaySvc string `mapstructure:"gateway"`
GatewaySvc string `mapstructure:"gatewaysvc"`
// TODO(jdf): Realm is optional, will be filled with request host if not given?
Realm string `mapstructure:"realm"`
CredentialChain []string `mapstructure:"credential_chain"`
@ -77,6 +74,25 @@ func New(m map[string]interface{}, unprotected []string) (global.Middleware, err
return nil, err
}
conf.GatewaySvc = sharedconf.GetGatewaySVC(conf.GatewaySvc)
// set defaults
if conf.TokenStrategy == "" {
conf.TokenStrategy = "header"
}
if conf.TokenWriter == "" {
conf.TokenWriter = "header"
}
if conf.TokenManager == "" {
conf.TokenManager = "jwt"
}
if len(conf.CredentialChain) == 0 {
conf.CredentialChain = []string{"basic", "bearer"}
}
credChain := []auth.CredentialStrategy{}
for i := range conf.CredentialChain {
f, ok := registry.NewCredentialFuncs[conf.CredentialChain[i]]
@ -224,7 +240,7 @@ func New(m map[string]interface{}, unprotected []string) (global.Middleware, err
// store user and core access token in context.
ctx = user.ContextSetUser(ctx, u)
ctx = token.ContextSetToken(ctx, tkn)
ctx = metadata.AppendToOutgoingContext(ctx, defaultHeader, tkn) // TODO(jfd): hardcoded metadata key. use PerRPCCredentials?
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, tkn) // TODO(jfd): hardcoded metadata key. use PerRPCCredentials?
r = r.WithContext(ctx)
h.ServeHTTP(w, r)

View File

@ -23,46 +23,20 @@ import (
"github.com/cs3org/reva/internal/http/interceptors/auth/token/registry"
"github.com/cs3org/reva/pkg/auth"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
)
const (
defaultHeader = "X-Access-Token"
"github.com/cs3org/reva/pkg/token"
)
func init() {
registry.Register("header", New)
}
type config struct {
Header string `mapstructure:"header"`
}
type strategy struct {
header string
}
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
}
if c.Header == "" {
c.Header = defaultHeader
}
return c, nil
}
// New returns a new auth strategy that checks for basic auth.
func New(m map[string]interface{}) (auth.TokenStrategy, error) {
conf, err := parseConfig(m)
if err != nil {
return nil, err
}
return &strategy{header: conf.Header}, nil
return &strategy{header: token.TokenHeader}, nil
}
func (s *strategy) GetToken(r *http.Request) string {

View File

@ -23,38 +23,20 @@ import (
"github.com/cs3org/reva/internal/http/interceptors/auth/tokenwriter/registry"
"github.com/cs3org/reva/pkg/auth"
"github.com/mitchellh/mapstructure"
"github.com/pkg/errors"
"github.com/cs3org/reva/pkg/token"
)
func init() {
registry.Register("header", New)
}
type config struct {
Header string `mapstructure:"header"`
}
type strategy struct {
header string
}
func parseConfig(m map[string]interface{}) (*config, error) {
c := &config{Header: "X-Access-Token"}
if err := mapstructure.Decode(m, c); err != nil {
err = errors.Wrap(err, "error decoding conf")
return nil, err
}
return c, nil
}
// New returns a new token writer strategy that stores token in a header.
func New(m map[string]interface{}) (auth.TokenWriter, error) {
conf, err := parseConfig(m)
if err != nil {
return nil, err
}
return &strategy{header: conf.Header}, nil
return &strategy{header: token.TokenHeader}, nil
}
func (s *strategy) WriteToken(token string, w http.ResponseWriter) {

View File

@ -35,6 +35,7 @@ func init() {
type config struct {
AllowCredentials bool `mapstructure:"allow_credentials"`
OptionsPassthrough bool `mapstructure:"options_passthrough"`
Debug bool `mapstructure:"debug"`
MaxAge int `mapstructure:"max_age"`
Priority int `mapstructure:"priority"`
AllowedMethods []string `mapstructure:"allowed_methods"`
@ -64,9 +65,11 @@ func New(m map[string]interface{}) (global.Middleware, int, error) {
}
if len(conf.AllowedHeaders) == 0 {
conf.AllowedHeaders = []string{"Origin", "Accept", "Content-Type", "X-Requested-With", "Authorization", "Ocs-Apirequest", "If-None-Match"}
conf.AllowedHeaders = []string{"Origin", "Accept", "Content-Type", "Depth", "Authorization", "Ocs-Apirequest", "If-None-Match", "If-Match", "Destination", "Overwrite", "X-Request-Id", "X-Requested-With"}
}
// TODO(jfd): use log from request context, otherwise fmt will be used to log,
// preventing us from pinging the log to eg jq
c := cors.New(cors.Options{
AllowCredentials: conf.AllowCredentials,
AllowedHeaders: conf.AllowedHeaders,
@ -75,9 +78,7 @@ func New(m map[string]interface{}) (global.Middleware, int, error) {
ExposedHeaders: conf.ExposedHeaders,
MaxAge: conf.MaxAge,
OptionsPassthrough: conf.OptionsPassthrough,
Debug: false,
// TODO(jfd): use log from request context, otherwise fmt will be used to log,
// preventing us from pinging the log to eg jq
Debug: conf.Debug,
})
return c.Handler, conf.Priority, nil

View File

@ -48,7 +48,6 @@ type transferClaims struct {
}
type config struct {
Prefix string `mapstructure:"prefix"`
GatewayEndpoint string `mapstructure:"gateway"`
TransferSharedSecret string `mapstructure:"transfer_shared_secret"`
}
@ -64,6 +63,10 @@ func New(m map[string]interface{}) (global.Service, error) {
return nil, err
}
if conf.Prefix == "" {
conf.Prefix = "data"
}
s := &svc{conf: conf}
s.setHandler()
return s, nil

View File

@ -55,6 +55,10 @@ func New(m map[string]interface{}) (global.Service, error) {
return nil, err
}
if conf.Prefix == "" {
conf.Prefix = "data"
}
if conf.TmpFolder == "" {
conf.TmpFolder = os.TempDir()
}

View File

@ -24,18 +24,18 @@ import (
"net/http"
"time"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/rhttp/global"
"github.com/cs3org/reva/pkg/rhttp/router"
"github.com/cs3org/reva/pkg/sharedconf"
"github.com/mitchellh/mapstructure"
"github.com/ory/fosite"
"github.com/ory/fosite/compose"
"github.com/ory/fosite/handler/openid"
"github.com/ory/fosite/storage"
"github.com/ory/fosite/token/jwt"
"github.com/pkg/errors"
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/rhttp/global"
"github.com/cs3org/reva/pkg/rhttp/router"
"github.com/mitchellh/mapstructure"
)
func init() {
@ -44,7 +44,7 @@ func init() {
type config struct {
Prefix string `mapstructure:"prefix"`
GatewayEndpoint string `mapstructure:"gateway"`
GatewayEndpoint string `mapstructure:"gatewaysvc"`
Clients map[string]map[string]interface{} `mapstructure:"clients"`
Issuer string `mapstructure:"issuer"`
}
@ -80,6 +80,8 @@ func New(m map[string]interface{}) (global.Service, error) {
c.Prefix = "oauth2"
}
c.GatewayEndpoint = sharedconf.GetGatewaySVC(c.GatewayEndpoint)
clients, err := getClients(c.Clients)
if err != nil {
return nil, errors.Wrap(err, "oidcprovider: error parsing oidc clients")

View File

@ -58,7 +58,7 @@ func (s *svc) doUserinfo(w http.ResponseWriter, r *http.Request) {
internalToken := session.internalToken // To include in the context.
ctx = token.ContextSetToken(ctx, internalToken)
ctx = metadata.AppendToOutgoingContext(ctx, "x-access-token", internalToken) // TODO(labkode): this sucks.
ctx = metadata.AppendToOutgoingContext(ctx, token.TokenHeader, internalToken) // TODO(labkode): this sucks.
sub := session.GetSubject()
fmt.Printf("internal token: %s subject: %s session:%+v", internalToken, sub, session)

View File

@ -68,7 +68,7 @@ func (s *svc) doMove(w http.ResponseWriter, r *http.Request, ns string) {
}
urlPath := dstURL.Path
baseURI := r.Context().Value("baseuri").(string)
baseURI := r.Context().Value(ctxKeyBaseURI).(string)
log.Info().Str("url_path", urlPath).Str("base_uri", baseURI).Msg("move urls")
// TODO replace with HasPrefix:
i := strings.Index(urlPath, baseURI)

View File

@ -33,6 +33,7 @@ import (
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
"github.com/cs3org/reva/pkg/rhttp/global"
"github.com/cs3org/reva/pkg/rhttp/router"
"github.com/cs3org/reva/pkg/sharedconf"
"github.com/mitchellh/mapstructure"
)
@ -52,7 +53,7 @@ type Config struct {
FilesNamespace string `mapstructure:"files_namespace"`
WebdavNamespace string `mapstructure:"webdav_namespace"`
ChunkFolder string `mapstructure:"chunk_folder"`
GatewaySvc string `mapstructure:"gateway"`
GatewaySvc string `mapstructure:"gatewaysvc"`
}
type svc struct {
@ -68,6 +69,8 @@ func New(m map[string]interface{}) (global.Service, error) {
return nil, err
}
conf.GatewaySvc = sharedconf.GetGatewaySVC(conf.GatewaySvc)
if conf.ChunkFolder == "" {
conf.ChunkFolder = os.TempDir()
}

View File

@ -27,13 +27,6 @@ func (s *svc) doOptions(w http.ResponseWriter, r *http.Request, ns string) {
allow += " MOVE, UNLOCK, PROPFIND, MKCOL, REPORT, SEARCH,"
allow += " PUT" // TODO(jfd): only for files ... but we cannot create the full path without a user ... which we only have when credentials are sent
w.Header().Add("Vary", "Origin")
w.Header().Add("Vary", "Access-Control-Request-Method")
w.Header().Add("Vary", "Access-Control-Request-Headers")
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Allow-Methods", allow)
w.Header().Set("Access-Control-Allow-Headers", "Authorization, X-Requested-With, Content-Type, Depth, Ocs-Apirequest, If-Match, If-None-Match, Destination")
w.Header().Set("Content-Type", "application/xml")
w.Header().Set("Allow", allow)
w.Header().Set("DAV", "1, 2")

View File

@ -32,7 +32,6 @@ import (
userpb "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
rpc "github.com/cs3org/go-cs3apis/cs3/rpc/v1beta1"
provider "github.com/cs3org/go-cs3apis/cs3/storage/provider/v1beta1"
registry "github.com/cs3org/go-cs3apis/cs3/storage/registry/v1beta1"
"github.com/cs3org/reva/internal/http/utils"
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/rgrpc/todo/pool"
@ -161,7 +160,7 @@ func (h *TrashbinHandler) listTrashbin(w http.ResponseWriter, r *http.Request, s
return
}
getHomeRes, err := gc.GetHome(ctx, &registry.GetHomeRequest{})
getHomeRes, err := gc.GetHome(ctx, &provider.GetHomeRequest{})
if err != nil {
log.Error().Err(err).Msg("error calling GetHomeProvider")
w.WriteHeader(http.StatusInternalServerError)

View File

@ -96,7 +96,7 @@ func (h *CapabilitiesHandler) init(c *Config) {
h.c.Capabilities.Checksums = &CapabilitiesChecksums{}
}
if h.c.Capabilities.Checksums.SupportedTypes == nil {
h.c.Capabilities.Checksums.SupportedTypes = []string{"SHA1"}
h.c.Capabilities.Checksums.SupportedTypes = []string{"SHA256"}
}
if h.c.Capabilities.Checksums.PreferredUploadType == "" {
h.c.Capabilities.Checksums.PreferredUploadType = "SHA1"

View File

@ -24,6 +24,7 @@ import (
"github.com/cs3org/reva/pkg/appctx"
"github.com/cs3org/reva/pkg/rhttp/global"
"github.com/cs3org/reva/pkg/rhttp/router"
"github.com/cs3org/reva/pkg/sharedconf"
"github.com/mitchellh/mapstructure"
)
@ -36,7 +37,7 @@ type Config struct {
Prefix string `mapstructure:"prefix"`
Config ConfigData `mapstructure:"config"`
Capabilities CapabilitiesData `mapstructure:"capabilities"`
GatewaySvc string `mapstructure:"gateway"`
GatewaySvc string `mapstructure:"gatewaysvc"`
}
type svc struct {
@ -55,6 +56,8 @@ func New(m map[string]interface{}) (global.Service, error) {
conf.Prefix = "ocs"
}
conf.GatewaySvc = sharedconf.GetGatewaySVC(conf.GatewaySvc)
s := &svc{
c: conf,
V1Handler: new(V1Handler),

View File

@ -65,10 +65,13 @@ func (h *UsersHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
DisplayName: u.DisplayName,
Email: u.Mail,
})
return
case "groups":
WriteOCSSuccess(w, r, &GroupsData{})
return
default:
WriteOCSError(w, r, MetaNotFound.StatusCode, "Not found", nil)
return
}
}

View File

@ -74,7 +74,7 @@ type Attribute struct {
}
func (a *Attribute) serialize() string {
return fmt.Sprintf("%s.%s=%q", a.Type, a.Key, a.Key)
return fmt.Sprintf("%s.%s=%s", a.Type, a.Key, a.Val)
}
func (a *Attribute) isValid() bool {
@ -200,9 +200,6 @@ func (c *Client) execute(ctx context.Context, cmd *exec.Cmd) (string, string, er
err = nil
case 2:
err = errtypes.NotFound(errBuf.String())
case 22:
// eos reports back error code 22 when the user is not allowed to enter the instance
err = errtypes.NotFound(errBuf.String())
}
}
}
@ -212,13 +209,14 @@ func (c *Client) execute(ctx context.Context, cmd *exec.Cmd) (string, string, er
log.Info().Str("args", args).Str("env", env).Int("exit", exitStatus).Msg("eos cmd")
if err != nil && exitStatus != 2 { // don't wrap the errtypes.NotFoundError
err = errors.Wrap(err, "error while executing command")
err = errors.Wrap(err, "eosclient: error while executing command")
}
return outBuf.String(), errBuf.String(), err
}
// exec executes the command and returns the stdout, stderr and return code
// exec executes only EOS commands the command and returns the stdout, stderr and return code.
// execute() executes arbitrary commands.
func (c *Client) executeEOS(ctx context.Context, cmd *exec.Cmd) (string, string, error) {
log := appctx.GetLogger(ctx)
@ -250,7 +248,7 @@ func (c *Client) executeEOS(ctx context.Context, cmd *exec.Cmd) (string, string,
err = errtypes.NotFound(errBuf.String())
case 22:
// eos reports back error code 22 when the user is not allowed to enter the instance
err = errtypes.NotFound(errBuf.String())
err = errtypes.PermissionDenied(errBuf.String())
}
}
}
@ -260,7 +258,7 @@ func (c *Client) executeEOS(ctx context.Context, cmd *exec.Cmd) (string, string,
log.Info().Str("args", args).Str("env", env).Int("exit", exitStatus).Str("err", errBuf.String()).Msg("eos cmd")
if err != nil && exitStatus != 2 { // don't wrap the errtypes.NotFoundError
err = errors.Wrap(err, "error while executing command")
err = errors.Wrap(err, "eosclient: error while executing command")
}
return outBuf.String(), errBuf.String(), err
@ -482,6 +480,35 @@ func (c *Client) Touch(ctx context.Context, username, path string) error {
return err
}
// Chown given path
func (c *Client) Chown(ctx context.Context, username, chownUser, path string) error {
unixUser, err := c.getUnixUser(username)
if err != nil {
return err
}
unixChownUser, err := c.getUnixUser(chownUser)
if err != nil {
return err
}
cmd := exec.CommandContext(ctx, c.opt.EosBinary, "-r", unixUser.Uid, unixUser.Gid, "chown", unixChownUser.Uid+":"+unixChownUser.Gid, path)
_, _, err = c.executeEOS(ctx, cmd)
return err
}
// Chmod given path
func (c *Client) Chmod(ctx context.Context, username, mode, path string) error {
unixUser, err := c.getUnixUser(username)
if err != nil {
return err
}
cmd := exec.CommandContext(ctx, c.opt.EosBinary, "-r", unixUser.Uid, unixUser.Gid, "chmod", mode, path)
_, _, err = c.executeEOS(ctx, cmd)
return err
}
// CreateDir creates a directory at the given path
func (c *Client) CreateDir(ctx context.Context, username, path string) error {
unixUser, err := c.getUnixUser(username)
@ -489,7 +516,7 @@ func (c *Client) CreateDir(ctx context.Context, username, path string) error {
return err
}
cmd := exec.CommandContext(ctx, c.opt.EosBinary, "-r", unixUser.Uid, unixUser.Gid, "mkdir", path)
cmd := exec.CommandContext(ctx, c.opt.EosBinary, "-r", unixUser.Uid, unixUser.Gid, "mkdir", "-p", path)
_, _, err = c.executeEOS(ctx, cmd)
return err
}
@ -525,7 +552,7 @@ func (c *Client) List(ctx context.Context, username, path string) ([]*FileInfo,
cmd := exec.CommandContext(ctx, c.opt.EosBinary, "-r", unixUser.Uid, unixUser.Gid, "find", "--fileinfo", "--maxdepth", "1", path)
stdout, _, err := c.executeEOS(ctx, cmd)
if err != nil {
return nil, errors.Wrapf(err, "error listing fn=%s", path)
return nil, errors.Wrapf(err, "eosclient: error listing fn=%s", path)
}
return c.parseFind(path, stdout)
}

View File

@ -30,6 +30,14 @@ func (e NotFound) Error() string { return "error: not found: " + string(e) }
// IsNotFound is the method to check for w
func (e NotFound) IsNotFound() {}
// PermissionDenied is the error to use when a resource cannot be access because of missing permissions.
type PermissionDenied string
func (e PermissionDenied) Error() string { return "error: permission denied: " + string(e) }
// IsPermissionDenied is the method to check for w
func (e PermissionDenied) IsPermissionDenied() {}
// AlreadyExists is the error to use when a resource something is not found.
type AlreadyExists string
@ -91,3 +99,9 @@ type IsInvalidCredentials interface {
type IsNotSupported interface {
IsNotSupported()
}
// IsPermissionDenied is the interface to implement
// to specify that an action is not supported.
type IsPermissionDenied interface {
IsPermissionDenied()
}

View File

@ -40,7 +40,8 @@ func NewOK(ctx context.Context) *rpc.Status {
// NewNotFound returns a Status with CODE_NOT_FOUND and logs the msg.
func NewNotFound(ctx context.Context, msg string) *rpc.Status {
appctx.GetLogger(ctx).Warn().Msg(msg)
log := appctx.GetLogger(ctx).With().CallerWithSkipFrameCount(3).Logger()
log.Warn().Msg(msg)
return &rpc.Status{
Code: rpc.Code_CODE_NOT_FOUND,
Message: msg,
@ -50,7 +51,8 @@ func NewNotFound(ctx context.Context, msg string) *rpc.Status {
// NewInvalid returns a Status with CODE_INVALID_ARGUMENT and logs the msg.
func NewInvalid(ctx context.Context, msg string) *rpc.Status {
appctx.GetLogger(ctx).Warn().Msg(msg)
log := appctx.GetLogger(ctx).With().CallerWithSkipFrameCount(3).Logger()
log.Warn().Msg(msg)
return &rpc.Status{
Code: rpc.Code_CODE_INVALID_ARGUMENT,
Message: msg,
@ -64,7 +66,10 @@ func NewInternal(ctx context.Context, err error, msg string) *rpc.Status {
if err == nil {
panic("Internal error triggered without an error context")
}
appctx.GetLogger(ctx).Err(err).Msg(msg)
log := appctx.GetLogger(ctx).With().CallerWithSkipFrameCount(3).Logger()
log.Err(err).Msg(msg)
return &rpc.Status{
Code: rpc.Code_CODE_INTERNAL,
Message: msg,
@ -74,7 +79,8 @@ func NewInternal(ctx context.Context, err error, msg string) *rpc.Status {
// NewUnauthenticated returns a Status with CODE_UNAUTHENTICATED and logs the msg.
func NewUnauthenticated(ctx context.Context, err error, msg string) *rpc.Status {
appctx.GetLogger(ctx).Warn().Err(err).Msg(msg)
log := appctx.GetLogger(ctx).With().CallerWithSkipFrameCount(3).Logger()
log.Warn().Err(err).Msg(msg)
return &rpc.Status{
Code: rpc.Code_CODE_UNAUTHENTICATED,
Message: msg,
@ -84,7 +90,8 @@ func NewUnauthenticated(ctx context.Context, err error, msg string) *rpc.Status
// NewUnimplemented returns a Status with CODE_UNIMPLEMENTED and logs the msg.
func NewUnimplemented(ctx context.Context, err error, msg string) *rpc.Status {
appctx.GetLogger(ctx).Error().Err(err).Msg(msg)
log := appctx.GetLogger(ctx).With().CallerWithSkipFrameCount(3).Logger()
log.Error().Err(err).Msg(msg)
return &rpc.Status{
Code: rpc.Code_CODE_UNIMPLEMENTED,
Message: msg,
@ -102,7 +109,7 @@ func NewInvalidArg(ctx context.Context, msg string) *rpc.Status {
// NewErrorFromCode returns a standardized Error for a given RPC code.
func NewErrorFromCode(code rpc.Code, pkgname string) error {
return errors.New(pkgname + ": RPC failed with code " + code.String())
return errors.New(pkgname + ": grpc failed with code " + code.String())
}
// internal function to attach the trace to a context

View File

@ -29,10 +29,6 @@ import (
"go.opencensus.io/plugin/ochttp"
)
const (
defaultAccessHeader = "X-Access-Token"
)
// GetHTTPClient returns an http client with open census tracing support.
// TODO(labkode): harden it.
// https://medium.com/@nate510/don-t-use-go-s-default-http-client-4804cb19f779
@ -54,7 +50,7 @@ func NewRequest(ctx context.Context, method, url string, body io.Reader) (*http.
// TODO(labkode): make header / auth configurable
tkn, ok := token.ContextGetToken(ctx)
if ok {
httpReq.Header.Set(defaultAccessHeader, tkn)
httpReq.Header.Set(token.TokenHeader, tkn)
}
httpReq = httpReq.WithContext(ctx)

View File

@ -0,0 +1,55 @@
// Copyright 2018-2019 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 sharedconf
import (
"github.com/mitchellh/mapstructure"
)
var sharedConf = &conf{}
type conf struct {
JWTSecret string `mapstructure:"jwt_secret"`
GatewaySVC string `mapstructure:"gatewaysvc"`
}
// Decode decodes the configuration.
func Decode(v interface{}) error {
if err := mapstructure.Decode(v, sharedConf); err != nil {
return err
}
return nil
}
// GetJWTSecret returns the package level configured jwt secret if not overwriten.
func GetJWTSecret(val string) string {
if val == "" {
return sharedConf.JWTSecret
}
return val
}
// GetGatewaySVC returns the package level configured gateway service if not overwriten.
func GetGatewaySVC(val string) string {
if val == "" {
return sharedConf.GatewaySVC
}
return val
}

View File

@ -0,0 +1,64 @@
// Copyright 2018-2019 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 sharedconf
import (
"testing"
)
func Test(t *testing.T) {
conf := map[string]interface{}{
"jwt_secret": "",
"gateway": "",
}
err := Decode(conf)
if err != nil {
t.Fatal(err)
}
got := GetJWTSecret("secret")
if got != "secret" {
t.Fatalf("expected %q got %q", "secret", got)
}
got = GetJWTSecret("")
if got != "" {
t.Fatalf("expected %q got %q", "", got)
}
conf = map[string]interface{}{
"jwt_secret": "dummy",
}
err = Decode(conf)
if err != nil {
t.Fatal(err)
}
got = GetJWTSecret("secret")
if got != "secret" {
t.Fatalf("expected %q got %q", "secret", got)
}
got = GetJWTSecret("")
if got != "dummy" {
t.Fatalf("expected %q got %q", "dummy", got)
}
}

View File

@ -108,6 +108,9 @@ type config struct {
// UseKeyTabAuth changes will authenticate requests by using an EOS keytab.
UseKeytab bool `mapstrucuture:"use_keytab"`
// EnableHome enables the creation of home directories.
EnableHome bool `mapstructure:"enable_home"`
// SecProtocol specifies the xrootd security protocol to use between the server and EOS.
SecProtocol string `mapstructure:"sec_protocol"`
@ -194,6 +197,13 @@ func New(m map[string]interface{}) (storage.FS, error) {
return eosStorage, nil
}
func (fs *eosStorage) getHomeForUser(u *userpb.User) string {
// TODO(labkode): define home path layout in configuration
// like home: %letter%/%username% and then do string substitution.
home := path.Join(fs.mountpoint, u.Username)
return home
}
func (fs *eosStorage) Shutdown(ctx context.Context) error {
// TODO(labkode): in a grpc implementation we can close connections.
return nil
@ -555,6 +565,82 @@ func (fs *eosStorage) GetQuota(ctx context.Context) (int, int, error) {
return fs.c.GetQuota(ctx, u.Username, fs.conf.Namespace)
}
func (fs *eosStorage) GetHome(ctx context.Context) (string, error) {
u, err := getUser(ctx)
if err != nil {
return "", errors.Wrap(err, "eos: no user in ctx")
}
home := fs.getHomeForUser(u)
return home, nil
}
func (fs *eosStorage) CreateHome(ctx context.Context) error {
u, err := getUser(ctx)
if err != nil {
return errors.Wrap(err, "eos: no user in ctx")
}
home := fs.getHomeForUser(u)
_, err = fs.c.GetFileInfoByPath(ctx, "root", home)
if err == nil { // home already exists
return nil
}
// TODO(labkode): abort on any error that is not found
if _, ok := err.(errtypes.IsNotFound); !ok {
return errors.Wrap(err, "eos: error verifying if user home directory exists")
}
// TODO(labkode): only trigger creation on not found, copy from CERNBox logic.
err = fs.c.CreateDir(ctx, "root", home)
if err != nil {
// EOS will return success on mkdir over an existing directory.
return errors.Wrap(err, "eos: error creating dir")
}
err = fs.c.Chown(ctx, "root", u.Username, home)
if err != nil {
return errors.Wrap(err, "eos: error chowning directory")
}
err = fs.c.Chmod(ctx, "root", "2770", home)
if err != nil {
return errors.Wrap(err, "eos: error chmoding directory")
}
attrs := []*eosclient.Attribute{
&eosclient.Attribute{
Type: eosclient.SystemAttr,
Key: "mask",
Val: "700",
},
&eosclient.Attribute{
Type: eosclient.SystemAttr,
Key: "allow.oc.sync",
Val: "1",
},
&eosclient.Attribute{
Type: eosclient.SystemAttr,
Key: "mtime.propagation",
Val: "1",
},
&eosclient.Attribute{
Type: eosclient.SystemAttr,
Key: "forced.atomic",
Val: "1",
},
}
for _, attr := range attrs {
err = fs.c.SetAttr(ctx, "root", attr, home)
if err != nil {
return errors.Wrap(err, "eos: error setting attribute")
}
}
return nil
}
func (fs *eosStorage) CreateDir(ctx context.Context, fn string) error {
u, err := getUser(ctx)
if err != nil {

View File

@ -169,6 +169,14 @@ func (fs *localFS) UnsetArbitraryMetadata(ctx context.Context, ref *provider.Ref
return errtypes.NotSupported("local: operation not supported")
}
func (fs *localFS) GetHome(ctx context.Context) (string, error) {
return "", errtypes.NotSupported("local: creating home not supported")
}
func (fs *localFS) CreateHome(ctx context.Context) error {
return errtypes.NotSupported("local: creating home not supported")
}
func (fs *localFS) CreateDir(ctx context.Context, fn string) error {
fn = fs.addRoot(fn)
err := os.Mkdir(fn, 0700)

View File

@ -152,7 +152,6 @@ func init() {
type config struct {
DataDirectory string `mapstructure:"datadirectory"`
Scan bool `mapstructure:"scan"`
Autocreate bool `mapstructure:"autocreate"`
Redis string `mapstructure:"redis"`
}
@ -173,10 +172,6 @@ func (c *config) init(m map[string]interface{}) {
if _, ok := m["scan"]; !ok {
c.Scan = true
}
// default to autocreate if not configured
if _, ok := m["autocreate"]; !ok {
c.Autocreate = true
}
}
// New returns an implementation to of the storage.FS interface that talk to
@ -230,6 +225,15 @@ func (fs *ocFS) Shutdown(ctx context.Context) error {
return fs.pool.Close()
}
func getUser(ctx context.Context) (*userpb.User, error) {
u, ok := user.ContextGetUser(ctx)
if !ok {
err := errors.Wrap(errtypes.UserRequired(""), "owncloud: error getting user from ctx")
return nil, err
}
return u, nil
}
// scan files and add uuid to path mapping to kv store
func (fs *ocFS) scanFiles(ctx context.Context, conn redis.Conn) {
if fs.c.Scan {
@ -462,29 +466,6 @@ func readOrCreateID(ctx context.Context, np string, conn redis.Conn) string {
return uid.String()
}
func (fs *ocFS) autocreate(ctx context.Context, fsfn string) {
if fs.c.Autocreate {
parts := strings.SplitN(fsfn, "/files", 2)
switch len(parts) {
case 1:
return // error? there is no files in here ...
case 2:
if parts[1] == "" {
// nothing to do, fsfn is the home
} else {
// only create home
fsfn = path.Join(parts[0], "files")
}
err := os.MkdirAll(fsfn, 0700)
if err != nil {
appctx.GetLogger(ctx).Debug().Err(err).
Str("fsfn", fsfn).
Msg("could not autocreate dir")
}
}
}
}
func (fs *ocFS) getPath(ctx context.Context, id *provider.ResourceId) (string, error) {
c := fs.pool.Get()
defer c.Close()
@ -868,6 +849,43 @@ func (fs *ocFS) GetQuota(ctx context.Context) (int, int, error) {
return 0, 0, nil
}
func (fs *ocFS) getHomeForUser(u *userpb.User) string {
return path.Join("/", u.Username)
}
func (fs *ocFS) CreateHome(ctx context.Context) error {
u, err := getUser(ctx)
if err != nil {
return errors.Wrap(err, "eos: no user in ctx")
}
home := fs.getHomeForUser(u)
homePaths := []string{
path.Join(fs.c.DataDirectory, home, "files"),
path.Join(fs.c.DataDirectory, home, "files_trashbin"),
path.Join(fs.c.DataDirectory, home, "files_versions"),
}
for _, v := range homePaths {
if err = os.MkdirAll(v, 0700); err != nil {
return errors.Wrap(err, "ocFS: error creating home path: "+v)
}
}
return nil
}
func (fs *ocFS) GetHome(ctx context.Context) (string, error) {
u, err := getUser(ctx)
if err != nil {
return "", errors.Wrap(err, "eos: no user in ctx")
}
home := fs.getHomeForUser(u)
return home, nil
}
func (fs *ocFS) CreateDir(ctx context.Context, fn string) (err error) {
np := fs.getInternalPath(ctx, fn)
if err = os.Mkdir(np, 0700); err != nil {
@ -1164,8 +1182,6 @@ func (fs *ocFS) GetMD(ctx context.Context, ref *provider.Reference) (*provider.R
return nil, errors.Wrap(err, "ocFS: error resolving reference")
}
fs.autocreate(ctx, np)
md, err := os.Stat(np)
if err != nil {
if os.IsNotExist(err) {
@ -1186,8 +1202,6 @@ func (fs *ocFS) ListFolder(ctx context.Context, ref *provider.Reference) ([]*pro
return nil, errors.Wrap(err, "ocFS: error resolving reference")
}
fs.autocreate(ctx, np)
mds, err := ioutil.ReadDir(np)
if err != nil {
if os.IsNotExist(err) {
@ -1305,8 +1319,6 @@ func (fs *ocFS) ListRevisions(ctx context.Context, ref *provider.Reference) ([]*
}
vp := fs.getVersionsPath(ctx, np)
fs.autocreate(ctx, vp)
bn := path.Base(np)
revisions := []*provider.FileVersion{}

View File

@ -253,6 +253,14 @@ func (fs *s3FS) CreateReference(ctx context.Context, path string, targetURI *url
return errtypes.NotSupported("s3: operation not supported")
}
func (fs *s3FS) GetHome(ctx context.Context) (string, error) {
return "", errtypes.NotSupported("eos: not supported")
}
func (fs *s3FS) CreateHome(ctx context.Context) error {
return errtypes.NotSupported("s3fs: not supported")
}
func (fs *s3FS) CreateDir(ctx context.Context, fn string) error {
log := appctx.GetLogger(ctx)
fn = fs.addRoot(fn) + "/" // append / to indicate folder // TODO only if fn does not end in /

View File

@ -35,73 +35,9 @@ func init() {
registry.Register("static", New)
}
type reg struct {
rules map[string]string
}
func (b *reg) ListProviders(ctx context.Context) ([]*registrypb.ProviderInfo, error) {
providers := []*registrypb.ProviderInfo{}
for k, v := range b.rules {
providers = append(providers, &registrypb.ProviderInfo{
Address: v,
ProviderPath: k,
})
}
return providers, nil
}
// returns the the root path of the first provider in the list.
// TODO(labkode): this is not production ready.
func (b *reg) GetHome(ctx context.Context) (string, error) {
for k := range b.rules {
if strings.HasPrefix(k, "/") {
return k, nil
}
}
return "", errors.New("static: home not found")
}
func (b *reg) FindProvider(ctx context.Context, ref *provider.Reference) (*registrypb.ProviderInfo, error) {
// find longest match
var match string
// we try to find first by path as most storage operations will be done on path.
fn := ref.GetPath()
if fn != "" {
for prefix := range b.rules {
if strings.HasPrefix(fn, prefix) && len(prefix) > len(match) {
match = prefix
}
}
}
if match != "" {
return &registrypb.ProviderInfo{
ProviderPath: match,
Address: b.rules[match],
}, nil
}
// we try with id
id := ref.GetId()
if id == nil {
return nil, errtypes.NotFound("storage provider not found for ref " + ref.String())
}
for prefix := range b.rules {
if id.StorageId == prefix {
// TODO(labkode): fill path info based on provider id, if path and storage id points to same id, take that.
return &registrypb.ProviderInfo{
ProviderId: prefix,
Address: b.rules[prefix],
}, nil
}
}
return nil, errtypes.NotFound("storage provider not found for ref " + ref.String())
}
type config struct {
Rules map[string]string `mapstructure:"rules"`
Rules map[string]string `mapstructure:"rules"`
HomeProvider string `mapstructure:"home_provider"`
}
func parseConfig(m map[string]interface{}) (*config, error) {
@ -119,5 +55,73 @@ func New(m map[string]interface{}) (storage.Registry, error) {
if err != nil {
return nil, err
}
return &reg{rules: c.Rules}, nil
return &reg{c: c}, nil
}
type reg struct {
c *config
}
func (b *reg) ListProviders(ctx context.Context) ([]*registrypb.ProviderInfo, error) {
providers := []*registrypb.ProviderInfo{}
for k, v := range b.c.Rules {
providers = append(providers, &registrypb.ProviderInfo{
Address: v,
ProviderPath: k,
})
}
return providers, nil
}
// returns the the root path of the first provider in the list.
// TODO(labkode): this is not production ready.
func (b *reg) GetHome(ctx context.Context) (*registrypb.ProviderInfo, error) {
for k, v := range b.c.Rules {
if k == b.c.HomeProvider {
return &registrypb.ProviderInfo{
ProviderPath: k,
Address: v,
}, nil
}
}
return nil, errors.New("static: home not found")
}
func (b *reg) FindProvider(ctx context.Context, ref *provider.Reference) (*registrypb.ProviderInfo, error) {
// find longest match
var match string
// we try to find first by path as most storage operations will be done on path.
fn := ref.GetPath()
if fn != "" {
for prefix := range b.c.Rules {
if strings.HasPrefix(fn, prefix) && len(prefix) > len(match) {
match = prefix
}
}
}
if match != "" {
return &registrypb.ProviderInfo{
ProviderPath: match,
Address: b.c.Rules[match],
}, nil
}
// we try with id
id := ref.GetId()
if id == nil {
return nil, errtypes.NotFound("storage provider not found for ref " + ref.String())
}
for prefix := range b.c.Rules {
if id.StorageId == prefix {
// TODO(labkode): fill path info based on provider id, if path and storage id points to same id, take that.
return &registrypb.ProviderInfo{
ProviderId: prefix,
Address: b.c.Rules[prefix],
}, nil
}
}
return nil, errtypes.NotFound("storage provider not found for ref " + ref.String())
}

View File

@ -29,6 +29,8 @@ import (
// FS is the interface to implement access to the storage.
type FS interface {
GetHome(ctx context.Context) (string, error)
CreateHome(ctx context.Context) error
CreateDir(ctx context.Context, fn string) error
Delete(ctx context.Context, ref *provider.Reference) error
Move(ctx context.Context, oldRef, newRef *provider.Reference) error
@ -60,7 +62,7 @@ type FS interface {
type Registry interface {
FindProvider(ctx context.Context, ref *provider.Reference) (*registry.ProviderInfo, error)
ListProviders(ctx context.Context) ([]*registry.ProviderInfo, error)
GetHome(ctx context.Context) (string, error)
GetHome(ctx context.Context) (*registry.ProviderInfo, error)
}
// PathWrapper is the interface to implement for path transformations

View File

@ -24,6 +24,7 @@ import (
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
"github.com/cs3org/reva/pkg/errtypes"
"github.com/cs3org/reva/pkg/sharedconf"
"github.com/cs3org/reva/pkg/token"
"github.com/cs3org/reva/pkg/token/manager/registry"
"github.com/dgrijalva/jwt-go"
@ -62,6 +63,8 @@ func New(value map[string]interface{}) (token.Manager, error) {
c.Expires = defaultExpiraton
}
c.Secret = sharedconf.GetJWTSecret(c.Secret)
if c.Secret == "" {
return nil, errors.New("jwt: secret for signing payloads is not defined in config")
}

View File

@ -24,6 +24,10 @@ import (
user "github.com/cs3org/go-cs3apis/cs3/identity/user/v1beta1"
)
// TokenHeader is the header to be used across grpc and http services
// to forward the access token.
const TokenHeader = "x-access-token"
type key int
const tokenKey key = iota