Merge branch 'master' into config-doc-descriptions
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/shared"
|
||||
)
|
||||
|
||||
// Config combines all available configuration parts.
|
||||
type Config struct {
|
||||
Commons *shared.Commons `yaml:"-"` // don't use this directly as configuration for a service
|
||||
|
||||
Service Service `yaml:"-"`
|
||||
|
||||
Tracing *Tracing `yaml:"tracing"`
|
||||
Log *Log `yaml:"log"`
|
||||
Debug Debug `yaml:"debug"`
|
||||
|
||||
HTTP HTTP `yaml:"http"`
|
||||
|
||||
Reva *Reva `yaml:"reva"`
|
||||
|
||||
Policies []Policy `yaml:"policies"`
|
||||
OIDC OIDC `yaml:"oidc"`
|
||||
TokenManager *TokenManager `yaml:"token_manager"`
|
||||
PolicySelector *PolicySelector `yaml:"policy_selector"`
|
||||
PreSignedURL PreSignedURL `yaml:"pre_signed_url"`
|
||||
AccountBackend string `yaml:"account_backend" env:"PROXY_ACCOUNT_BACKEND_TYPE" desc:"Account backend the proxy should use, currenly only 'cs3' is possible here."`
|
||||
UserOIDCClaim string `yaml:"user_oidc_claim" env:"PROXY_USER_OIDC_CLAIM" desc:"The name of an OpenID Connect claim that should be used for resolving users with the account backend. Currently defaults to 'email'."`
|
||||
UserCS3Claim string `yaml:"user_cs3_claim" env:"PROXY_USER_CS3_CLAIM" desc:"The name of a CS3 user attribute (claim) that should be mapped to the 'user_oidc_claim'. Currently defaults to 'mail' (other possible values are: 'username', 'displayname')"`
|
||||
MachineAuthAPIKey string `yaml:"machine_auth_api_key" env:"OCIS_MACHINE_AUTH_API_KEY;PROXY_MACHINE_AUTH_API_KEY" desc:"Machine auth API key used for accessing the 'auth-machine' service to impersonate users."`
|
||||
AutoprovisionAccounts bool `yaml:"auto_provision_accounts" env:"PROXY_AUTOPROVISION_ACCOUNTS" desc:"Set this to 'true' to automatically provsion users that do not yet exist in the users service on-demand upon first signin. To use this a write-enabled libregraph user backend needs to be setup an running."`
|
||||
EnableBasicAuth bool `yaml:"enable_basic_auth" env:"PROXY_ENABLE_BASIC_AUTH" desc:"Set this to true to enable 'basic' (username/password) authentication."`
|
||||
InsecureBackends bool `yaml:"insecure_backends" env:"PROXY_INSECURE_BACKENDS" desc:"Disable TLS certificate validation for all http backend connections."`
|
||||
AuthMiddleware AuthMiddleware `yaml:"auth_middleware"`
|
||||
|
||||
Context context.Context `yaml:"-"`
|
||||
}
|
||||
|
||||
// Policy enables us to use multiple directors.
|
||||
type Policy struct {
|
||||
Name string `yaml:"name"`
|
||||
Routes []Route `yaml:"routes"`
|
||||
}
|
||||
|
||||
// Route defines forwarding routes
|
||||
type Route struct {
|
||||
Type RouteType `yaml:"type,omitempty"`
|
||||
// Method optionally limits the route to this HTTP method
|
||||
Method string `yaml:"method,omitempty"`
|
||||
Endpoint string `yaml:"endpoint,omitempty"`
|
||||
// Backend is a static URL to forward the request to
|
||||
Backend string `yaml:"backend,omitempty"`
|
||||
// Service name to look up in the registry
|
||||
Service string `yaml:"service,omitempty"`
|
||||
ApacheVHost bool `yaml:"apache_vhost,omitempty"`
|
||||
}
|
||||
|
||||
// RouteType defines the type of a route
|
||||
type RouteType string
|
||||
|
||||
const (
|
||||
// PrefixRoute are routes matched by a prefix
|
||||
PrefixRoute RouteType = "prefix"
|
||||
// QueryRoute are routes matched by a prefix and query parameters
|
||||
QueryRoute RouteType = "query"
|
||||
// RegexRoute are routes matched by a pattern
|
||||
RegexRoute RouteType = "regex"
|
||||
// DefaultRouteType is the PrefixRoute
|
||||
DefaultRouteType RouteType = PrefixRoute
|
||||
)
|
||||
|
||||
var (
|
||||
// RouteTypes is an array of the available route types
|
||||
RouteTypes = []RouteType{QueryRoute, RegexRoute, PrefixRoute}
|
||||
)
|
||||
|
||||
// AuthMiddleware configures the proxy http auth middleware.
|
||||
type AuthMiddleware struct {
|
||||
CredentialsByUserAgent map[string]string `yaml:"credentials_by_user_agent"`
|
||||
}
|
||||
|
||||
// OIDC is the config for the OpenID-Connect middleware. If set the proxy will try to authenticate every request
|
||||
// with the configured oidc-provider
|
||||
type OIDC struct {
|
||||
Issuer string `yaml:"issuer" env:"OCIS_URL;OCIS_OIDC_ISSUER;PROXY_OIDC_ISSUER" desc:"URL of the OIDC issuer. It defaults to URL of the builtin IDP."`
|
||||
Insecure bool `yaml:"insecure" env:"OCIS_INSECURE;PROXY_OIDC_INSECURE" desc:"Disable TLS certificate validation for connections to the IDP. (not recommended for production environments."`
|
||||
UserinfoCache UserinfoCache `yaml:"user_info_cache"`
|
||||
}
|
||||
|
||||
// UserinfoCache is a TTL cache configuration.
|
||||
type UserinfoCache struct {
|
||||
Size int `yaml:"size" env:"PROXY_OIDC_USERINFO_CACHE_SIZE" desc:"Cache size for oidc user info."`
|
||||
TTL int `yaml:"ttl" env:"PROXY_OIDC_USERINFO_CACHE_TTL" desc:"Max TTL for the oidc user info cache."`
|
||||
}
|
||||
|
||||
// PolicySelector is the toplevel-configuration for different selectors
|
||||
type PolicySelector struct {
|
||||
Static *StaticSelectorConf `yaml:"static"`
|
||||
Claims *ClaimsSelectorConf `yaml:"claims"`
|
||||
Regex *RegexSelectorConf `yaml:"regex"`
|
||||
}
|
||||
|
||||
// StaticSelectorConf is the config for the static-policy-selector
|
||||
type StaticSelectorConf struct {
|
||||
Policy string `yaml:"policy"`
|
||||
}
|
||||
|
||||
// TokenManager is the config for using the reva token manager
|
||||
type TokenManager struct {
|
||||
JWTSecret string `yaml:"jwt_secret" env:"OCIS_JWT_SECRET;PROXY_JWT_SECRET" desc:"The secret to mint and validate jwt tokens."`
|
||||
}
|
||||
|
||||
// PreSignedURL is the config for the presigned url middleware
|
||||
type PreSignedURL struct {
|
||||
AllowedHTTPMethods []string `yaml:"allowed_http_methods"`
|
||||
Enabled bool `yaml:"enabled" env:"PROXY_ENABLE_PRESIGNEDURLS" desc:"Allow ocs to get a signing key to sign requests."`
|
||||
}
|
||||
|
||||
// ClaimsSelectorConf is the config for the claims-selector
|
||||
type ClaimsSelectorConf struct {
|
||||
DefaultPolicy string `yaml:"default_policy"`
|
||||
UnauthenticatedPolicy string `yaml:"unauthenticated_policy"`
|
||||
SelectorCookieName string `yaml:"selector_cookie_name"`
|
||||
}
|
||||
|
||||
// RegexSelectorConf is the config for the regex-selector
|
||||
type RegexSelectorConf struct {
|
||||
DefaultPolicy string `yaml:"default_policy"`
|
||||
MatchesPolicies []RegexRuleConf `yaml:"matches_policies"`
|
||||
UnauthenticatedPolicy string `yaml:"unauthenticated_policy"`
|
||||
SelectorCookieName string `yaml:"selector_cookie_name"`
|
||||
}
|
||||
|
||||
type RegexRuleConf struct {
|
||||
Priority int `yaml:"priority"`
|
||||
Property string `yaml:"property"`
|
||||
Match string `yaml:"match"`
|
||||
Policy string `yaml:"policy"`
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package config
|
||||
|
||||
// Debug defines the available debug configuration.
|
||||
type Debug struct {
|
||||
Addr string `yaml:"addr" env:"PROXY_DEBUG_ADDR" desc:"Bind address of the debug server, where metrics, health, config and debug endpoints will be exposed."`
|
||||
Token string `yaml:"token" env:"PROXY_DEBUG_TOKEN" desc:"Token to secure the metrics endpoint"`
|
||||
Pprof bool `yaml:"pprof" env:"PROXY_DEBUG_PPROF" desc:"Enables pprof, which can be used for profiling"`
|
||||
Zpages bool `yaml:"zpages" env:"PROXY_DEBUG_ZPAGES" desc:"Enables zpages, which can be used for collecting and viewing in-memory traces."`
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
package defaults
|
||||
|
||||
import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/config/defaults"
|
||||
"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
|
||||
)
|
||||
|
||||
func FullDefaultConfig() *config.Config {
|
||||
cfg := DefaultConfig()
|
||||
EnsureDefaults(cfg)
|
||||
Sanitize(cfg)
|
||||
return cfg
|
||||
}
|
||||
|
||||
func DefaultConfig() *config.Config {
|
||||
return &config.Config{
|
||||
Debug: config.Debug{
|
||||
Addr: "127.0.0.1:9205",
|
||||
Token: "",
|
||||
},
|
||||
HTTP: config.HTTP{
|
||||
Addr: "0.0.0.0:9200",
|
||||
Root: "/",
|
||||
Namespace: "com.owncloud.web",
|
||||
TLSCert: path.Join(defaults.BaseDataPath(), "proxy", "server.crt"),
|
||||
TLSKey: path.Join(defaults.BaseDataPath(), "proxy", "server.key"),
|
||||
TLS: true,
|
||||
},
|
||||
Service: config.Service{
|
||||
Name: "proxy",
|
||||
},
|
||||
OIDC: config.OIDC{
|
||||
Issuer: "https://localhost:9200",
|
||||
Insecure: true,
|
||||
//Insecure: true,
|
||||
UserinfoCache: config.UserinfoCache{
|
||||
Size: 1024,
|
||||
TTL: 10,
|
||||
},
|
||||
},
|
||||
PolicySelector: nil,
|
||||
Reva: &config.Reva{
|
||||
Address: "127.0.0.1:9142",
|
||||
},
|
||||
PreSignedURL: config.PreSignedURL{
|
||||
AllowedHTTPMethods: []string{"GET"},
|
||||
Enabled: true,
|
||||
},
|
||||
AccountBackend: "cs3",
|
||||
UserOIDCClaim: "email",
|
||||
UserCS3Claim: "mail",
|
||||
AutoprovisionAccounts: false,
|
||||
EnableBasicAuth: false,
|
||||
InsecureBackends: false,
|
||||
}
|
||||
}
|
||||
|
||||
func DefaultPolicies() []config.Policy {
|
||||
return []config.Policy{
|
||||
{
|
||||
Name: "ocis",
|
||||
Routes: []config.Route{
|
||||
{
|
||||
Endpoint: "/",
|
||||
Backend: "http://localhost:9100",
|
||||
},
|
||||
{
|
||||
Endpoint: "/.well-known/",
|
||||
Backend: "http://localhost:9130",
|
||||
},
|
||||
{
|
||||
Endpoint: "/konnect/",
|
||||
Backend: "http://localhost:9130",
|
||||
},
|
||||
{
|
||||
Endpoint: "/signin/",
|
||||
Backend: "http://localhost:9130",
|
||||
},
|
||||
{
|
||||
Endpoint: "/archiver",
|
||||
Backend: "http://localhost:9140",
|
||||
},
|
||||
{
|
||||
Type: config.RegexRoute,
|
||||
Endpoint: "/ocs/v[12].php/cloud/user/signing-key", // only `user/signing-key` is left in ocis-ocs
|
||||
Backend: "http://localhost:9110",
|
||||
},
|
||||
{
|
||||
Endpoint: "/ocs/",
|
||||
Backend: "http://localhost:9140",
|
||||
},
|
||||
{
|
||||
Type: config.QueryRoute,
|
||||
Endpoint: "/remote.php/?preview=1",
|
||||
Backend: "http://localhost:9115",
|
||||
},
|
||||
{
|
||||
// TODO the actual REPORT goes to /dav/files/{username}, which is user specific ... how would this work in a spaces world?
|
||||
// TODO what paths are returned? the href contains the full path so it should be possible to return urls from other spaces?
|
||||
// TODO or we allow a REPORT on /dav/spaces to search all spaces and /dav/space/{spaceid} to search a specific space
|
||||
// send webdav REPORT requests to search service
|
||||
Method: "REPORT",
|
||||
Endpoint: "/remote.php/dav/",
|
||||
Backend: "http://localhost:9115", // TODO use registry?
|
||||
},
|
||||
{
|
||||
Type: config.QueryRoute,
|
||||
Endpoint: "/dav/?preview=1",
|
||||
Backend: "http://localhost:9115",
|
||||
},
|
||||
{
|
||||
Type: config.QueryRoute,
|
||||
Endpoint: "/webdav/?preview=1",
|
||||
Backend: "http://localhost:9115",
|
||||
},
|
||||
{
|
||||
Endpoint: "/remote.php/",
|
||||
Service: "com.owncloud.web.ocdav",
|
||||
},
|
||||
{
|
||||
Endpoint: "/dav/",
|
||||
Service: "com.owncloud.web.ocdav",
|
||||
},
|
||||
{
|
||||
Endpoint: "/webdav/",
|
||||
Service: "com.owncloud.web.ocdav",
|
||||
},
|
||||
{
|
||||
Endpoint: "/status",
|
||||
Service: "com.owncloud.web.ocdav",
|
||||
},
|
||||
{
|
||||
Endpoint: "/status.php",
|
||||
Service: "com.owncloud.web.ocdav",
|
||||
},
|
||||
{
|
||||
Endpoint: "/index.php/",
|
||||
Service: "com.owncloud.web.ocdav",
|
||||
},
|
||||
{
|
||||
Endpoint: "/apps/",
|
||||
Service: "com.owncloud.web.ocdav",
|
||||
},
|
||||
{
|
||||
Endpoint: "/data",
|
||||
Backend: "http://localhost:9140",
|
||||
},
|
||||
{
|
||||
Endpoint: "/app/", // /app or /apps? ocdav only handles /apps
|
||||
Backend: "http://localhost:9140",
|
||||
},
|
||||
{
|
||||
Endpoint: "/graph/",
|
||||
Backend: "http://localhost:9120",
|
||||
},
|
||||
{
|
||||
Endpoint: "/graph-explorer",
|
||||
Backend: "http://localhost:9135",
|
||||
},
|
||||
{
|
||||
Endpoint: "/api/v0/settings",
|
||||
Backend: "http://localhost:9190",
|
||||
},
|
||||
{
|
||||
Endpoint: "/settings.js",
|
||||
Backend: "http://localhost:9190",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func EnsureDefaults(cfg *config.Config) {
|
||||
// provide with defaults for shared logging, since we need a valid destination address for BindEnv.
|
||||
if cfg.Log == nil && cfg.Commons != nil && cfg.Commons.Log != nil {
|
||||
cfg.Log = &config.Log{
|
||||
Level: cfg.Commons.Log.Level,
|
||||
Pretty: cfg.Commons.Log.Pretty,
|
||||
Color: cfg.Commons.Log.Color,
|
||||
File: cfg.Commons.Log.File,
|
||||
}
|
||||
} else if cfg.Log == nil {
|
||||
cfg.Log = &config.Log{}
|
||||
}
|
||||
// provide with defaults for shared tracing, since we need a valid destination address for BindEnv.
|
||||
if cfg.Tracing == nil && cfg.Commons != nil && cfg.Commons.Tracing != nil {
|
||||
cfg.Tracing = &config.Tracing{
|
||||
Enabled: cfg.Commons.Tracing.Enabled,
|
||||
Type: cfg.Commons.Tracing.Type,
|
||||
Endpoint: cfg.Commons.Tracing.Endpoint,
|
||||
Collector: cfg.Commons.Tracing.Collector,
|
||||
}
|
||||
} else if cfg.Tracing == nil {
|
||||
cfg.Tracing = &config.Tracing{}
|
||||
}
|
||||
|
||||
if cfg.TokenManager == nil && cfg.Commons != nil && cfg.Commons.TokenManager != nil {
|
||||
cfg.TokenManager = &config.TokenManager{
|
||||
JWTSecret: cfg.Commons.TokenManager.JWTSecret,
|
||||
}
|
||||
} else if cfg.TokenManager == nil {
|
||||
cfg.TokenManager = &config.TokenManager{}
|
||||
}
|
||||
|
||||
if cfg.MachineAuthAPIKey == "" && cfg.Commons != nil && cfg.Commons.MachineAuthAPIKey != "" {
|
||||
cfg.MachineAuthAPIKey = cfg.Commons.MachineAuthAPIKey
|
||||
}
|
||||
|
||||
if cfg.Reva == nil && cfg.Commons != nil && cfg.Commons.Reva != nil {
|
||||
cfg.Reva = &config.Reva{
|
||||
Address: cfg.Commons.Reva.Address,
|
||||
}
|
||||
} else if cfg.Reva == nil {
|
||||
cfg.Reva = &config.Reva{}
|
||||
}
|
||||
}
|
||||
|
||||
func Sanitize(cfg *config.Config) {
|
||||
// sanitize config
|
||||
if cfg.Policies == nil {
|
||||
cfg.Policies = DefaultPolicies()
|
||||
}
|
||||
|
||||
if cfg.PolicySelector == nil {
|
||||
cfg.PolicySelector = &config.PolicySelector{
|
||||
Static: &config.StaticSelectorConf{
|
||||
Policy: "ocis",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if cfg.HTTP.Root != "/" {
|
||||
cfg.HTTP.Root = strings.TrimSuffix(cfg.HTTP.Root, "/")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package config
|
||||
|
||||
// HTTP defines the available http configuration.
|
||||
type HTTP struct {
|
||||
Addr string `yaml:"addr" env:"PROXY_HTTP_ADDR" desc:"The bind address of the HTTP service."`
|
||||
Root string `yaml:"root" env:"PROXY_HTTP_ROOT" desc:"The root path of the HTTP service."`
|
||||
Namespace string `yaml:"-"`
|
||||
TLSCert string `yaml:"tls_cert" env:"PROXY_TRANSPORT_TLS_CERT"`
|
||||
TLSKey string `yaml:"tls_key" env:"PROXY_TRANSPORT_TLS_KEY"`
|
||||
TLS bool `yaml:"tls" env:"PROXY_TLS"`
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package config
|
||||
|
||||
// Log defines the available log configuration.
|
||||
type Log struct {
|
||||
Level string `mapstructure:"level" env:"OCIS_LOG_LEVEL;PROXY_LOG_LEVEL" desc:"The log level. Valid values are: \"panic\", \"fatal\", \"error\", \"warn\", \"info\", \"debug\", \"trace\"."`
|
||||
Pretty bool `mapstructure:"pretty" env:"OCIS_LOG_PRETTY;PROXY_LOG_PRETTY" desc:"Activates pretty log output."`
|
||||
Color bool `mapstructure:"color" env:"OCIS_LOG_COLOR;PROXY_LOG_COLOR" desc:"Activates colorized log output."`
|
||||
File string `mapstructure:"file" env:"OCIS_LOG_FILE;PROXY_LOG_FILE" desc:"The path to the log file. Activates logging to this file if set."`
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package parser
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
ociscfg "github.com/owncloud/ocis/v2/ocis-pkg/config"
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/shared"
|
||||
"github.com/owncloud/ocis/v2/services/proxy/pkg/config"
|
||||
"github.com/owncloud/ocis/v2/services/proxy/pkg/config/defaults"
|
||||
|
||||
"github.com/owncloud/ocis/v2/ocis-pkg/config/envdecode"
|
||||
)
|
||||
|
||||
// ParseConfig loads configuration from known paths.
|
||||
func ParseConfig(cfg *config.Config) error {
|
||||
_, err := ociscfg.BindSourcesToStructs(cfg.Service.Name, cfg)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defaults.EnsureDefaults(cfg)
|
||||
// load all env variables relevant to the config in the current context.
|
||||
if err := envdecode.Decode(cfg); err != nil {
|
||||
// no environment variable set for this config is an expected "error"
|
||||
if !errors.Is(err, envdecode.ErrNoTargetFieldsAreSet) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
defaults.Sanitize(cfg)
|
||||
|
||||
return Validate(cfg)
|
||||
}
|
||||
|
||||
func Validate(cfg *config.Config) error {
|
||||
if cfg.TokenManager.JWTSecret == "" {
|
||||
return shared.MissingJWTTokenError(cfg.Service.Name)
|
||||
}
|
||||
|
||||
if cfg.MachineAuthAPIKey == "" {
|
||||
return shared.MissingMachineAuthApiKeyError(cfg.Service.Name)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package config
|
||||
|
||||
// Reva defines all available REVA configuration.
|
||||
type Reva struct {
|
||||
Address string `yaml:"address" env:"REVA_GATEWAY" desc:"The CS3 gateway endpoint."`
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package config
|
||||
|
||||
// Service defines the available service configuration.
|
||||
type Service struct {
|
||||
Name string `yaml:"-"`
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package config
|
||||
|
||||
// Tracing defines the available tracing configuration.
|
||||
type Tracing struct {
|
||||
Enabled bool `yaml:"enabled" env:"OCIS_TRACING_ENABLED;PROXY_TRACING_ENABLED" desc:"Activates tracing."`
|
||||
Type string `yaml:"type" env:"OCIS_TRACING_TYPE;PROXY_TRACING_TYPE" desc:"The type of tracing. Defaults to \"\", which is the same as \"jaeger\". Allowed tracing types are \"jaeger\" and \"\" as of now."`
|
||||
Endpoint string `yaml:"endpoint" env:"OCIS_TRACING_ENDPOINT;PROXY_TRACING_ENDPOINT" desc:"The endpoint of the tracing agent."`
|
||||
Collector string `yaml:"collector" env:"OCIS_TRACING_COLLECTOR;PROXY_TRACING_COLLECTOR" desc:"The HTTP endpoint for sending spans directly to a collector, i.e. http://jaeger-collector:14268/api/traces. Only used if the tracing endpoint is unset."`
|
||||
}
|
||||
Reference in New Issue
Block a user